; Gunzip by Wouter Vermaelen
; https://github.com/m9710797/msx-gunzip
;
; Original code
; Copyright 2015 Laurens Holst laurens.nospam@grauw.nl
; http://www.grauw.nl/projects/gunzip
;
; You need to add the following to compile:
; Functions
; GzipReadInputBuffer
; GzipWriteOutputBuffer
; GzipExitWithError
; GzipThrowException
; Defines
; GzipBuffersStart
;
;
; Read a single bit from the input.
; This code fragment is generated by 'GenerateHuffman'
; Requires: PrepareRead has been called (registers C and DE are reserved)
; output: carry-flag, reset -> read 0-bit, set-> read 1-bit
; Modifies: a
; Unchanged: b, hl, ix, iy
ReadBitInlineA: MACRO
srl c
call z,ReadBitA ; if sentinel bit is shifted out
ENDM
GzipExtract:
; Read header
; Header constants
FLAG_HCRC: equ #02
FLAG_EXTRA: equ #04
FLAG_NAME: equ #08
FLAG_COMMENT: equ #10
FLAG_RESERVED: equ #20 ; #E0
ld hl,0
ld (OutputCount + 0),hl
ld (OutputCount + 2),hl
ld hl,0xffff
ld (Crc32Value + 0),hl
ld (Crc32Value + 2),hl
xor a
ld (InputBits),a
ld hl,InputBufferEnd - 1
ld (InputBufPos),hl
ld hl,OutputBuffer
ld (OutputBufPos),hl
ld de,(InputBufPos)
; Check two signature bytes
call ReadByte
cp 31 ; gzip signature (1)
ld hl,TextNotGzip
jp nz,GzipExitWithError
call ReadByte
cp 139 ; gzip signature (1)
;ld hl,TextNotGzip ; hl not changed
jp nz,GzipExitWithError
; Check compression algorithm
call ReadByte
cp 8 ; deflate compression ID (1)
ld hl,TextNotDeflate
jp nz,GzipExitWithError
; Read flags
call ReadByte
ld (HeaderFlags),a
; Skip mtime[4], xfl, os
ld hl,6
call SkipInputBytes
; Check for unknown flags
ld a,(HeaderFlags)
and FLAG_RESERVED
ld hl,TextUnknownFlag
jp nz,GzipExitWithError
; Check and skip extra section
ld a,(HeaderFlags)
and FLAG_EXTRA
jr z,NoSkipExtra
call ReadByte
ld l,a
call ReadByte
ld h,a
call SkipInputBytes
NoSkipExtra:
; Skip name
ld a,(HeaderFlags)
and FLAG_NAME
call nz,SkipZString
; Skip comment
ld a,(HeaderFlags)
and FLAG_COMMENT
call nz,SkipZString
; Skip header CRC
ld a,(HeaderFlags)
and FLAG_HCRC
ld hl,2
call nz,SkipInputBytes
ld (InputBufPos),de
; Decompress all blocks in the gz file
InflateLoop: call PrepareRead
ReadBitInlineA
push af
call Read2Bits
push af
call FinishRead
pop af
call InflateBlock
pop af
jr nc,InflateLoop
; Finish last (partially filled) OutputBuffer (update count, crc)
call FinishBlock
; Verify the decompressed data
; Read expected values from file
ld de,(InputBufPos)
call ReadByte
ld l,a ; bits 7-0
call ReadByte
ld h,a ; bits 15-8
push hl ; expected crc bits 15-0
call ReadByte
ld l,a ; bits 23-16
call ReadByte
ld h,a ; bits 31-24
push hl ; expected crc bits 31-16
call ReadByte
ld l,a ; bits 7-0
call ReadByte
ld h,a ; bits 15-8
push hl ; expected-size bits 15-0
call ReadByte
ld l,a ; bits 23-16
call ReadByte
ld h,a ; hl = expected-size bits 31-16
;ld (InputBufPos),de ; not needed anymore
; Verify size
ld de,(OutputCount + 2) ; de = actual size bits 31-16
or a ; hl = expected size bits 31-16
sbc hl,de
jr nz,SizeError
ld de,(OutputCount + 0) ; de = actual size bits 15-0
pop hl ; hl = expected size bits 15-0
sbc hl,de
SizeError: ld hl,TextSizeError
jp nz,GzipExitWithError
; Verify CRC
pop hl ; hl = expected crc bits 31-16
pop de ; de = expected crc bits 15-0
ld a,(NoCrcCheck)
or a
ret nz
ld bc,(Crc32Value + 2) ; de = actual crc bits 31-16
scf
adc hl,bc
jr nz,CrcError
ex de,hl
ld bc,(Crc32Value + 0) ; de = actual crc bits 15-0
adc hl,bc
ret z ; ok
CrcError: ld hl,TextCrcError
jp GzipExitWithError
; Skip zero-terminated string
SkipZString: call ReadByte
and a
jr nz,SkipZString
ret
; hl = nr of bytes to skip
SkipInputBytes: call ReadByte
dec hl
ld a,h
or l
jr nz,SkipInputBytes
ret
; === Inflate decompression ===
; -- decompress one block --
; a = block type
InflateBlock: and a
jr z,Uncompressed
cp 2
jr c,FixedComp
jp z,DynamicComp
ld hl,TextBlockErr
jp GzipExitWithError
; An uncompressed block
Uncompressed: ld de,(InputBufPos)
xor a
ld (InputBits),a ; re-align to byte boundary
call ReadByte
ld c,a
call ReadByte
ld b,a ; bc = block-length
call ReadByte
ld l,a
call ReadByte
ld h,a ; hl = complement of block-length
scf
adc hl,bc
ld hl,TextLengthErr
jp nz,GzipExitWithError
ld a,b
or c
jr z,UncompEnd ; length = 0
ld a,c
dec bc
inc b
ld c,b
ld b,a
ld hl,(OutputBufPos)
UncompLoop: ;call ReadByte ; partially inline this call
inc e
call z,ReadByte2
ld a,(de)
;call WriteByte ; partially inline this call
ld (hl),a
inc l
call z,WriteByte2
djnz UncompLoop
dec c
jr nz,UncompLoop
ld (OutputBufPos),hl
UncompEnd: ld (InputBufPos),de
ret
; A block compressed using the fixed alphabet
FixedComp: ld bc,FixedLitCount
ld de,FixedLitLen
ld hl,LLSymbols
ld iy,LiteralTree
ld ix,LiteralTreeEnd
call GenerateHuffman
ld bc,FixedDistCount
ld de,FixedDistLen
ld hl,DistSymbols
ld iy,DistanceTree
ld ix,DistanceTreeEnd
call GenerateHuffman
jr DoInflate
; A block compressed using a dynamic alphabet
DynamicComp: call BuildDynAlpha
DoInflate: ; generate CopySetLength routine in front of DistanceTree
ld hl,CopySL
ld de,CopySetLength
ld bc,CopySLLen
ldir
ld iy,Write_AndNext
call PrepareRead
ld hl,(OutputBufPos)
call LiteralTree ; generated code
ld (OutputBufPos),hl
jp FinishRead
; -- Create dynamic alphabet --
MAX_HEADER_LEN: equ 19 ; maximum number of 'header code lengths'
MAX_LIT_LEN: equ 286 ; maximum number of 'literal/length code lengths'
MAX_DIST_LEN: equ 30 ; maximum number of 'distance code lengths'
BuildDynAlpha:
; Clear header code lengths
ld hl,HdrCodeLengths
ld de,HdrCodeLengths + 1
ld bc,MAX_HEADER_LEN - 1
ld (hl),b ; 0
ldir
; Read hlit
call PrepareRead
call Read5Bits
inc a
cp ((MAX_LIT_LEN) & #FF) + 1
call nc,GzipThrowException
ld (hlit + 0),a
; Read hdist
call Read5Bits
inc a
cp MAX_DIST_LEN + 1
call nc,GzipThrowException
ld (hdist + 0),a
; Read hclen
call Read4Bits
add a,4
cp MAX_HEADER_LEN + 1
call nc,GzipThrowException
; Read header code lengths
ld ixl,a ; hclen
ld hl,HeaderCodeOrder
ld iy,HdrCodeLengths
DynLoop: ld a,(hl)
inc hl
ld (DynStore + 2),a ; self modifying code!
call Read3Bits ; changes B
DynStore: ld (iy + 0),a ; offset is dynamically changed!
dec ixl
jr nz,DynLoop
push bc
push de
; Construct header code alphabet
ld bc,MAX_HEADER_LEN
ld de,HdrCodeLengths ; de = length of symbols
ld hl,HeaderSymbols
ld iy,HeaderTree
ld ix,HeaderTreeEnd
call GenerateHuffman
; Read literal length distance code lengths
ld bc,(hdist)
ld ix,(hlit)
add ix,bc
inc ixh ; +1 for nested 8-bit loop
ld hl,LLDCodeLengths
pop de
pop bc
call HeaderTree ; decode the header (generated code)
call FinishRead
; Construct literal length alphabet
ld bc,(hlit) ; bc = number of symbols
ld de,LLDCodeLengths ; de = length of symbols
ld hl,LLSymbols ; iy = literal/length symbol handlers table
ld iy,LiteralTree
ld ix,LiteralTreeEnd
call GenerateHuffman
; Construct distance alphabet
ld bc,(hdist) ; bc = number of symbols
ld hl,LLDCodeLengths
ld de,(hlit)
add hl,de
ex de,hl ; de = length of symbols
ld hl,DistSymbols ; iy = distance symbol handlers table
ld iy,DistanceTree
ld ix,DistanceTreeEnd
jp GenerateHuffman
; -- Generate Huffman decoding function --
; In:
; [bc] = number of symbols
; [de] = table containing length of each symbol
; [hl] = table containing pointer to leaf-routine for each symbol
; [iy] = output-buffer
; [ix] = output-buffer-end (only for buffer overflow check)
; Out:
; output-buffer filled with decoding function
; Modifies:
; - all registers
; - buffers CountBuffer and SortedBuffer are changed, but can be
; freely used outside this routine. IOW it's all scratch area.
; Requires:
; CountBuffer must be 256-byte aligned
MAX_CODELENGTH: equ 16
GenerateHuffman:
push ix
push iy
push hl
push de
push bc
; Generate list of (code-length, symbol-handler) pairs, sorted on code-length
; clear CountBuffer
ld hl,CountBuffer
ld de,CountBuffer + 1
ld bc,(2 * MAX_CODELENGTH) - 1
ld (hl),b ; b = 0
ldir
; count code lengths
pop de ; de = number of symbols
ld b,e
dec de
inc d
ld c,d ; bc = numSymbols converted into 2 8-bit counters
pop de ; de = codeLengths
push de
push bc
ld h,CountBuffer / 256
CountLoop: ld a,(de)
inc de
add a,a
jr z,CountNext
ld l,a
inc (hl)
jr nc,CountNext
inc l
inc (hl)
CountNext: djnz CountLoop
dec c
jr nz,CountLoop
; calculate running sum * 4, transform CountBuffer into OffsetBuffer
ld de,SortedBuffer
ld l,c ; c = 0 hl = CountBuffer
ld a,MAX_CODELENGTH
AccumLoop: ld c,(hl)
ld (hl),e
inc l
ld b,(hl)
ld (hl),d
inc l
ex de,hl
add hl,bc
add hl,bc
add hl,bc
add hl,bc
ex de,hl
dec a
jr nz,AccumLoop
ex de,hl
ld (hl),a ; a = 0 sentinel
; sort
pop bc ; bc = numSymbols converted into 2 8-bit counters
pop hl ; hl = codeLengths
exx
pop bc ; bc = symbolHandlers
ld h,CountBuffer / 256
exx
SortLoop: ld a,(hl) ; a = length
inc hl
add a,a
exx
jr z,SortSkip
ld l,a
ld e,(hl)
inc l
ld d,(hl) ; de = ptr in SortedBuffer
rrca
ld (de),a ; store length
inc de
ld a,(bc) ; copy handler length
inc bc
ld (de),a
inc de
ld a,(bc) ; copy ptr to handler
inc bc
ld (de),a
inc de
ld a,(bc)
inc bc
ld (de),a
inc de
ld (hl),d ; update ptr to SortedBuffer
dec l
ld (hl),e
SortNext exx
djnz SortLoop
dec c
jr nz,SortLoop
; build tree
ld hl,SortedBuffer ; hl = ptr to sorted (code-length, symbol-handler)-pairs
inc c ; b = 0 = bits left c = 1 = code length
call GetNextSymbol
pop de ; de = treeBuffer
call BuildBranch
pop hl ; hl = treeBufferEnd
and a
sbc hl,de
ret nc
jp GzipThrowException
SortSkip: inc bc
inc bc
inc bc
jr SortNext
; b = bits left
; c = code length
; de = tree position
; hl = sorted (code length, symbol) list pointer
; iy = current branch
BuildBranch: push iy
ld iyl,e
ld iyh,d
; generate code for a branch (test 1 bit from the input)
ex de,hl
ld (hl),#CB ; +0 SRL C
inc hl
ld (hl),#39 ; +1
inc hl
ld (hl),#CC ; +2 CALL Z,nn
inc hl
ld (hl),(ReadBitA) & #FF; +3
inc hl
ld (hl),ReadBitA / 256 ; +4
inc hl
ld (hl),#DA ; +5 JP c,nn
inc hl
inc hl ; +6 skip address, filled-in later
inc hl ; +7
ex de,hl
call BuildBranchZero
call nc,BuildBranchOne
pop iy
inc b
ret
BuildBranchOne: ; fill-in address of 'JP C,nn' instruction
djnz Branch1
Leaf1: inc hl ; symbol length
inc hl ; skip handler length
ld a,(hl)
inc hl
ld (iy + 6),a ; replace 'nn' with address of symbol handler
ld a,(hl)
inc hl
ld (iy + 7),a
jp GetNextSymbol
Branch1: ld (iy + 6),e ; replace 'nn' with address of next branch
ld (iy + 7),d
jp BuildBranch
BuildBranchZero:; generate some code after the 'JP C,nn' instruction
djnz BuildBranch; generate another branch
Leaf0: ; Generate code to handle a symbol. One possibility is to
; generate a JP to the handler routine. Usually these handlers
; are small, so instead we inline (=copy) them.
inc hl ; skip symbol length
ld a,c
push de ; de = destination
ld c,(hl) ; b = 0 bc = length of handler routine
inc hl
ld e,(hl)
inc hl
ld d,(hl)
inc hl
ex (sp),hl ; hl = destination (sp) = SortedBuffer
ex de,hl
ldir ; b = 0
pop hl
ld c,a
;jp GetNextSymbol
; b = bits left
; c = code length
; hl = sorted (code length, symbol) list pointer
; b, c <- updated
; f <- c: end reached
GetNextSymbol: inc b
ld a,(hl)
sub c
ret z
ret c
ld c,(hl)
add a,b
ld b,a
ret
; -- Symbol routines used by the 'header decoder' Huffman tree
; Pairs of
; length of the routine (1 bytes)
; pointer to the routine (2 bytes)
HeaderSymbols: db WriteLen_0_len
dw WriteLen_0
db WriteLen_1_len
dw WriteLen_1
db WriteLen_2_len
dw WriteLen_2
db WriteLen_3_len
dw WriteLen_3
db WriteLen_4_len
dw WriteLen_4
db WriteLen_5_len
dw WriteLen_5
db WriteLen_6_len
dw WriteLen_6
db WriteLen_7_len
dw WriteLen_7
db WriteLen_8_len
dw WriteLen_8
db WriteLen_9_len
dw WriteLen_9
db WriteLen_10_len
dw WriteLen_10
db WriteLen_11_len
dw WriteLen_11
db WriteLen_12_len
dw WriteLen_12
db WriteLen_13_len
dw WriteLen_13
db WriteLen_14_len
dw WriteLen_14
db WriteLen_15_len
dw WriteLen_15
db HeaderCopyLen
dw HeaderCopy
db HdrZFill3Len
dw HdrZFill3
db HdrZFill11Len
dw HdrZFill11
db ThrowInlineLen
dw ThrowInline
; For all of these routines, the calling convention is like this:
; c = bit reader state
; de = InputBufPos
; hl = literal/length/distance code lengths position
; ix = loop counter for nested 8-bit loop
; Header code alphabet symbols 0-15
WriteLen_0: ld (hl),0
jp HeaderNext
WriteLen_0_len: equ $-WriteLen_0
WriteLen_1: ld (hl),1
jp HeaderNext
WriteLen_1_len: equ $-WriteLen_1
WriteLen_2: ld (hl),2
jp HeaderNext
WriteLen_2_len: equ $-WriteLen_2
WriteLen_3: ld (hl),3
jp HeaderNext
WriteLen_3_len: equ $-WriteLen_3
WriteLen_4: ld (hl),4
jp HeaderNext
WriteLen_4_len: equ $-WriteLen_4
WriteLen_5: ld (hl),5
jp HeaderNext
WriteLen_5_len: equ $-WriteLen_5
WriteLen_6: ld (hl),6
jp HeaderNext
WriteLen_6_len: equ $-WriteLen_6
WriteLen_7: ld (hl),7
jp HeaderNext
WriteLen_7_len: equ $-WriteLen_7
WriteLen_8: ld (hl),8
jp HeaderNext
WriteLen_8_len: equ $-WriteLen_8
WriteLen_9: ld (hl),9
jp HeaderNext
WriteLen_9_len: equ $-WriteLen_9
WriteLen_10: ld (hl),10
jp HeaderNext
WriteLen_10_len:equ $-WriteLen_10
WriteLen_11: ld (hl),11
jp HeaderNext
WriteLen_11_len:equ $-WriteLen_11
WriteLen_12: ld (hl),12
jp HeaderNext
WriteLen_12_len:equ $-WriteLen_12
WriteLen_13: ld (hl),13
jp HeaderNext
WriteLen_13_len:equ $-WriteLen_13
WriteLen_14: ld (hl),14
jp HeaderNext
WriteLen_14_len:equ $-WriteLen_14
WriteLen_15: ld (hl),15
jp HeaderNext
WriteLen_15_len:equ $-WriteLen_15
; Header code alphabet symbol 16
HeaderCopy: call Read2Bits
add a,3
ld b,a
dec hl
ld a,(hl)
inc hl
jp HeaderFill
HeaderCopyLen: equ $ - HeaderCopy
; Header code alphabet symbol 17
HdrZFill3: call Read3Bits
add a,3 ; 3..10
ld b,a
xor a
jp HeaderFill
HdrZFill3Len: equ $-HdrZFill3
; Header code alphabet symbol 18
HdrZFill11: call Read7Bits
add a,11 ; 11..138
ld b,a
xor a
jp HeaderFill
HdrZFill11Len: equ $ - HdrZFill11
HeaderNext: inc hl
dec ixl
jp nz,HeaderTree
dec ixh
jp nz,HeaderTree
ret
; a = fill value
; b = repeat count
FillLoop: dec b
jp z,HeaderTree
HeaderFill: ld (hl),a
inc hl
dec ixl
jp nz,FillLoop
dec ixh
jr nz,FillLoop
ret
; Inline-able version of 'GzipThrowException'
ThrowInline: jp GzipThrowException
ThrowInlineLen: equ $ - ThrowInline
; -- Symbol routines used by the 'literal + copy-length' Huffman tree
LLSymbols: db WriteLitLen ; 0
dw WriteLit00
db WriteLitLen
dw WriteLit01
db WriteLitLen
dw WriteLit02
db WriteLitLen
dw WriteLit03
db WriteLitLen
dw WriteLit04
db WriteLitLen
dw WriteLit05
db WriteLitLen
dw WriteLit06
db WriteLitLen
dw WriteLit07
db WriteLitLen
dw WriteLit08
db WriteLitLen
dw WriteLit09
db WriteLitLen
dw WriteLit0A
db WriteLitLen
dw WriteLit0B
db WriteLitLen
dw WriteLit0C
db WriteLitLen
dw WriteLit0D
db WriteLitLen
dw WriteLit0E
db WriteLitLen
dw WriteLit0F
db WriteLitLen
dw WriteLit10
db WriteLitLen
dw WriteLit11
db WriteLitLen
dw WriteLit12
db WriteLitLen
dw WriteLit13
db WriteLitLen
dw WriteLit14
db WriteLitLen
dw WriteLit15
db WriteLitLen
dw WriteLit16
db WriteLitLen
dw WriteLit17
db WriteLitLen
dw WriteLit18
db WriteLitLen
dw WriteLit19
db WriteLitLen
dw WriteLit1A
db WriteLitLen
dw WriteLit1B
db WriteLitLen
dw WriteLit1C
db WriteLitLen
dw WriteLit1D
db WriteLitLen
dw WriteLit1E
db WriteLitLen
dw WriteLit1F
db WriteLitLen
dw WriteLit20
db WriteLitLen
dw WriteLit21
db WriteLitLen
dw WriteLit22
db WriteLitLen
dw WriteLit23
db WriteLitLen
dw WriteLit24
db WriteLitLen
dw WriteLit25
db WriteLitLen
dw WriteLit26
db WriteLitLen
dw WriteLit27
db WriteLitLen
dw WriteLit28
db WriteLitLen
dw WriteLit29
db WriteLitLen
dw WriteLit2A
db WriteLitLen
dw WriteLit2B
db WriteLitLen
dw WriteLit2C
db WriteLitLen
dw WriteLit2D
db WriteLitLen
dw WriteLit2E
db WriteLitLen
dw WriteLit2F
db WriteLitLen
dw WriteLit30
db WriteLitLen
dw WriteLit31
db WriteLitLen
dw WriteLit32
db WriteLitLen
dw WriteLit33
db WriteLitLen
dw WriteLit34
db WriteLitLen
dw WriteLit35
db WriteLitLen
dw WriteLit36
db WriteLitLen
dw WriteLit37
db WriteLitLen
dw WriteLit38
db WriteLitLen
dw WriteLit39
db WriteLitLen
dw WriteLit3A
db WriteLitLen
dw WriteLit3B
db WriteLitLen
dw WriteLit3C
db WriteLitLen
dw WriteLit3D
db WriteLitLen
dw WriteLit3E
db WriteLitLen
dw WriteLit3F
db WriteLitLen
dw WriteLit40
db WriteLitLen
dw WriteLit41
db WriteLitLen
dw WriteLit42
db WriteLitLen
dw WriteLit43
db WriteLitLen
dw WriteLit44
db WriteLitLen
dw WriteLit45
db WriteLitLen
dw WriteLit46
db WriteLitLen
dw WriteLit47
db WriteLitLen
dw WriteLit48
db WriteLitLen
dw WriteLit49
db WriteLitLen
dw WriteLit4A
db WriteLitLen
dw WriteLit4B
db WriteLitLen
dw WriteLit4C
db WriteLitLen
dw WriteLit4D
db WriteLitLen
dw WriteLit4E
db WriteLitLen
dw WriteLit4F
db WriteLitLen
dw WriteLit50
db WriteLitLen
dw WriteLit51
db WriteLitLen
dw WriteLit52
db WriteLitLen
dw WriteLit53
db WriteLitLen
dw WriteLit54
db WriteLitLen
dw WriteLit55
db WriteLitLen
dw WriteLit56
db WriteLitLen
dw WriteLit57
db WriteLitLen
dw WriteLit58
db WriteLitLen
dw WriteLit59
db WriteLitLen
dw WriteLit5A
db WriteLitLen
dw WriteLit5B
db WriteLitLen
dw WriteLit5C
db WriteLitLen
dw WriteLit5D
db WriteLitLen
dw WriteLit5E
db WriteLitLen
dw WriteLit5F
db WriteLitLen
dw WriteLit60
db WriteLitLen
dw WriteLit61
db WriteLitLen
dw WriteLit62
db WriteLitLen
dw WriteLit63
db WriteLitLen
dw WriteLit64
db WriteLitLen
dw WriteLit65
db WriteLitLen
dw WriteLit66
db WriteLitLen
dw WriteLit67
db WriteLitLen
dw WriteLit68
db WriteLitLen
dw WriteLit69
db WriteLitLen
dw WriteLit6A
db WriteLitLen
dw WriteLit6B
db WriteLitLen
dw WriteLit6C
db WriteLitLen
dw WriteLit6D
db WriteLitLen
dw WriteLit6E
db WriteLitLen
dw WriteLit6F
db WriteLitLen
dw WriteLit70
db WriteLitLen
dw WriteLit71
db WriteLitLen
dw WriteLit72
db WriteLitLen
dw WriteLit73
db WriteLitLen
dw WriteLit74
db WriteLitLen
dw WriteLit75
db WriteLitLen
dw WriteLit76
db WriteLitLen
dw WriteLit77
db WriteLitLen
dw WriteLit78
db WriteLitLen
dw WriteLit79
db WriteLitLen
dw WriteLit7A
db WriteLitLen
dw WriteLit7B
db WriteLitLen
dw WriteLit7C
db WriteLitLen
dw WriteLit7D
db WriteLitLen
dw WriteLit7E
db WriteLitLen
dw WriteLit7F
db WriteLitLen
dw WriteLit80
db WriteLitLen
dw WriteLit81
db WriteLitLen
dw WriteLit82
db WriteLitLen
dw WriteLit83
db WriteLitLen
dw WriteLit84
db WriteLitLen
dw WriteLit85
db WriteLitLen
dw WriteLit86
db WriteLitLen
dw WriteLit87
db WriteLitLen
dw WriteLit88
db WriteLitLen
dw WriteLit89
db WriteLitLen
dw WriteLit8A
db WriteLitLen
dw WriteLit8B
db WriteLitLen
dw WriteLit8C
db WriteLitLen
dw WriteLit8D
db WriteLitLen
dw WriteLit8E
db WriteLitLen
dw WriteLit8F
db WriteLitLen
dw WriteLit90
db WriteLitLen
dw WriteLit91
db WriteLitLen
dw WriteLit92
db WriteLitLen
dw WriteLit93
db WriteLitLen
dw WriteLit94
db WriteLitLen
dw WriteLit95
db WriteLitLen
dw WriteLit96
db WriteLitLen
dw WriteLit97
db WriteLitLen
dw WriteLit98
db WriteLitLen
dw WriteLit99
db WriteLitLen
dw WriteLit9A
db WriteLitLen
dw WriteLit9B
db WriteLitLen
dw WriteLit9C
db WriteLitLen
dw WriteLit9D
db WriteLitLen
dw WriteLit9E
db WriteLitLen
dw WriteLit9F
db WriteLitLen
dw WriteLitA0
db WriteLitLen
dw WriteLitA1
db WriteLitLen
dw WriteLitA2
db WriteLitLen
dw WriteLitA3
db WriteLitLen
dw WriteLitA4
db WriteLitLen
dw WriteLitA5
db WriteLitLen
dw WriteLitA6
db WriteLitLen
dw WriteLitA7
db WriteLitLen
dw WriteLitA8
db WriteLitLen
dw WriteLitA9
db WriteLitLen
dw WriteLitAA
db WriteLitLen
dw WriteLitAB
db WriteLitLen
dw WriteLitAC
db WriteLitLen
dw WriteLitAD
db WriteLitLen
dw WriteLitAE
db WriteLitLen
dw WriteLitAF
db WriteLitLen
dw WriteLitB0
db WriteLitLen
dw WriteLitB1
db WriteLitLen
dw WriteLitB2
db WriteLitLen
dw WriteLitB3
db WriteLitLen
dw WriteLitB4
db WriteLitLen
dw WriteLitB5
db WriteLitLen
dw WriteLitB6
db WriteLitLen
dw WriteLitB7
db WriteLitLen
dw WriteLitB8
db WriteLitLen
dw WriteLitB9
db WriteLitLen
dw WriteLitBA
db WriteLitLen
dw WriteLitBB
db WriteLitLen
dw WriteLitBC
db WriteLitLen
dw WriteLitBD
db WriteLitLen
dw WriteLitBE
db WriteLitLen
dw WriteLitBF
db WriteLitLen
dw WriteLitC0
db WriteLitLen
dw WriteLitC1
db WriteLitLen
dw WriteLitC2
db WriteLitLen
dw WriteLitC3
db WriteLitLen
dw WriteLitC4
db WriteLitLen
dw WriteLitC5
db WriteLitLen
dw WriteLitC6
db WriteLitLen
dw WriteLitC7
db WriteLitLen
dw WriteLitC8
db WriteLitLen
dw WriteLitC9
db WriteLitLen
dw WriteLitCA
db WriteLitLen
dw WriteLitCB
db WriteLitLen
dw WriteLitCC
db WriteLitLen
dw WriteLitCD
db WriteLitLen
dw WriteLitCE
db WriteLitLen
dw WriteLitCF
db WriteLitLen
dw WriteLitD0
db WriteLitLen
dw WriteLitD1
db WriteLitLen
dw WriteLitD2
db WriteLitLen
dw WriteLitD3
db WriteLitLen
dw WriteLitD4
db WriteLitLen
dw WriteLitD5
db WriteLitLen
dw WriteLitD6
db WriteLitLen
dw WriteLitD7
db WriteLitLen
dw WriteLitD8
db WriteLitLen
dw WriteLitD9
db WriteLitLen
dw WriteLitDA
db WriteLitLen
dw WriteLitDB
db WriteLitLen
dw WriteLitDC
db WriteLitLen
dw WriteLitDD
db WriteLitLen
dw WriteLitDE
db WriteLitLen
dw WriteLitDF
db WriteLitLen
dw WriteLitE0
db WriteLitLen
dw WriteLitE1
db WriteLitLen
dw WriteLitE2
db WriteLitLen
dw WriteLitE3
db WriteLitLen
dw WriteLitE4
db WriteLitLen
dw WriteLitE5
db WriteLitLen
dw WriteLitE6
db WriteLitLen
dw WriteLitE7
db WriteLitLen
dw WriteLitE8
db WriteLitLen
dw WriteLitE9
db WriteLitLen
dw WriteLitEA
db WriteLitLen
dw WriteLitEB
db WriteLitLen
dw WriteLitEC
db WriteLitLen
dw WriteLitED
db WriteLitLen
dw WriteLitEE
db WriteLitLen
dw WriteLitEF
db WriteLitLen
dw WriteLitF0
db WriteLitLen
dw WriteLitF1
db WriteLitLen
dw WriteLitF2
db WriteLitLen
dw WriteLitF3
db WriteLitLen
dw WriteLitF4
db WriteLitLen
dw WriteLitF5
db WriteLitLen
dw WriteLitF6
db WriteLitLen
dw WriteLitF7
db WriteLitLen
dw WriteLitF8
db WriteLitLen
dw WriteLitF9
db WriteLitLen
dw WriteLitFA
db WriteLitLen
dw WriteLitFB
db WriteLitLen
dw WriteLitFC
db WriteLitLen
dw WriteLitFD
db WriteLitLen
dw WriteLitFE
db WriteLitLen
dw WriteLitFF
db EndBlockLen ; 256
dw EndBlock
db CopyLen0Len ; 257
dw CopyLen0
db CopyLen1Len
dw CopyLen1
db CopyLen2Len
dw CopyLen2
db CopyLen3Len
dw CopyLen3
db CopyLen4Len
dw CopyLen4
db CopyLen5Len
dw CopyLen5
db CopyLen6Len
dw CopyLen6
db CopyLen7Len
dw CopyLen7
db CopyLen8Len
dw CopyLen8
db CopyLen9Len
dw CopyLen9
db CopyLen10Len
dw CopyLen10
db CopyLen11Len
dw CopyLen11
db CopyLen12Len
dw CopyLen12
db CopyLen13Len
dw CopyLen13
db CopyLen14Len
dw CopyLen14
db CopyLen15Len
dw CopyLen15
db CopyLen16Len
dw CopyLen16
db CopyLen17Len
dw CopyLen17
db CopyLen18Len
dw CopyLen18
db CopyLen19Len
dw CopyLen19
db CopyLen20Len
dw CopyLen20
db CopyLen21Len
dw CopyLen21
db CopyLen22Len
dw CopyLen22
db CopyLen23Len
dw CopyLen23
db CopyLen24Len
dw CopyLen24
db CopyLen25Len
dw CopyLen25
db CopyLen26Len
dw CopyLen26
db CopyLen27Len
dw CopyLen27
db CopyLen28Len
dw CopyLen28
db ThrowInlineLen ; 286
dw ThrowInline
db ThrowInlineLen ; 287
dw ThrowInline
; For all of these routines, the calling convention is like this:
; c = bit reader state
; de = InputBufPos
; hl = OutputBufPos
; iy = Write_AndNext
; Literal/length alphabet symbols 0-255
WriteLit00: ld (hl),#00
jp (iy) ; Write_AndNext
WriteLit01: ld (hl),#01
jp (iy)
WriteLit02: ld (hl),#02
jp (iy)
WriteLit03: ld (hl),#03
jp (iy)
WriteLit04: ld (hl),#04
jp (iy)
WriteLit05: ld (hl),#05
jp (iy)
WriteLit06: ld (hl),#06
jp (iy)
WriteLit07: ld (hl),#07
jp (iy)
WriteLit08: ld (hl),#08
jp (iy)
WriteLit09: ld (hl),#09
jp (iy)
WriteLit0A: ld (hl),#0A
jp (iy)
WriteLit0B: ld (hl),#0B
jp (iy)
WriteLit0C: ld (hl),#0C
jp (iy)
WriteLit0D: ld (hl),#0D
jp (iy)
WriteLit0E: ld (hl),#0E
jp (iy)
WriteLit0F: ld (hl),#0F
jp (iy)
WriteLit10: ld (hl),#10
jp (iy)
WriteLit11: ld (hl),#11
jp (iy)
WriteLit12: ld (hl),#12
jp (iy)
WriteLit13: ld (hl),#13
jp (iy)
WriteLit14: ld (hl),#14
jp (iy)
WriteLit15: ld (hl),#15
jp (iy)
WriteLit16: ld (hl),#16
jp (iy)
WriteLit17: ld (hl),#17
jp (iy)
WriteLit18: ld (hl),#18
jp (iy)
WriteLit19: ld (hl),#19
jp (iy)
WriteLit1A: ld (hl),#1A
jp (iy)
WriteLit1B: ld (hl),#1B
jp (iy)
WriteLit1C: ld (hl),#1C
jp (iy)
WriteLit1D: ld (hl),#1D
jp (iy)
WriteLit1E: ld (hl),#1E
jp (iy)
WriteLit1F: ld (hl),#1F
jp (iy)
WriteLit20: ld (hl),#20
jp (iy)
WriteLit21: ld (hl),#21
jp (iy)
WriteLit22: ld (hl),#22
jp (iy)
WriteLit23: ld (hl),#23
jp (iy)
WriteLit24: ld (hl),#24
jp (iy)
WriteLit25: ld (hl),#25
jp (iy)
WriteLit26: ld (hl),#26
jp (iy)
WriteLit27: ld (hl),#27
jp (iy)
WriteLit28: ld (hl),#28
jp (iy)
WriteLit29: ld (hl),#29
jp (iy)
WriteLit2A: ld (hl),#2A
jp (iy)
WriteLit2B: ld (hl),#2B
jp (iy)
WriteLit2C: ld (hl),#2C
jp (iy)
WriteLit2D: ld (hl),#2D
jp (iy)
WriteLit2E: ld (hl),#2E
jp (iy)
WriteLit2F: ld (hl),#2F
jp (iy)
WriteLit30: ld (hl),#30
jp (iy)
WriteLit31: ld (hl),#31
jp (iy)
WriteLit32: ld (hl),#32
jp (iy)
WriteLit33: ld (hl),#33
jp (iy)
WriteLit34: ld (hl),#34
jp (iy)
WriteLit35: ld (hl),#35
jp (iy)
WriteLit36: ld (hl),#36
jp (iy)
WriteLit37: ld (hl),#37
jp (iy)
WriteLit38: ld (hl),#38
jp (iy)
WriteLit39: ld (hl),#39
jp (iy)
WriteLit3A: ld (hl),#3A
jp (iy)
WriteLit3B: ld (hl),#3B
jp (iy)
WriteLit3C: ld (hl),#3C
jp (iy)
WriteLit3D: ld (hl),#3D
jp (iy)
WriteLit3E: ld (hl),#3E
jp (iy)
WriteLit3F: ld (hl),#3F
jp (iy)
WriteLit40: ld (hl),#40
jp (iy)
WriteLit41: ld (hl),#41
jp (iy)
WriteLit42: ld (hl),#42
jp (iy)
WriteLit43: ld (hl),#43
jp (iy)
WriteLit44: ld (hl),#44
jp (iy)
WriteLit45: ld (hl),#45
jp (iy)
WriteLit46: ld (hl),#46
jp (iy)
WriteLit47: ld (hl),#47
jp (iy)
WriteLit48: ld (hl),#48
jp (iy)
WriteLit49: ld (hl),#49
jp (iy)
WriteLit4A: ld (hl),#4A
jp (iy)
WriteLit4B: ld (hl),#4B
jp (iy)
WriteLit4C: ld (hl),#4C
jp (iy)
WriteLit4D: ld (hl),#4D
jp (iy)
WriteLit4E: ld (hl),#4E
jp (iy)
WriteLit4F: ld (hl),#4F
jp (iy)
WriteLit50: ld (hl),#50
jp (iy)
WriteLit51: ld (hl),#51
jp (iy)
WriteLit52: ld (hl),#52
jp (iy)
WriteLit53: ld (hl),#53
jp (iy)
WriteLit54: ld (hl),#54
jp (iy)
WriteLit55: ld (hl),#55
jp (iy)
WriteLit56: ld (hl),#56
jp (iy)
WriteLit57: ld (hl),#57
jp (iy)
WriteLit58: ld (hl),#58
jp (iy)
WriteLit59: ld (hl),#59
jp (iy)
WriteLit5A: ld (hl),#5A
jp (iy)
WriteLit5B: ld (hl),#5B
jp (iy)
WriteLit5C: ld (hl),#5C
jp (iy)
WriteLit5D: ld (hl),#5D
jp (iy)
WriteLit5E: ld (hl),#5E
jp (iy)
WriteLit5F: ld (hl),#5F
jp (iy)
WriteLit60: ld (hl),#60
jp (iy)
WriteLit61: ld (hl),#61
jp (iy)
WriteLit62: ld (hl),#62
jp (iy)
WriteLit63: ld (hl),#63
jp (iy)
WriteLit64: ld (hl),#64
jp (iy)
WriteLit65: ld (hl),#65
jp (iy)
WriteLit66: ld (hl),#66
jp (iy)
WriteLit67: ld (hl),#67
jp (iy)
WriteLit68: ld (hl),#68
jp (iy)
WriteLit69: ld (hl),#69
jp (iy)
WriteLit6A: ld (hl),#6A
jp (iy)
WriteLit6B: ld (hl),#6B
jp (iy)
WriteLit6C: ld (hl),#6C
jp (iy)
WriteLit6D: ld (hl),#6D
jp (iy)
WriteLit6E: ld (hl),#6E
jp (iy)
WriteLit6F: ld (hl),#6F
jp (iy)
WriteLit70: ld (hl),#70
jp (iy)
WriteLit71: ld (hl),#71
jp (iy)
WriteLit72: ld (hl),#72
jp (iy)
WriteLit73: ld (hl),#73
jp (iy)
WriteLit74: ld (hl),#74
jp (iy)
WriteLit75: ld (hl),#75
jp (iy)
WriteLit76: ld (hl),#76
jp (iy)
WriteLit77: ld (hl),#77
jp (iy)
WriteLit78: ld (hl),#78
jp (iy)
WriteLit79: ld (hl),#79
jp (iy)
WriteLit7A: ld (hl),#7A
jp (iy)
WriteLit7B: ld (hl),#7B
jp (iy)
WriteLit7C: ld (hl),#7C
jp (iy)
WriteLit7D: ld (hl),#7D
jp (iy)
WriteLit7E: ld (hl),#7E
jp (iy)
WriteLit7F: ld (hl),#7F
jp (iy)
WriteLit80: ld (hl),#80
jp (iy)
WriteLit81: ld (hl),#81
jp (iy)
WriteLit82: ld (hl),#82
jp (iy)
WriteLit83: ld (hl),#83
jp (iy)
WriteLit84: ld (hl),#84
jp (iy)
WriteLit85: ld (hl),#85
jp (iy)
WriteLit86: ld (hl),#86
jp (iy)
WriteLit87: ld (hl),#87
jp (iy)
WriteLit88: ld (hl),#88
jp (iy)
WriteLit89: ld (hl),#89
jp (iy)
WriteLit8A: ld (hl),#8A
jp (iy)
WriteLit8B: ld (hl),#8B
jp (iy)
WriteLit8C: ld (hl),#8C
jp (iy)
WriteLit8D: ld (hl),#8D
jp (iy)
WriteLit8E: ld (hl),#8E
jp (iy)
WriteLit8F: ld (hl),#8F
jp (iy)
WriteLit90: ld (hl),#90
jp (iy)
WriteLit91: ld (hl),#91
jp (iy)
WriteLit92: ld (hl),#92
jp (iy)
WriteLit93: ld (hl),#93
jp (iy)
WriteLit94: ld (hl),#94
jp (iy)
WriteLit95: ld (hl),#95
jp (iy)
WriteLit96: ld (hl),#96
jp (iy)
WriteLit97: ld (hl),#97
jp (iy)
WriteLit98: ld (hl),#98
jp (iy)
WriteLit99: ld (hl),#99
jp (iy)
WriteLit9A: ld (hl),#9A
jp (iy)
WriteLit9B: ld (hl),#9B
jp (iy)
WriteLit9C: ld (hl),#9C
jp (iy)
WriteLit9D: ld (hl),#9D
jp (iy)
WriteLit9E: ld (hl),#9E
jp (iy)
WriteLit9F: ld (hl),#9F
jp (iy)
WriteLitA0: ld (hl),#A0
jp (iy)
WriteLitA1: ld (hl),#A1
jp (iy)
WriteLitA2: ld (hl),#A2
jp (iy)
WriteLitA3: ld (hl),#A3
jp (iy)
WriteLitA4: ld (hl),#A4
jp (iy)
WriteLitA5: ld (hl),#A5
jp (iy)
WriteLitA6: ld (hl),#A6
jp (iy)
WriteLitA7: ld (hl),#A7
jp (iy)
WriteLitA8: ld (hl),#A8
jp (iy)
WriteLitA9: ld (hl),#A9
jp (iy)
WriteLitAA: ld (hl),#AA
jp (iy)
WriteLitAB: ld (hl),#AB
jp (iy)
WriteLitAC: ld (hl),#AC
jp (iy)
WriteLitAD: ld (hl),#AD
jp (iy)
WriteLitAE: ld (hl),#AE
jp (iy)
WriteLitAF: ld (hl),#AF
jp (iy)
WriteLitB0: ld (hl),#B0
jp (iy)
WriteLitB1: ld (hl),#B1
jp (iy)
WriteLitB2: ld (hl),#B2
jp (iy)
WriteLitB3: ld (hl),#B3
jp (iy)
WriteLitB4: ld (hl),#B4
jp (iy)
WriteLitB5: ld (hl),#B5
jp (iy)
WriteLitB6: ld (hl),#B6
jp (iy)
WriteLitB7: ld (hl),#B7
jp (iy)
WriteLitB8: ld (hl),#B8
jp (iy)
WriteLitB9: ld (hl),#B9
jp (iy)
WriteLitBA: ld (hl),#BA
jp (iy)
WriteLitBB: ld (hl),#BB
jp (iy)
WriteLitBC: ld (hl),#BC
jp (iy)
WriteLitBD: ld (hl),#BD
jp (iy)
WriteLitBE: ld (hl),#BE
jp (iy)
WriteLitBF: ld (hl),#BF
jp (iy)
WriteLitC0: ld (hl),#C0
jp (iy)
WriteLitC1: ld (hl),#C1
jp (iy)
WriteLitC2: ld (hl),#C2
jp (iy)
WriteLitC3: ld (hl),#C3
jp (iy)
WriteLitC4: ld (hl),#C4
jp (iy)
WriteLitC5: ld (hl),#C5
jp (iy)
WriteLitC6: ld (hl),#C6
jp (iy)
WriteLitC7: ld (hl),#C7
jp (iy)
WriteLitC8: ld (hl),#C8
jp (iy)
WriteLitC9: ld (hl),#C9
jp (iy)
WriteLitCA: ld (hl),#CA
jp (iy)
WriteLitCB: ld (hl),#CB
jp (iy)
WriteLitCC: ld (hl),#CC
jp (iy)
WriteLitCD: ld (hl),#CD
jp (iy)
WriteLitCE: ld (hl),#CE
jp (iy)
WriteLitCF: ld (hl),#CF
jp (iy)
WriteLitD0: ld (hl),#D0
jp (iy)
WriteLitD1: ld (hl),#D1
jp (iy)
WriteLitD2: ld (hl),#D2
jp (iy)
WriteLitD3: ld (hl),#D3
jp (iy)
WriteLitD4: ld (hl),#D4
jp (iy)
WriteLitD5: ld (hl),#D5
jp (iy)
WriteLitD6: ld (hl),#D6
jp (iy)
WriteLitD7: ld (hl),#D7
jp (iy)
WriteLitD8: ld (hl),#D8
jp (iy)
WriteLitD9: ld (hl),#D9
jp (iy)
WriteLitDA: ld (hl),#DA
jp (iy)
WriteLitDB: ld (hl),#DB
jp (iy)
WriteLitDC: ld (hl),#DC
jp (iy)
WriteLitDD: ld (hl),#DD
jp (iy)
WriteLitDE: ld (hl),#DE
jp (iy)
WriteLitDF: ld (hl),#DF
jp (iy)
WriteLitE0: ld (hl),#E0
jp (iy)
WriteLitE1: ld (hl),#E1
jp (iy)
WriteLitE2: ld (hl),#E2
jp (iy)
WriteLitE3: ld (hl),#E3
jp (iy)
WriteLitE4: ld (hl),#E4
jp (iy)
WriteLitE5: ld (hl),#E5
jp (iy)
WriteLitE6: ld (hl),#E6
jp (iy)
WriteLitE7: ld (hl),#E7
jp (iy)
WriteLitE8: ld (hl),#E8
jp (iy)
WriteLitE9: ld (hl),#E9
jp (iy)
WriteLitEA: ld (hl),#EA
jp (iy)
WriteLitEB: ld (hl),#EB
jp (iy)
WriteLitEC: ld (hl),#EC
jp (iy)
WriteLitED: ld (hl),#ED
jp (iy)
WriteLitEE: ld (hl),#EE
jp (iy)
WriteLitEF: ld (hl),#EF
jp (iy)
WriteLitF0: ld (hl),#F0
jp (iy)
WriteLitF1: ld (hl),#F1
jp (iy)
WriteLitF2: ld (hl),#F2
jp (iy)
WriteLitF3: ld (hl),#F3
jp (iy)
WriteLitF4: ld (hl),#F4
jp (iy)
WriteLitF5: ld (hl),#F5
jp (iy)
WriteLitF6: ld (hl),#F6
jp (iy)
WriteLitF7: ld (hl),#F7
jp (iy)
WriteLitF8: ld (hl),#F8
jp (iy)
WriteLitF9: ld (hl),#F9
jp (iy)
WriteLitFA: ld (hl),#FA
jp (iy)
WriteLitFB: ld (hl),#FB
jp (iy)
WriteLitFC: ld (hl),#FC
jp (iy)
WriteLitFD: ld (hl),#FD
jp (iy)
WriteLitFE: ld (hl),#FE
jp (iy)
WriteLitFF: ld (hl),#FF
jp (iy)
WriteLitLen: equ WriteLit02 - WriteLit01
; Literal/length alphabet symbol 256
EndBlock: ret ; done inflating this block
EndBlockLen: equ $ - EndBlock
; Literal/length alphabet symbols 257-285
CopyLen0: ld ix,Copy_AndNext3
jp DistanceTree
CopyLen0Len: equ $ - CopyLen0
CopyLen1: ld ix,Copy_AndNext4
jp DistanceTree
CopyLen1Len: equ $ - CopyLen1
CopyLen2: ld ix,Copy_AndNext5
jp DistanceTree
CopyLen2Len: equ $ - CopyLen2
CopyLen3: ld ix,Copy_AndNext6
jp DistanceTree
CopyLen3Len: equ $ - CopyLen3
CopyLen4: ld ix,Copy_AndNext7
jp DistanceTree
CopyLen4Len: equ $ - CopyLen4
CopyLen5: ld ix,Copy_AndNext8
jp DistanceTree
CopyLen5Len: equ $ - CopyLen5
CopyLen6: ld ix,Copy_AndNext9
jp DistanceTree
CopyLen6Len: equ $ - CopyLen6
CopyLen7: ld ix,Copy_AndNext10
jp DistanceTree
CopyLen7Len: equ $ - CopyLen7
CopyLen8: ReadBitInlineA
ld a,0
adc a,11 ; 11..12
jp CopySetLength
CopyLen8Len: equ $ - CopyLen8
CopyLen9: ReadBitInlineA
ld a,0
adc a,13 ; 13..14
jp CopySetLength
CopyLen9Len: equ $ - CopyLen9
CopyLen10: ReadBitInlineA
ld a,0
adc a,15 ; 15..16
jp CopySetLength
CopyLen10Len: equ $ - CopyLen10
CopyLen11: ReadBitInlineA
ld a,0
adc a,17 ; 17..18
jp CopySetLength
CopyLen11Len: equ $ - CopyLen11
CopyLen12: call Read2Bits
add a,19 ; 19..22
jp CopySetLength
CopyLen12Len: equ $ - CopyLen12
CopyLen13: call Read2Bits
add a,23 ; 23..26
jp CopySetLength
CopyLen13Len: equ $ - CopyLen13
CopyLen14: call Read2Bits
add a,27 ; 27..30
jp CopySetLength
CopyLen14Len: equ $ - CopyLen14
CopyLen15: call Read2Bits
add a,31 ; 31..34
jp CopySetLength
CopyLen15Len: equ $ - CopyLen15
CopyLen16: call Read3Bits
add a,35 ; 35..42
jp CopySetLength
CopyLen16Len: equ $ - CopyLen16
CopyLen17: call Read3Bits
add a,43 ; 43..50
jp CopySetLength
CopyLen17Len: equ $ - CopyLen17
CopyLen18: call Read3Bits
add a,51 ; 51..58
jp CopySetLength
CopyLen18Len: equ $ - CopyLen18
CopyLen19: call Read3Bits
add a,59 ; 59..66
jp CopySetLength
CopyLen19Len: equ $ - CopyLen19
CopyLen20: call Read4Bits
add a,67 ; 67..82
jp CopySetLength
CopyLen20Len: equ $ - CopyLen20
CopyLen21: call Read4Bits
add a,83 ; 83..98
jp CopySetLength
CopyLen21Len: equ $ - CopyLen21
CopyLen22: call Read4Bits
add a,99 ; 99..114
jp CopySetLength
CopyLen22Len: equ $ - CopyLen22
CopyLen23: call Read4Bits
add a,115 ; 115..130
jp CopySetLength
CopyLen23Len: equ $ - CopyLen23
CopyLen24: call Read5Bits
add a,131 ; 131..162
jp CopySetLength
CopyLen24Len: equ $ - CopyLen24
CopyLen25: call Read5Bits
add a,163 ; 163..194
jp CopySetLength
CopyLen25Len: equ $ - CopyLen25
CopyLen26: call Read5Bits
add a,195 ; 195..226
jp CopySetLength
CopyLen26Len: equ $ - CopyLen26
CopyLen27: call Read5Bits
add a,227 ; 227..257
exx
ld c,a
ld b,0
jr nc,CopySetLength0
inc b
CopySetLength0 ld ix,Copy_AndNext
exx
jp DistanceTree
CopyLen27Len: equ $ - CopyLen27
CopyLen28: ld ix,Copy_AndNext258
jp DistanceTree
CopyLen28Len: equ $ - CopyLen28
; a = length
;CopySetLength:
CopySL: exx
ld c,a
ld b,0
ld ix,Copy_AndNext
exx
;jp DistanceTree ; this routine is copied in front of DistanceTree
CopySLLen: equ $ - CopySL
; -- Symbol routines used by the 'distance' Huffman tree
DistSymbols: db CopyDist0Len
dw CopyDist0
db CopyDist1Len
dw CopyDist1
db CopyDist2Len
dw CopyDist2
db CopyDist3Len
dw CopyDist3
db CopyDist4Len
dw CopyDist4
db CopyDist5Len
dw CopyDist5
db CopyDist6Len
dw CopyDist6
db CopyDist7Len
dw CopyDist7
db CopyDist8Len
dw CopyDist8
db CopyDist9Len
dw CopyDist9
db CopyDist10Len
dw CopyDist10
db CopyDist11Len
dw CopyDist11
db CopyDist12Len
dw CopyDist12
db CopyDist13Len
dw CopyDist13
db CopyDist14Len
dw CopyDist14
db CopyDist15Len
dw CopyDist15
db CopyDist16Len
dw CopyDist16
db CopyDist17Len
dw CopyDist17
db CopyDist18Len
dw CopyDist18
db CopyDist19Len
dw CopyDist19
db CopyDist20Len
dw CopyDist20
db CopyDist21Len
dw CopyDist21
db CopyDist22Len
dw CopyDist22
db CopyDist23Len
dw CopyDist23
db CopyDist24Len
dw CopyDist24
db CopyDist25Len
dw CopyDist25
db CopyDist26Len
dw CopyDist26
db CopyDist27Len
dw CopyDist27
db CopyDist28Len
dw CopyDist28
db CopyDist29Len
dw CopyDist29
db ThrowInlineLen
dw ThrowInline
db ThrowInlineLen
dw ThrowInline
; For all of these routines, the calling convention is like this:
; bc = length of the to-be-copied block
; 'c = bit reader state
; 'de = InputBufPos
; 'hl = OutputBufPos
; ix = copy-routine (Copy_AndNext or a specialized version Copy_AndNext<nn>)
; iy = Write_AndNext
; Distance alphabet symbols 0-29
CopyDist0: push hl
exx
ld hl,-1
jp (ix)
CopyDist0Len: equ $ - CopyDist0
CopyDist1: push hl
exx
ld hl,-2
jp (ix)
CopyDist1Len: equ $ - CopyDist1
CopyDist2: push hl
exx
ld hl,-3
jp (ix)
CopyDist2Len: equ $ - CopyDist2
CopyDist3: push hl
exx
ld hl,-4
jp (ix)
CopyDist3Len: equ $ - CopyDist3
CopyDist4: ReadBitInlineA ; set c-flag
sbc a,a ; carry ? -1 : 0
sub 5 ; carry ? -6 : -5
push hl
exx
ld l,a
ld h,#ff
jp (ix)
CopyDist4Len: equ $ - CopyDist4
CopyDist5: ReadBitInlineA
sbc a,a
sub 7 ; -7..-8
push hl
exx
ld l,a
ld h,#ff
jp (ix)
CopyDist5Len: equ $ - CopyDist5
CopyDist6: call Read2Bits
xor -9 ; -9..-12
push hl
exx
ld l,a
ld h,#ff
jp (ix)
CopyDist6Len: equ $ - CopyDist6
CopyDist7: call Read2Bits
xor -13 ; -13..-16
push hl
exx
ld l,a
ld h,#ff
jp (ix)
CopyDist7Len: equ $ - CopyDist7
CopyDist8: call Read3Bits
xor -17 ; -17..-24
push hl
exx
ld l,a
ld h,#ff
jp (ix)
CopyDist8Len: equ $ - CopyDist8
CopyDist9: call Read3Bits
xor -25 ; -25..-32
push hl
exx
ld l,a
ld h,#ff
jp (ix)
CopyDist9Len: equ $ - CopyDist9
CopyDist10: call Read4Bits
xor -33 ; -33..-48
push hl
exx
ld l,a
ld h,#ff
jp (ix)
CopyDist10Len: equ $ - CopyDist10
CopyDist11: call Read4Bits
xor -49 ; -49..-64
push hl
exx
ld l,a
ld h,#ff
jp (ix)
CopyDist11Len: equ $ - CopyDist11
CopyDist12: call Read5Bits
xor -65 ; -64..-96
push hl
exx
ld l,a
ld h,#ff
jp (ix)
CopyDist12Len: equ $ - CopyDist12
CopyDist13: call Read5Bits
xor -97 ; -97..-128
push hl
exx
ld l,a
ld h,#ff
jp (ix)
CopyDist13Len: equ $ - CopyDist13
CopyDist14: call Read6Bits
xor -129 ; -129..-192
push hl
exx
ld l,a
ld h,#ff
jp (ix)
CopyDist14Len: equ $ - CopyDist14
CopyDist15: call Read6Bits
xor -193 ; -193..-256
push hl
exx
ld l,a
ld h,#ff
jp (ix)
CopyDist15Len: equ $ - CopyDist15
CopyDist16: call Read7Bits
push hl
exx
cpl
ld l,a
ld h,-2 ; -257..-384
jp (ix)
CopyDist16Len: equ $ - CopyDist16
CopyDist17: call Read7Bits
push hl
exx
xor -385 & #FF
ld l,a
ld h,-2 ; -385..-512
jp (ix)
CopyDist17Len: equ $ - CopyDist17
CopyDist18: call Read8Bits
push hl
exx
cpl
ld l,a
ld h,-3 ; -513..-768
jp (ix)
CopyDist18Len: equ $ - CopyDist18
CopyDist19: call Read8Bits
push hl
exx
cpl
ld l,a
ld h,-4 ; -769..-1024
jp (ix)
CopyDist19Len: equ $ - CopyDist19
CopyDist20: call Read8Bits
ex af,af'
ReadBitInlineA
sbc a,a
sub 5 ; -5/-6 -> -1025..-1536
push hl
exx
ld h,a
ex af,af'
cpl
ld l,a
jp (ix)
CopyDist20Len: equ $ - CopyDist20
CopyDist21: call Read8Bits
ex af,af'
ReadBitInlineA
sbc a,a
sub 7 ; -7/-8 -> -1537..-2048
push hl
exx
ld h,a
ex af,af'
cpl
ld l,a
jp (ix)
CopyDist21Len: equ $ - CopyDist21
CopyDist22: call Read8Bits
ex af,af'
call Read2Bits
xor -9 ; -2049..-3072
push hl
exx
ld h,a
ex af,af'
cpl
ld l,a
jp (ix)
CopyDist22Len: equ $ - CopyDist22
CopyDist23: call Read8Bits
ex af,af'
call Read2Bits
xor -13 ; -3073..-4096
push hl
exx
ld h,a
ex af,af'
cpl
ld l,a
jp (ix)
CopyDist23Len: equ $ - CopyDist23
CopyDist24: call Read8Bits
ex af,af'
call Read3Bits
xor -17 ; -4097..-6144
push hl
exx
ld h,a
ex af,af'
cpl
ld l,a
jp (ix)
CopyDist24Len: equ $ - CopyDist24
CopyDist25: call Read8Bits
ex af,af'
call Read3Bits
xor -25 ; -6145..-8192
push hl
exx
ld h,a
ex af,af'
cpl
ld l,a
jp (ix)
CopyDist25Len: equ $ - CopyDist25
CopyDist26: call Read8Bits
ex af,af'
call Read4Bits
xor -33 ; -8193..-12288
push hl
exx
ld h,a
ex af,af'
cpl
ld l,a
jp (ix)
CopyDist26Len: equ $ - CopyDist26
CopyDist27: call Read8Bits
ex af,af'
call Read4Bits
xor -49 ; -12289..-16364
push hl
exx
ld h,a
ex af,af'
cpl
ld l,a
jp (ix)
CopyDist27Len: equ $ - CopyDist27
CopyDist28: call Read8Bits
ex af,af'
call Read5Bits
xor -65 ; -16385..-24576
push hl
exx
ld h,a
ex af,af'
cpl
ld l,a
jp (ix)
CopyDist28Len: equ $ - CopyDist28
CopyDist29: call Read8Bits
ex af,af'
call Read5Bits
xor -97 ; -24577..-32768
push hl
exx
ld h,a
ex af,af'
cpl
ld l,a
jp (ix)
CopyDist29Len: equ $ - CopyDist29
; -- Routines to read bits and bytes from the GZ file --
; Read a byte from the input
; Requires: regsiter DE contains 'InputBufPos' (in/out)
; a <- value
; Unchanged: bc, hl, ix, iy
; Note: Before the fast-path was:
; ld a,(de)
; inc e
; ret nz
; This is faster than the current implementation. Though in the places where
; performance matters ReadByte is (partially) inlined, and then this
; alternative is a tiny bit faster. It also results in overall simpler code.
ReadByte: inc e
call z,ReadByte2 ; crosses 256-byte boundary?
ld a,(de)
ret
ReadByte2: inc d
ld a,d
cp InputBufferEnd / 256
ret nz
push bc
push hl
ld de,InputBuffer
ld hl,InputBufSize
call GzipReadInputBuffer
pop hl
pop bc
ld de,InputBuffer
ret
; For speed reasons all the ReadXX functions below require register C and DE
; to contains certain values (and those functions also update C, DE). This
; function sets up the correct values in C and DE.
PrepareRead: ld a,(InputBits)
ld c,a
ld de,(InputBufPos)
ret
; After you're done calling the ReadXX functions and you want to use regsiters
; C and DE for other stuff again. They should be written back to memory.
FinishRead: ld (InputBufPos),de
ld a,c
ld (InputBits),a
ret
; 'outline' part of ReadBitInlineA
ReadBitA: ;call ReadByte ; partially inline this call
inc e
jr z,ReadBitA2
ld a,(de)
scf ; set sentinel bit
rra
ld c,a
ret
ReadBitA2: call ReadByte2
ld a,(de)
scf ; set sentinel bit
rra
ld c,a
ret
; Similar to ReadBitInlineA, but changes regsiter B instead of A (is a tiny bit
; slower because of that).
ReadBitInlineB: MACRO
srl c
call z,ReadBitB ; if sentinel bit is shifted out
ENDM
; 'outline' part of ReadBitInlineB
ReadBitB: ld b,a
;call ReadByte ; partially inline this call
inc e
jr z,ReadBitB2
ld a,(de)
scf ; set sentinel bit
rra
ld c,a
ld a,b
ret
ReadBitB2 call ReadByte2
ld a,(de)
scf ; set sentinel bit
rra
ld c,a
ld a,b
ret
; Routines to read {2..8} bits from the input.
; Requires: PrepareRead has been called (registers C and DE are reserved)
; a <- value
; Modifies: b
; Unchanged: hl, ix, iy
Read2Bits: xor a
ReadBitInlineB
rra
ReadBitInlineB
rla
rla
ret
Read3Bits: xor a
ReadBitInlineB
rra
ReadBitInlineB
rra
ReadBitInlineB
rla
rla
rla
ret
Read4Bits: xor a
ReadBitInlineB
rra
ReadBitInlineB
rra
ReadBitInlineB
rra
ReadBitInlineB
rla
rla
rla
rla
ret
Read5Bits: xor a
ReadBitInlineB
rra
ReadBitInlineB
rra
ReadBitInlineB
rra
ReadBitInlineB
rra
ReadBitInlineB
rra
rra
rra
rra
ret
Read6Bits: xor a
ReadBitInlineB
rra
ReadBitInlineB
rra
ReadBitInlineB
rra
ReadBitInlineB
rra
ReadBitInlineB
rra
ReadBitInlineB
rra
rra
rra
ret
Read7Bits: xor a
ReadBitInlineB
rra
ReadBitInlineB
rra
ReadBitInlineB
rra
ReadBitInlineB
rra
ReadBitInlineB
rra
ReadBitInlineB
rra
ReadBitInlineB
rra
rra
ret
Read8Bits: ReadBitInlineB
rra
ReadBitInlineB
rra
ReadBitInlineB
rra
ReadBitInlineB
rra
ReadBitInlineB
rra
ReadBitInlineB
rra
ReadBitInlineB
rra
ReadBitInlineB
rra
ret
; -- Routines to write to the output file --
; -- they also maintain a sliding window to the last 32kB
; -- and they calculate a CRC32 value of the data
; Write a byte to the output.
; This routine is very tightly coupled to the huffman decode routines. In fact
; it's not really a function at all. Instead of returning it jumps to
; 'LiteralTree'. And because of this, this function should not be called, but
; jumped to.
;
; a = value
; hl = OutputBufPos (in/out)
; Modifies: a
Write_AndNext: ;ld (hl),a ; write is already done
inc l
jp nz,LiteralTree ; crosses 256-byte boundary?
inc h
ld a,h
cp OutputBufEnd / 256
jp nz,LiteralTree ; end of buffer reached?
call FinishBlock2
; hl = OutputBufPos = OutputBuffer
jp LiteralTree
;;; TODO
Copy_AndNext3: pop de ; de = destination = OutputBufPos
add hl,de ; hl = source
ld a,h
sub OutputBuffer / 256
sub OutputBufSize / 256
jr nc,CopyWrap3
WrapContinue3 ld a,d
cp (OutputBufEnd / 256) - 1
jr nc,CopySlow3
ldi
ldi
ldi
push de
; and next
exx
pop hl ; updated OutputBufPos
jp LiteralTree
CopyWrap3: add a,OutputBuffer / 256
ld h,a
cp (OutputBufEnd / 256) - 1 ; only check source when it wrapped
jr c,WrapContinue3 ; does the source have a 256 byte margin without wrapping?
CopySlow3 ld bc,3
jp CopySlow
;;; TODO
Copy_AndNext4: pop de ; de = destination = OutputBufPos
add hl,de ; hl = source
ld a,h
sub OutputBuffer / 256
sub OutputBufSize / 256
jr nc,CopyWrap4
WrapContinue4 ld a,d
cp (OutputBufEnd / 256) - 1
jr nc,CopySlow4
ldi
ldi
ldi
ldi
push de
; and next
exx
pop hl ; updated OutputBufPos
jp LiteralTree
CopyWrap4: add a,OutputBuffer / 256
ld h,a
cp (OutputBufEnd / 256) - 1 ; only check source when it wrapped
jr c,WrapContinue4 ; does the source have a 256 byte margin without wrapping?
CopySlow4 ld bc,4
jp CopySlow
;;; TODO
Copy_AndNext5: pop de ; de = destination = OutputBufPos
add hl,de ; hl = source
ld a,h
sub OutputBuffer / 256
sub OutputBufSize / 256
jr nc,CopyWrap5
WrapContinue5 ld a,d
cp (OutputBufEnd / 256) - 1
jr nc,CopySlow5
ldi
ldi
ldi
ldi
ldi
push de
; and next
exx
pop hl ; updated OutputBufPos
jp LiteralTree
CopyWrap5: add a,OutputBuffer / 256
ld h,a
cp (OutputBufEnd / 256) - 1 ; only check source when it wrapped
jr c,WrapContinue5 ; does the source have a 256 byte margin without wrapping?
CopySlow5 ld bc,5
jp CopySlow
;;; TODO
Copy_AndNext6: pop de ; de = destination = OutputBufPos
add hl,de ; hl = source
ld a,h
sub OutputBuffer / 256
sub OutputBufSize / 256
jr nc,CopyWrap6
WrapContinue6 ld a,d
cp (OutputBufEnd / 256) - 1
jr nc,CopySlow6
ldi
ldi
ldi
ldi
ldi
ldi
push de
; and next
exx
pop hl ; updated OutputBufPos
jp LiteralTree
CopyWrap6: add a,OutputBuffer / 256
ld h,a
cp (OutputBufEnd / 256) - 1 ; only check source when it wrapped
jr c,WrapContinue6 ; does the source have a 256 byte margin without wrapping?
CopySlow6 ld bc,6
jp CopySlow
;;; TODO
Copy_AndNext7: pop de ; de = destination = OutputBufPos
add hl,de ; hl = source
ld a,h
sub OutputBuffer / 256
sub OutputBufSize / 256
jr nc,CopyWrap7
WrapContinue7 ld a,d
cp (OutputBufEnd / 256) - 1
jr nc,CopySlow7
ldi
ldi
ldi
ldi
ldi
ldi
ldi
push de
; and next
exx
pop hl ; updated OutputBufPos
jp LiteralTree
CopyWrap7: add a,OutputBuffer / 256
ld h,a
cp (OutputBufEnd / 256) - 1 ; only check source when it wrapped
jr c,WrapContinue7 ; does the source have a 256 byte margin without wrapping?
CopySlow7 ld bc,7
jp CopySlow
;;; TODO
Copy_AndNext8: pop de ; de = destination = OutputBufPos
add hl,de ; hl = source
ld a,h
sub OutputBuffer / 256
sub OutputBufSize / 256
jr nc,CopyWrap8
WrapContinue8 ld a,d
cp (OutputBufEnd / 256) - 1
jr nc,CopySlow8
ldi
ldi
ldi
ldi
ldi
ldi
ldi
ldi
push de
; and next
exx
pop hl ; updated OutputBufPos
jp LiteralTree
CopyWrap8: add a,OutputBuffer / 256
ld h,a
cp (OutputBufEnd / 256) - 1 ; only check source when it wrapped
jr c,WrapContinue8 ; does the source have a 256 byte margin without wrapping?
CopySlow8 ld bc,8
jp CopySlow
;;; TODO
Copy_AndNext9: pop de ; de = destination = OutputBufPos
add hl,de ; hl = source
ld a,h
sub OutputBuffer / 256
sub OutputBufSize / 256
jr nc,CopyWrap9
WrapContinue9 ld a,d
cp (OutputBufEnd / 256) - 1
jr nc,CopySlow9
ldi
ldi
ldi
ldi
ldi
ldi
ldi
ldi
ldi
push de
; and next
exx
pop hl ; updated OutputBufPos
jp LiteralTree
CopyWrap9: add a,OutputBuffer / 256
ld h,a
cp (OutputBufEnd / 256) - 1 ; only check source when it wrapped
jr c,WrapContinue9 ; does the source have a 256 byte margin without wrapping?
CopySlow9 ld bc,9
jp CopySlow
;;; TODO
Copy_AndNext10: pop de ; de = destination = OutputBufPos
add hl,de ; hl = source
ld a,h
sub OutputBuffer / 256
sub OutputBufSize / 256
jr nc,CopyWrap10
WrapContinue10 ld a,d
cp (OutputBufEnd / 256) - 1
jr nc,CopySlow10
ldi
ldi
ldi
ldi
ldi
ldi
ldi
ldi
ldi
ldi
push de
; and next
exx
pop hl ; updated OutputBufPos
jp LiteralTree
CopyWrap10: add a,OutputBuffer / 256
ld h,a
cp (OutputBufEnd / 256) - 1 ; only check source when it wrapped
jr c,WrapContinue10 ; does the source have a 256 byte margin without wrapping?
CopySlow10 ld bc,10
jr CopySlow
;;; TODO
Copy_AndNext258:ld bc,258
pop de ; de = destination = OutputBufPos
add hl,de ; hl = source
ld a,h
sub OutputBuffer / 256
sub OutputBufSize / 256
jr nc,CopyWrap258
WrapContinue258 ld a,d
cp (OutputBufEnd / 256) - 2
jr nc,CopySlow
ldi
ldi
Ldi258 ldi
ldi
ldi
ldi
ldi
ldi
ldi
ldi
ldi
ldi
ldi
ldi
ldi
ldi
ldi
ldi
jp pe,Ldi258
push de
; and next
exx
pop hl ; updated OutputBufPos
jp LiteralTree
CopyWrap258: add a,OutputBuffer / 256
ld h,a
cp (OutputBufEnd / 256) - 2 ; only check source when it wrapped
jr c,WrapContinue258 ; does the source have a 256 byte margin without wrapping?
jr CopySlow
; Repeat (copy) a chunk of data that was written before.
; Like 'Write_AndNext' above, this routine is very tightly coupled to the
; huffman decode routines. It does not return, instead it jumps to LiteralTree.
; (top-of-stack) = OutputBufPos
; bc = byte count (range 3-258)
; hl = -distance
; hl <- new OutputBufPos
; Modifies: (after exx) af, bc', de', hl'
Copy_AndNext: pop de ; de = destination = OutputBufPos
add hl,de ; hl = source
ld a,h
jr nc,CopyWrap
cp OutputBuffer / 256
jr c,CopyWrap
ld a,(OutputBufEnd / 256) - 3
WrapContinue: cp d ; does the destination have a 512 byte margin without wrapping?
jr c,CopySlow
ldi
ldi
ldir
push de
; and next
exx
pop hl ; updated OutputBufPos
jp LiteralTree
CopyWrap: add a,OutputBufSize / 256
ld h,a
ld a,(OutputBufEnd / 256) - 3 ; only check source when it wrapped
cp h ; does the source have a 512 byte margin without wrapping?
jp nc,WrapContinue
; bc = byte count
; hl = buffer source
; de = buffer destination
; Modifies: af, bc, de, hl
CopySlow: ld (OutputBufPos),de
ld e,l
ld d,h
add hl,bc
jr c,CopySplit
ld a,h
cp OutputBufEnd / 256
jp c,WrBlk_AndNext
; hl = end address
CopySplit: push bc
ld bc,OutputBufEnd
and a
sbc hl,bc ; hl = bytes past end
ex (sp),hl
pop bc
push bc
sbc hl,bc ; hl = bytes until end
ld c,l
ld b,h
call WriteBlock
pop bc
ld hl,OutputBuffer
ld a,b
or c
jp nz,CopySlow
; and next
exx
ld hl,(OutputBufPos)
jp LiteralTree
WrBlk_AndNext: call WriteBlock
; and next
exx
ld hl,(OutputBufPos)
jp LiteralTree
; bc = byte count
; de = source
; Modifies: af, bc, de, hl
WriteBlock: ld hl,(OutputBufPos)
add hl,bc
jr c,CopySplit2
ld a,h
cp OutputBufEnd / 256
jr nc,CopySplit2
and a
sbc hl,bc
ex de,hl
ldir
ld (OutputBufPos),de
ret
; hl = end address
CopySplit2: push bc
ld bc,OutputBufEnd
and a
sbc hl,bc ; hl = bytes past end
ld c,l
ld b,h
ex (sp),hl
sbc hl,bc ; hl = bytes until end
ld c,l
ld b,h
ex de,hl
ld de,(OutputBufPos)
ldir
push hl
ex de,hl ; hl = OutputBufPos
call FinishBlock2
pop de
pop bc
ld a,b
or c
jp nz,WriteBlock
ret
; a = value
; de,bc <- unchanged
;WriteByte: ld (hl),a
; inc l
; ret nz ; crosses 256-byte boundary?
WriteByte2: inc h
ld a,h
cp OutputBufEnd / 256
ret nz ; end of buffer reached?
jp FinishBlock2
; hl = OutputBufPos = OutputBuffer
; 'Finish' the data in the (fully or partially filled) OutputBuffer. This is
; - update OutputCount
; - update Crc32Value
; - write the data to disk
; - reinitialize OutputBufPos
; hl <- OutputBuffer
FinishBlock: ld hl,(OutputBufPos)
FinishBlock2: push bc
push de
ld bc,OutputBuffer
or a
sbc hl,bc ; hl = #bytes in OutputBuffer
jp z,FinishBlockEnd ; any data present?
; Increase count
push hl
ld bc,(OutputCount + 0)
add hl,bc
ld (OutputCount + 0),hl
jr nc,SkipInc64
ld hl,(OutputCount + 2)
inc hl
ld (OutputCount + 2),hl
SkipInc64:
; Update CRC32
ld a,(NoCrcCheck)
or a
jp nz,SkipCrcUpdate
ld hl,OutputBuffer
pop bc ; bc = #bytes in OutputBuffer
push bc
exx
push bc
push de
push hl
ld de,(Crc32Value + 0)
ld bc,(Crc32Value + 2) ; bc:de = old crc value (32-bit)
exx
; crc loop is unrolled 2x, so handle the case of an odd number
; of elements specially
bit 0,c
jr z,SkipOddCrc
ld a,(hl)
inc hl
exx
xor e
ld l,a
ld h,CRC32Table / 256
ld a,(hl)
xor d
ld e,a
inc h
ld a,(hl)
xor c
ld d,a
inc h
ld a,(hl)
xor b
ld c,a
inc h
ld b,(hl)
exx
SkipOddCrc: srl b
rr c ; bc /= 2
ld a,b
or c
jr z,CRC32End
ld a,c ; convert 16-bit counter bc to two 8-bit counters in b and c
dec bc
inc b
ld c,b
ld b,a
; Use the Z80 stack as an 'accelerator' to read bytes from a
; table -> the 'pop' instruction reads two bytes and increments
; the pointer into the table.
; Of course this only works when interrupts are disabled.
ld (SaveSP),sp
CRC32Loop2: di
ld sp,hl
CRC32Loop: pop hl
ld a,l
exx
xor e
ld l,a
ld h,CRC32Table / 256
ld a,(hl)
xor d
ld e,a
inc h
ld a,(hl)
xor c
ld d,a
inc h
ld a,(hl)
xor b
ld c,a
inc h
ld b,(hl)
exx
ld a,h
exx
xor e
ld l,a
ld h,CRC32Table / 256
ld a,(hl)
xor d
ld e,a
inc h
ld a,(hl)
xor c
ld d,a
inc h
ld a,(hl)
xor b
ld c,a
inc h
ld b,(hl)
exx
djnz CRC32Loop
; Don't disable interrupts for too long, so briefly enable them
; before disabling them again for the next iteration of the
; outer loop
ld hl,0
add hl,sp
ei
SaveSP=$+1
ld sp,0
dec c
jp nz,CRC32Loop2
CRC32End: exx
ld (Crc32Value + 0),de
ld (Crc32Value + 2),bc ; store updated crc value (32-bit)
pop hl
pop de
pop bc
exx
SkipCrcUpdate:
; Write data to file
ld de,OutputBuffer
pop hl ; hl = #bytes in OutputBuffer
call GzipWriteOutputBuffer
FinishBlockEnd: pop de
pop bc
ld hl,OutputBuffer
ld (OutputBufPos),hl
ret
; === strings ===
TextNotGzip:
; db "Not a GZIP file.", 0
TextNotDeflate:
; db "Not compressed with DEFLATE.", 0
TextUnknownFlag:
; db "Unknown flag.", 0
TextSizeError:
; db "Inflated size mismatch.", 0
TextCrcError:
; db "Inflated CRC32 mismatch.", 0
TextBlockErr:
; db "Invalid block type.", 0
TextLengthErr:
; db "Invalid length.", 0
; === variables ===
; -- Set by parsing the gzip header --
HeaderFlags: db 0
; -- Filled in by parsing the command line --
NoCrcCheck: db 0 ; non-zero when running without crc check
; -- Used during building the dynamic alphabet --
; Strictly speaking we only need to store the LSB of the following two values.
; But also storing the MSB allows for simpler code, so the space overhead here
; is more than made up in smaller code size.
hlit: dw 256 ; MSB fixed at '1'
hdist: dw 0 ; MSB fixed at '0'
; -- Used for reading the input file --
InputBufPos: dw InputBufferEnd - 1
InputBits: db 0 ; partially consumed byte, 0 -> start new byte
; -- Used for writing the output file
OutputCount: ds 4 ; 32-bit value
Crc32Value: ds 4,#FF ; 32-bit value
OutputBufPos: dw OutputBuffer
; === Constant tables ===
; -- Used during dynamic alphabet building
HeaderCodeOrder:db 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15
; -- The fixed alphabet --
; Lengths of the literal symbols
FixedLitLen: db 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 ; 0-143: 8
db 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8
db 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8
db 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8
db 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8
db 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8
db 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 ; 144-255: 9
db 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9
db 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9
db 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9
db 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 7, 7, 7, 7, 7, 7, 7, 7 ; 256-279: 7
db 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8 ; 280-287: 8
FixedLitCount: equ $ - FixedLitLen
; Lengths of the distance symbols
FixedDistLen: db 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
db 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
FixedDistCount: equ $ - FixedDistLen
; -- CRC32 lookup table, must be 256-byte aligned --
ds (256 - ($ & 255) & 255)
CRC32Table: ; uint32_t[256]
; bits 0-7
db #00, #96, #2c, #ba, #19, #8f, #35, #a3
db #32, #a4, #1e, #88, #2b, #bd, #07, #91
db #64, #f2, #48, #de, #7d, #eb, #51, #c7
db #56, #c0, #7a, #ec, #4f, #d9, #63, #f5
db #c8, #5e, #e4, #72, #d1, #47, #fd, #6b
db #fa, #6c, #d6, #40, #e3, #75, #cf, #59
db #ac, #3a, #80, #16, #b5, #23, #99, #0f
db #9e, #08, #b2, #24, #87, #11, #ab, #3d
db #90, #06, #bc, #2a, #89, #1f, #a5, #33
db #a2, #34, #8e, #18, #bb, #2d, #97, #01
db #f4, #62, #d8, #4e, #ed, #7b, #c1, #57
db #c6, #50, #ea, #7c, #df, #49, #f3, #65
db #58, #ce, #74, #e2, #41, #d7, #6d, #fb
db #6a, #fc, #46, #d0, #73, #e5, #5f, #c9
db #3c, #aa, #10, #86, #25, #b3, #09, #9f
db #0e, #98, #22, #b4, #17, #81, #3b, #ad
db #20, #b6, #0c, #9a, #39, #af, #15, #83
db #12, #84, #3e, #a8, #0b, #9d, #27, #b1
db #44, #d2, #68, #fe, #5d, #cb, #71, #e7
db #76, #e0, #5a, #cc, #6f, #f9, #43, #d5
db #e8, #7e, #c4, #52, #f1, #67, #dd, #4b
db #da, #4c, #f6, #60, #c3, #55, #ef, #79
db #8c, #1a, #a0, #36, #95, #03, #b9, #2f
db #be, #28, #92, #04, #a7, #31, #8b, #1d
db #b0, #26, #9c, #0a, #a9, #3f, #85, #13
db #82, #14, #ae, #38, #9b, #0d, #b7, #21
db #d4, #42, #f8, #6e, #cd, #5b, #e1, #77
db #e6, #70, #ca, #5c, #ff, #69, #d3, #45
db #78, #ee, #54, #c2, #61, #f7, #4d, #db
db #4a, #dc, #66, #f0, #53, #c5, #7f, #e9
db #1c, #8a, #30, #a6, #05, #93, #29, #bf
db #2e, #b8, #02, #94, #37, #a1, #1b, #8d
; bits 8-15
db #00, #30, #61, #51, #c4, #f4, #a5, #95
db #88, #b8, #e9, #d9, #4c, #7c, #2d, #1d
db #10, #20, #71, #41, #d4, #e4, #b5, #85
db #98, #a8, #f9, #c9, #5c, #6c, #3d, #0d
db #20, #10, #41, #71, #e4, #d4, #85, #b5
db #a8, #98, #c9, #f9, #6c, #5c, #0d, #3d
db #30, #00, #51, #61, #f4, #c4, #95, #a5
db #b8, #88, #d9, #e9, #7c, #4c, #1d, #2d
db #41, #71, #20, #10, #85, #b5, #e4, #d4
db #c9, #f9, #a8, #98, #0d, #3d, #6c, #5c
db #51, #61, #30, #00, #95, #a5, #f4, #c4
db #d9, #e9, #b8, #88, #1d, #2d, #7c, #4c
db #61, #51, #00, #30, #a5, #95, #c4, #f4
db #e9, #d9, #88, #b8, #2d, #1d, #4c, #7c
db #71, #41, #10, #20, #b5, #85, #d4, #e4
db #f9, #c9, #98, #a8, #3d, #0d, #5c, #6c
db #83, #b3, #e2, #d2, #47, #77, #26, #16
db #0b, #3b, #6a, #5a, #cf, #ff, #ae, #9e
db #93, #a3, #f2, #c2, #57, #67, #36, #06
db #1b, #2b, #7a, #4a, #df, #ef, #be, #8e
db #a3, #93, #c2, #f2, #67, #57, #06, #36
db #2b, #1b, #4a, #7a, #ef, #df, #8e, #be
db #b3, #83, #d2, #e2, #77, #47, #16, #26
db #3b, #0b, #5a, #6a, #ff, #cf, #9e, #ae
db #c2, #f2, #a3, #93, #06, #36, #67, #57
db #4a, #7a, #2b, #1b, #8e, #be, #ef, #df
db #d2, #e2, #b3, #83, #16, #26, #77, #47
db #5a, #6a, #3b, #0b, #9e, #ae, #ff, #cf
db #e2, #d2, #83, #b3, #26, #16, #47, #77
db #6a, #5a, #0b, #3b, #ae, #9e, #cf, #ff
db #f2, #c2, #93, #a3, #36, #06, #57, #67
db #7a, #4a, #1b, #2b, #be, #8e, #df, #ef
; bits 16-23
db #00, #07, #0e, #09, #6d, #6a, #63, #64
db #db, #dc, #d5, #d2, #b6, #b1, #b8, #bf
db #b7, #b0, #b9, #be, #da, #dd, #d4, #d3
db #6c, #6b, #62, #65, #01, #06, #0f, #08
db #6e, #69, #60, #67, #03, #04, #0d, #0a
db #b5, #b2, #bb, #bc, #d8, #df, #d6, #d1
db #d9, #de, #d7, #d0, #b4, #b3, #ba, #bd
db #02, #05, #0c, #0b, #6f, #68, #61, #66
db #dc, #db, #d2, #d5, #b1, #b6, #bf, #b8
db #07, #00, #09, #0e, #6a, #6d, #64, #63
db #6b, #6c, #65, #62, #06, #01, #08, #0f
db #b0, #b7, #be, #b9, #dd, #da, #d3, #d4
db #b2, #b5, #bc, #bb, #df, #d8, #d1, #d6
db #69, #6e, #67, #60, #04, #03, #0a, #0d
db #05, #02, #0b, #0c, #68, #6f, #66, #61
db #de, #d9, #d0, #d7, #b3, #b4, #bd, #ba
db #b8, #bf, #b6, #b1, #d5, #d2, #db, #dc
db #63, #64, #6d, #6a, #0e, #09, #00, #07
db #0f, #08, #01, #06, #62, #65, #6c, #6b
db #d4, #d3, #da, #dd, #b9, #be, #b7, #b0
db #d6, #d1, #d8, #df, #bb, #bc, #b5, #b2
db #0d, #0a, #03, #04, #60, #67, #6e, #69
db #61, #66, #6f, #68, #0c, #0b, #02, #05
db #ba, #bd, #b4, #b3, #d7, #d0, #d9, #de
db #64, #63, #6a, #6d, #09, #0e, #07, #00
db #bf, #b8, #b1, #b6, #d2, #d5, #dc, #db
db #d3, #d4, #dd, #da, #be, #b9, #b0, #b7
db #08, #0f, #06, #01, #65, #62, #6b, #6c
db #0a, #0d, #04, #03, #67, #60, #69, #6e
db #d1, #d6, #df, #d8, #bc, #bb, #b2, #b5
db #bd, #ba, #b3, #b4, #d0, #d7, #de, #d9
db #66, #61, #68, #6f, #0b, #0c, #05, #02
; bits 24-31
db #00, #77, #ee, #99, #07, #70, #e9, #9e
db #0e, #79, #e0, #97, #09, #7e, #e7, #90
db #1d, #6a, #f3, #84, #1a, #6d, #f4, #83
db #13, #64, #fd, #8a, #14, #63, #fa, #8d
db #3b, #4c, #d5, #a2, #3c, #4b, #d2, #a5
db #35, #42, #db, #ac, #32, #45, #dc, #ab
db #26, #51, #c8, #bf, #21, #56, #cf, #b8
db #28, #5f, #c6, #b1, #2f, #58, #c1, #b6
db #76, #01, #98, #ef, #71, #06, #9f, #e8
db #78, #0f, #96, #e1, #7f, #08, #91, #e6
db #6b, #1c, #85, #f2, #6c, #1b, #82, #f5
db #65, #12, #8b, #fc, #62, #15, #8c, #fb
db #4d, #3a, #a3, #d4, #4a, #3d, #a4, #d3
db #43, #34, #ad, #da, #44, #33, #aa, #dd
db #50, #27, #be, #c9, #57, #20, #b9, #ce
db #5e, #29, #b0, #c7, #59, #2e, #b7, #c0
db #ed, #9a, #03, #74, #ea, #9d, #04, #73
db #e3, #94, #0d, #7a, #e4, #93, #0a, #7d
db #f0, #87, #1e, #69, #f7, #80, #19, #6e
db #fe, #89, #10, #67, #f9, #8e, #17, #60
db #d6, #a1, #38, #4f, #d1, #a6, #3f, #48
db #d8, #af, #36, #41, #df, #a8, #31, #46
db #cb, #bc, #25, #52, #cc, #bb, #22, #55
db #c5, #b2, #2b, #5c, #c2, #b5, #2c, #5b
db #9b, #ec, #75, #02, #9c, #eb, #72, #05
db #95, #e2, #7b, #0c, #92, #e5, #7c, #0b
db #86, #f1, #68, #1f, #81, #f6, #6f, #18
db #88, #ff, #66, #11, #8f, #f8, #61, #16
db #a0, #d7, #4e, #39, #a7, #d0, #49, #3e
db #ae, #d9, #40, #37, #a9, #de, #47, #30
db #bd, #ca, #53, #24, #ba, #cd, #54, #23
db #b3, #c4, #5d, #2a, #b4, #c3, #5a, #2d
; === Buffers ===
; -- BuildDynAlpha --
; union {
; HdrCodeLengths ds MAX_HEADER_LEN
; struct {
; LLDCodeLengths ds MAX_LIT_LEN + MAX_DIST_LEN
; HeaderTree ds (8 + 5) * (MAX_HEADER_LEN - 1)
; }
; }
; These 3 buffers are only needed during BuildDynAlpha, though LLDCodeLengths
; cannot overlap with LiteralTree and DistanceTree
HdrCodeLSize: equ MAX_HEADER_LEN
LLDCodeLSize: equ MAX_LIT_LEN + MAX_DIST_LEN
HeaderTreeSize: equ (8 + 5) * (MAX_HEADER_LEN - 1)
HdrCodeLengths: equ GzipBuffersStart ; ds HdrCodeLSize
LLDCodeLengths: equ GzipBuffersStart ; ds LLDCodeLSize
HeaderTree: equ LLDCodeLengths + LLDCodeLSize ; ds HeaderTreeSize
HeaderTreeEnd: equ HeaderTree + HeaderTreeSize
; -- Generated literal/distance huffman trees
; These cannot overlap LLDCodeLengths, but overlapping HeaderTree is fine
LiteralTreeSize:equ (8 + 5) * (288 - 1)
LiteralTree: equ HeaderTree
LiteralTreeEnd: equ LiteralTree + LiteralTreeSize
DistTreeSize: equ (8 + 12) * (32 - 1)
CopySetLength: equ LiteralTreeEnd
DistanceTree: equ CopySetLength + CopySLLen
DistanceTreeEnd:equ DistanceTree + DistTreeSize
; -- Input and output file buffers
; These must be aligned at 256-byte boundary. OutputBuffer must be exactly
; 32kB. InputBuffer must be (any) multiple of 256 bytes, but bigger improves
; read performance.
Padding: equ (256 - ((DistanceTreeEnd) & 255)) & 255
OutputBufSize: equ #8000 ; _must_ be exactly 32kB
OutputBuffer: equ DistanceTreeEnd + Padding
OutputBufEnd: equ OutputBuffer + OutputBufSize
InputBufSize: equ 512
InputBuffer: equ OutputBufEnd
InputBufferEnd: equ InputBuffer + InputBufSize
; -- Huffman scratch area --
; Used while generating Huffman decoder. TODO maybe overlap with 'Padding'?
CountBufSize: equ MAX_CODELENGTH * 2 ; must be 256-byte aligned
CountBuffer: equ InputBufferEnd
CountBufEnd: equ CountBuffer + CountBufSize
SortedBufSize: equ 4 * MAX_LIT_LEN + 1
SortedBuffer: equ CountBufEnd
SortedBufEnd: equ SortedBuffer + SortedBufSize
GzipBuffersEnd: equ SortedBufEnd