6fee29082926 — Laurens Holst 5 years ago
ZlibArchive: Introduce decompressor for zlib format streams.
2 files changed, 389 insertions(+), 0 deletions(-)

A => src/Adler32Checker.asm
A => src/ZlibArchive.asm
A => src/Adler32Checker.asm +143 -0
@@ 0,0 1,143 @@ 
+;
+; Adler32 summer
+;
+Adler32Checker: MACRO
+	this:
+	Process:
+		push ix
+		ld ix,this
+	Process_this: equ $ - 2
+		call Adler32Checker_UpdateAdler32
+		pop ix
+		jp 0
+	Process_oldHook: equ $ - 2
+	adler32:
+		dd 1
+	_size:
+	ENDM
+
+Adler32Checker_class: Class Adler32Checker, Adler32Checker_template, Heap_main
+Adler32Checker_template: Adler32Checker
+
+; de = writer
+; ix = this
+; ix <- this
+; de <- this
+Adler32Checker_Construct:
+	ld iyl,e
+	ld iyh,d
+	ld e,(iy + Writer.flusher)
+	ld d,(iy + Writer.flusher + 1)
+	ld (ix + Adler32Checker.Process_oldHook),e
+	ld (ix + Adler32Checker.Process_oldHook + 1),d
+	ld e,ixl
+	ld d,ixh
+	ld (iy + Writer.flusher),e
+	ld (iy + Writer.flusher + 1),d
+	ld (ix + Adler32Checker.Process_this),e
+	ld (ix + Adler32Checker.Process_this + 1),d
+	ret
+
+; ix = this
+; ix <- this
+Adler32Checker_Destruct:
+	ret
+
+; bc = byte count
+; de = buffer start
+; ix = this
+; Modifies: none
+Adler32Checker_UpdateAdler32:
+	push af
+	push bc
+	push de
+	push hl
+	ex de,hl
+	exx
+	push bc
+	push de
+	push hl
+	ld e,(ix + Adler32Checker.adler32)
+	ld d,(ix + Adler32Checker.adler32 + 1)
+	ld c,(ix + Adler32Checker.adler32 + 2)
+	ld b,(ix + Adler32Checker.adler32 + 3)
+	call Adler32Checker_CalculateAdler32
+	ld (ix + Adler32Checker.adler32),e
+	ld (ix + Adler32Checker.adler32 + 1),d
+	ld (ix + Adler32Checker.adler32 + 2),c
+	ld (ix + Adler32Checker.adler32 + 3),b
+	pop hl
+	pop de
+	pop bc
+	exx
+	pop hl
+	pop de
+	pop bc
+	pop af
+	ret
+
+; bcde = expected adler32
+; ix = this
+; f <- nz: mismatch
+; Modifies: af, bc, de, hl
+Adler32Checker_VerifyAdler32:
+	ld l,(ix + Adler32Checker.adler32)
+	ld h,(ix + Adler32Checker.adler32 + 1)
+	and a
+	sbc hl,de
+	ret nz
+	ld l,(ix + Adler32Checker.adler32 + 2)
+	ld h,(ix + Adler32Checker.adler32 + 3)
+	and a
+	sbc hl,bc
+	ret
+
+; bc' = byte count
+; hl' = read address
+; bcde = current adler
+; ix = this
+; bcde <- updated adler
+; Modifies: af, bc, de, hl, bc', hl'
+Adler32Checker_CalculateAdler32: PROC
+	exx
+	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
+Loop:
+	ld a,(hl)
+	inc hl
+	exx
+	ld l,a
+	ld h,0
+	AddModulo hl, de, 65521
+	ld e,l
+	ld d,h
+	AddModulo hl, bc, 65521
+	ld c,l
+	ld b,h
+	exx
+	djnz Loop
+	dec c
+	jp nz,Loop
+	exx
+	ret
+	ENDP
+
+; ?hl = addend
+; ?de = addend
+; ?modulo = modulo value
+; Modifies: ?de
+AddModulo: MACRO ?hl, ?de, ?modulo
+	add ?hl,?de
+	jr nc,Check
+	ld ?de,10000H - ?modulo
+	add ?hl,?de
+Check:
+	ld ?de,10000H - ?modulo
+	add ?hl,?de
+	jr c,Done
+	sbc ?hl,?de
+Done:
+	ENDM

          
A => src/ZlibArchive.asm +246 -0
@@ 0,0 1,246 @@ 
+;
+; Zlib archive
+;
+ZlibArchive_DEFLATE_ID: equ 8
+ZlibArchive_MAX_WINDOW: equ 7
+
+ZlibArchive: MACRO
+	reader:
+		dw 0
+	inflate:
+		dw 0
+	adler32CheckEnabled:
+		db 0
+	adler32Checker:
+		dw 0
+	cm:
+		db 0
+	cinfo:
+		dd 0
+	flevel:
+		dd 0
+	adler32:
+		dd 0
+	_size:
+	ENDM
+
+ZlibArchive_class: Class ZlibArchive, ZlibArchive_template, Heap_main
+ZlibArchive_template: ZlibArchive
+
+; a = -1: Adler32 check enabled, 0: disabled
+; de = reader
+; ix = this
+; ix <- this
+; de <- this
+ZlibArchive_Construct:
+	ld (ix + ZlibArchive.reader),e
+	ld (ix + ZlibArchive.reader + 1),d
+	ld (ix + ZlibArchive.adler32CheckEnabled),a
+	call ZlibArchive_ReadHeader
+	ld e,ixl
+	ld d,ixh
+	ret
+
+; ix = this
+; ix <- this
+ZlibArchive_Destruct:
+	ret
+
+; ix = this
+; de <- file reader
+; iy <- file reader
+ZlibArchive_GetReaderIY:
+	ld e,(ix + ZlibArchive.reader)
+	ld d,(ix + ZlibArchive.reader + 1)
+	ld iyl,e
+	ld iyh,d
+	ret
+
+; ix = this
+; de <- Inflate implementation
+; ix <- Inflate implementation
+ZlibArchive_GetInflate:
+	ld e,(ix + ZlibArchive.inflate)
+	ld d,(ix + ZlibArchive.inflate + 1)
+	ld ixl,e
+	ld ixh,d
+	ret
+
+; ix = this
+ZlibArchive_ReadHeader:
+	call ZlibArchive_GetReaderIY
+	call Reader_ReadWordBE_IY
+	call ZlibArchive_CheckFCHECK
+	ld hl,ZlibArchive_invalidFCHECKError
+	jp nz,System_TerminateWithError
+	ld a,d
+	and 00001111B
+	cp ZlibArchive_DEFLATE_ID
+	ld hl,ZlibArchive_notDeflateError
+	jp nz,System_TerminateWithError
+	ld (ix + ZlibArchive.cm),a
+	ld a,d
+	and 11110000B
+	rrca
+	rrca
+	rrca
+	rrca
+	cp ZlibArchive_MAX_WINDOW + 1
+	ld hl,ZlibArchive_invalidWindowError
+	jp nc,System_TerminateWithError
+	ld (ix + ZlibArchive.cinfo),a
+	ld a,e
+	and 00100000B
+	ld hl,ZlibArchive_unsupportedPresetDictionaryError
+	jp nz,System_TerminateWithError
+	ld a,e
+	and 11000000B
+	rlca
+	rlca
+	ld (ix + ZlibArchive.flevel),a
+	ret
+
+; d = CMF
+; e = FLG
+; f <- nz: invalid
+; Modifies: af, bc, hl
+ZlibArchive_CheckFCHECK: PROC
+	ld l,e
+	ld h,d
+	ld c,31
+	xor a
+	ld b,16
+Loop:
+	add hl,hl
+	rla
+	cp c
+	jr c,NoAdd
+	sub c
+	inc l
+NoAdd:
+	djnz Loop
+	and a
+	ret
+	ENDP
+
+; ix = this
+ZlibArchive_ReadFooter:
+	call ZlibArchive_GetReaderIY
+	call Reader_ReadDoubleWordBE_IY
+	ld (ix + ZlibArchive.adler32),l
+	ld (ix + ZlibArchive.adler32 + 1),h
+	ld (ix + ZlibArchive.adler32 + 2),e
+	ld (ix + ZlibArchive.adler32 + 3),d
+	ret
+
+; de = writer (min 32K)
+; ix = this
+ZlibArchive_Extract:
+	bit 0,(ix + ZlibArchive.adler32CheckEnabled)
+	call nz,ZlibArchive_CreateAdler32Checker
+	call ZlibArchive_CreateInflate
+	call ZlibArchive_Inflate
+	call ZlibArchive_ReadFooter
+	call ZlibArchive_Verify
+	call ZlibArchive_DestroyInflate
+	bit 0,(ix + ZlibArchive.adler32CheckEnabled)
+	call nz,ZlibArchive_DestroyAdler32Checker
+	ret
+
+; de = writer (min 32K)
+; ix = this
+ZlibArchive_CreateInflate:
+	ld l,(ix + ZlibArchive.reader)
+	ld h,(ix + ZlibArchive.reader + 1)
+	push ix
+	call Inflate_class.New
+	call Inflate_Construct
+	pop ix
+	ld (ix + ZlibArchive.inflate),e
+	ld (ix + ZlibArchive.inflate + 1),d
+	ret
+
+; ix = this
+ZlibArchive_DestroyInflate:
+	push ix
+	call ZlibArchive_GetInflate
+	call Inflate_Destruct
+	call Inflate_class.Delete
+	pop ix
+	ld (ix + ZlibArchive.inflate),0
+	ld (ix + ZlibArchive.inflate + 1),0
+	ret
+
+; de = writer (min 32K)
+; ix = this
+ZlibArchive_CreateAdler32Checker:
+	push de
+	push ix
+	call Adler32Checker_class.New
+	call Adler32Checker_Construct
+	pop ix
+	ld (ix + ZlibArchive.adler32Checker),e
+	ld (ix + ZlibArchive.adler32Checker + 1),d
+	pop de
+	ret
+
+; de = writer (min 32K)
+; ix = this
+ZlibArchive_DestroyAdler32Checker:
+	ld e,(ix + ZlibArchive.adler32Checker)
+	ld d,(ix + ZlibArchive.adler32Checker + 1)
+	push ix
+	ld ixl,e
+	ld ixh,d
+	call Adler32Checker_Destruct
+	call Adler32Checker_class.Delete
+	pop ix
+	ret
+
+; ix = this
+ZlibArchive_Inflate:
+	push ix
+	call ZlibArchive_GetInflate
+	call Inflate_Inflate
+	pop ix
+	ret
+
+; ix = this
+ZlibArchive_Verify:
+	call ZlibArchive_VerifyAdler32
+	ld hl,ZlibArchive_adler32MismatchError
+	jp nz,System_TerminateWithError
+	ret
+
+; ix = this
+; f <- nz: mismatch
+ZlibArchive_VerifyAdler32:
+	bit 0,(ix + ZlibArchive.adler32CheckEnabled)
+	ret z
+	ld e,(ix + ZlibArchive.adler32Checker)
+	ld d,(ix + ZlibArchive.adler32Checker + 1)
+	push de
+	ld e,(ix + ZlibArchive.adler32)
+	ld d,(ix + ZlibArchive.adler32 + 1)
+	ld c,(ix + ZlibArchive.adler32 + 2)
+	ld b,(ix + ZlibArchive.adler32 + 3)
+	ex (sp),ix
+	call Adler32Checker_VerifyAdler32
+	pop ix
+	ret
+
+;
+ZlibArchive_invalidFCHECKError:
+	db "Invalid FCHECK.",13,10,0
+
+ZlibArchive_notDeflateError:
+	db "Not compressed with DEFLATE.",13,10,0
+
+ZlibArchive_invalidWindowError:
+	db "Invalid window size.",13,10,0
+
+ZlibArchive_unsupportedPresetDictionaryError:
+	db "Unsupported preset dictionary.",13,10,0
+
+ZlibArchive_adler32MismatchError:
+	db "Inflated Adler32 checksum mismatch.",13,10,0