Repository navigation
LZSS
Anonym271 edited this page Apr 25, 2021
·
3 revisions
The game uses an LZSS compression to store its files in the archives. LZSS compressed files have the following header:
| Offset | Type | Name | Description |
|---|---|---|---|
| 0x00 | uint32 | magic | Magic number (always "LZSS") |
| 0x04 | uint32 | type | Compression type (between 0 and 3) |
| 0x08 | uint64 | orig_length | Uncompressed size of the original file |
The game usually uses compression type 3 and I don't know how the others work, so the following is only valid for type 3.
The file contains control bytes that define wheter the next blocks are compressed and in which way. Every control block contains information about the next 4 blocks, giving each of them 2 bits of information.
-
0means one uncompressed byte -
1to3means compressed: the next two bytes will contain length and offset of the data in the decompressed file starting at the current writing position
This algorithm shows how to decompress these files:
flag_pos = 0
while not eof():
if flag_pos == 0:
flag_pos = 4
flags = read_byte()
flag = flags & 3
switch flag:
case 0:
write(read_byte())
break
case 1:
control = read_byte()
length = (control & 3) + 2
offset = (control >> 2) & 0x3F
copy_from_decompressed_stream(offset, length)
break
case 2:
control = read_byte() << 8
control |= read_byte()
length = (control & 0x3F) + 3
offset = (control >> 6) & 0x3FF
copy_from_decompressed_stream(offset, length)
break
case 3:
control = read_byte() << 8
control |= read_byte()
control <<= 8
control |= read_byte
length = (control & 0x1FF) + 3
offset = (control >> 9) & 0x7FFF
copy_from_decompressed_stream(offset, length)
break
flags >>= 2
flag_pos--