ChocolateBird/scripts/loaders/snes/compression.gd

34 lines
1.3 KiB
GDScript

static func decompress_lzss(rom: StreamPeer, uncompressed_length:=0) -> PoolByteArray:
# Algorithm from http://slickproductions.org/slickwiki/index.php/Noisecross:Final_Fantasy_V_Compression
# Reuploaded at https://www.ff6hacking.com/ff5wiki/index.php/Compression#Decompression_Type_02_.28LZSS.29
if not uncompressed_length:
uncompressed_length = rom.get_u16()
var output := PoolByteArray()
var buffer := PoolByteArray()
buffer.resize(0x800)
buffer.fill(0)
var buffer_p := 0x07DE
while len(output) < uncompressed_length:
var bitmap_byte := rom.get_u8()
for i in range(8):
var bit := (bitmap_byte >> i) & 1
if bit:
var b := rom.get_u8()
output.append(b)
buffer[buffer_p] = b
buffer_p = (buffer_p+1) % 0x800
else:
# Reuse bytes from previously decompressed buffer
var b1 := rom.get_u8() # lower 8 bits of offset
var b2 := rom.get_u8() # upper 3 bits of offset, 5bit length-3
var offset := b1 | ((b2 & 0xE0) << 3) # 11bit is [0, 0x7FF]
var length := (b2 & 0x1F) + 3 # The +3 is likely because the compression overhead makes this a sensible minimum
for j in range(length):
var b := buffer[offset]
output.append(b)
buffer[buffer_p] = b
buffer_p = (buffer_p+1) % 0x800
offset = (offset+1) % 0x800
output.resize(uncompressed_length)
return output