; ============================================================================== ; Function: DecompressData ; Purpose: Decompresses data using an LZ77-style algorithm. ; Input: ; hl: Pointer to the compressed data source. ; de: Pointer to the destination buffer for uncompressed data. ; Output: ; The destination buffer at 'de' is filled with decompressed data. ; ============================================================================== DecompressData: ; --- INITIALIZATION --- ; Save the initial destination address to check for completion later. ld a, e ld [initialDestAddress], a ; Save low byte of DE ld a, d ld [initialDestAddress+1], a ; Save high byte of DE ; Read the 16-bit uncompressed size from the source. ld c, [hl] inc hl ld b, [hl] inc hl ; Set DE to the end of the destination buffer. Decompression works backwards. push hl ; Save source pointer ld h, d ld l, e add hl, bc ; DE = DE (start) + BC (size) ld d, h ld e, l ; DE is now at the end of the buffer pop hl ; Restore source pointer ; Read a 16-bit offset from the source and advance the source pointer (hl). ld c, [hl] inc hl ld b, [hl] add hl, bc ; Prime the bitstream reader by loading the first data byte. ld a, [hl-] ; Load first byte ld [bitstreamCurrentByte], a ; Store it in our variable push hl ; Save source pointer ld hl, bitstreamCurrentByte ; Point HL to the current byte for bit reading scf ; Set Carry flag to 1 rl [hl] ; Rotate it into bit 0 to prevent premature byte-end detection jr c, HandleCopyRun ; Jump into the main loop, starting with a Copy operation. ; --- MAIN DECOMPRESSION LOOP --- ; The loop alternates between HandleLiteralRun and HandleCopyRun based on a control bit. HandleLiteralRun: call DecodeVariableLengthNumber ; Get the number of literal bytes to copy (length in BC). LiteralCopyLoop: ; Read 8 bits from the stream to form one literal byte. xor a call GetNextBit adc a call GetNextBit adc a call GetNextBit adc a call GetNextBit adc a call GetNextBit adc a call GetNextBit adc a call GetNextBit adc a call GetNextBit adc a ; Write the assembled byte to the destination buffer (working backwards). dec de ld [de], a ; Loop until all literal bytes are copied. dec bc ld a, b or c jr nz, LiteralCopyLoop ; Check if decompression is finished. ld a, [initialDestAddress+1] cp d jr nz, HandleCopyRun ; If not finished, the next block is always a copy block. ld a, [initialDestAddress] cp e jr c, HandleCopyRun ; If DE > initial address, continue. jr DecompressionFinished ; Decompression is complete. CheckBlockType: call GetNextBit ; Read one control bit from the stream. jr nc, HandleLiteralRun ; If bit is 0 (No Carry), it's a literal run. HandleCopyRun: ; If the bit is 1 (Carry), it's a copy run. call DecodeVariableLengthNumber ; Get the copy length into BC. ; This part seems to be manipulating the bitstream buffer state, possibly ; for a specific variant of the compression format. inc l ld [hl], c inc l ld [hl], b dec l dec l call DecodeVariableLengthNumber ; Get the copy offset into BC. push hl ; Save bitstream pointer inc bc ; Adjust offset (specific to this format) inc bc inc bc push bc ; Calculate the source address for the copy: (current_dest - 1) + offset. ld h, d ld l, e dec hl add hl, bc pop bc LzCopyLoop: ld a, [hl-] ; Read a byte from the calculated source (already decompressed data) dec de ; Decrement destination pointer ld [de], a ; Write the byte dec bc ; Decrement copy counter ld a, b or c jr nz, LzCopyLoop ; Loop until all bytes are copied. pop hl ; Restore bitstream pointer ; Check if decompression is finished. ld a, [initialDestAddress+1] cp d jr nz, CheckBlockType ; If not done, read the next control bit. ld a, [initialDestAddress] cp e jr c, CheckBlockType ; If DE > initial address, continue. DecompressionFinished: pop hl ; Clean up the stack ret ; Return from the function. ; ============================================================================== ; Function: DecodeVariableLengthNumber ; Purpose: Reads a variable-length encoded number from the bitstream. ; Input: ; hl: Pointer to the bitstream byte. ; Output: ; bc: Decoded 16-bit number. ; Reads bits using GetNextBit_B. ; ============================================================================== DecodeVariableLengthNumber: xor a ld b, a ld c, a call GetNextBit_B ; Read first bit adc a call GetNextBit_B ; Read second bit adc a jr z, DecodePath_00 ; If prefix is "00" dec a jr z, DecodePath_01 ; If prefix is "01" dec a jr z, DecodePath_10 ; If prefix is "10" ; Prefix is "11" ld a, $04 Read4Bits_Path11: call GetNextBit_B rl c rl b dec a jr nz, Read4Bits_Path11 ret DecodePath_10: ld a, $04 Read4Bits_Path10: call GetNextBit_B rl c rl b dec a jr nz, Read4Bits_Path10 ret DecodePath_01: ld a, $04 Read4Bits_Path01: call GetNextBit_B rl c rl b dec a jr nz, Read4Bits_Path01 ret DecodePath_00: ld a, $04 Read4Bits_Path00: call GetNextBit_B rl c rl b dec a jr nz, Read4Bits_Path00 ret ; ============================================================================== ; Function: GetNextBit / GetNextBit_B ; Purpose: Reads one bit from the bitstream byte at [hl]. ; Input: ; hl: Pointer to the bitstream byte (bitstreamCurrentByte). ; Output: ; Carry Flag: Set to 1 or 0, representing the bit read. ; Details: ; Shifts the byte at [hl] left. The most significant bit is moved into ; the Carry flag. If the byte becomes zero after the shift, it indicates ; all 8 bits have been read, and it contains logic to fetch the next ; byte of the compressed data. ; ============================================================================== GetNextBit: sla [hl] ; Shift byte left, MSB goes into Carry ret nz ; If result is not zero, we're done. ; If the byte is now zero, we need to load the next one from the source stream. di ; Disable interrupts for safe stack manipulation push af push hl add sp, $06 ; Manipulate stack to get source pointer pop hl ld a, [hl-] ; Read next byte from compressed source ld [bitstreamCurrentByte], a ; Update the bitstream byte push hl add sp, -$06 ; Restore stack pop hl pop af rl [hl] ; Rotate to prepare the new byte ei ; Re-enable interrupts ret GetNextBit_B: sla [hl] ret nz di push af push hl add sp, $08 pop hl ld a, [hl-] ld [bitstreamCurrentByte], a push hl add sp, -$08 pop hl pop af rl [hl] ei ret