Skip to content
Anonym271 edited this page Apr 25, 2021 · 3 revisions

LZSS Compression

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

Decompression

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.

  • 0 means one uncompressed byte
  • 1 to 3 means 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--

Clone this wiki locally