; Copyright 1999-2015 Aske Simon Christensen.
; Decompress Shrinkler-compressed data produced with the -d option.
; Uses 3 kilobytes of buffer anywhere in the memory
; Decompression code may read one longword beyond compressed data.
; The contents of this longword does not matter.
;
; Z80 version of 245 bytes
; roudoudou, Hicks, Antonio Villena & Urusergi
; usage
;-------
; LD IX,source
; LD DE,destination
; CALL shrinkler_decrunch
;
;--------------------------------------------------


shrinkler_getnumber
        ld      bc, 1
        ld      hl, shrinkler_d6+2
        ld      (hl), a
        dec     hl
        ld      (hl), c
shrinkler_numberloop:
        inc     (hl)
        call    shrinkler_getbit
        inc     (hl)
        jr      c, shrinkler_numberloop
shrinkler_bitsloop:
        dec     (hl)
        dec     (hl)
        ret     m
        call    shrinkler_getbit
        rl      c
        rl      b
        jr      shrinkler_bitsloop

;--------------------------------------------------
shrinkler_readbit:
        ld      (shrinkler_d3+1), hl
shrinkler_d4l:
        ld      hl, 0
shrinkler_d4h:
        ld      de, #8000
shrinkler_rb0
	adc hl,hl
	ld (shrinkler_d4l+1),hl
	ex hl,de
	jr nz,shrinkler_rb2-1
	adc hl,hl
	jr nz,shrinkler_rb3
shrinkler_rb1
	ld h,(ix)
	ld l,(ix+1)
	inc ix
	inc ix
	ccf
	jr c,shrinkler_rb0
	ex hl,de
	jr shrinkler_rb1-3
shrinkler_rb2
        ld	l,d ;adc hl, hl with ed prefix
shrinkler_rb3
        ld      (shrinkler_d4h+1),hl
shrinkler_d2
        ld      hl, 0
        adc     hl, hl
        ld      (shrinkler_d2+1), hl
        jr      shrinkler_getbit1


;--------------------------------------------------
shrinkler_getkind:
        ;Use parity as context
	ld l,1
shrinkler_altgetbit:
	ld a,l
	and e
	ld h,a
	dec hl
        ld      (shrinkler_d6+1), hl


shrinkler_getbit:
        exx
shrinkler_getbit1:
        ld      hl, (shrinkler_d3+1)
        add     hl,hl
        jr      nc, shrinkler_readbit


shrinkler_d6:
        ld      hl, 0
        add     hl, hl
        ld      de, shrinkler_pr+2        ; cause -1 context
        add     hl, de
        push    hl
        ld      e, (hl)
        inc     hl
        ld      d, (hl)
        ; D1 = One prob
        push    de
        ld      b, d
        ld      c, e            ; bc=de=d1 / hl=a1
        ld      a, #EB
shrinkler_shift4:
        srl     b
        rr      c
        add     a, a
        jr      c, shrinkler_shift4-1
	sbc     hl, bc          ; hl=d1-d1/16
        ex      hl, de
        ld      (hl), d
        dec     hl
        ld      (hl), e
        pop     bc              ; bc=d1 initial
shrinkler_d3:
        ld      de, 1
        sbc     hl, hl
shrinkler_muluw:
        add     hl, hl
        rl      e
        rl      d
        jr      nc, shrinkler_cont
        add     hl, bc
        jr      nc, shrinkler_cont
        inc     de
shrinkler_cont:
        sub		#0B
        jr      nz, shrinkler_muluw
        ld      hl, (shrinkler_d2+1)
        sbc     hl, de
        pop     bc
        jr      nc, shrinkler_zero


shrinkler_one:
        ; onebrob = 1 - (1 - oneprob) * (1 - adjust) = oneprob - oneprob * adjust + adjust
        ld      a, (bc)
        sub     1
        ld      (bc), a
        inc     bc
        ld      a, (bc)
        sbc     a, #F0                  ; (a1)+#FFF
        ld      (bc), a
        ex      de, hl
        jr      shrinkler_d3ret


shrinkler_decrunch:
        ; Init range decoder state
        ld      bc,shrinkler_pr
	xor	a
shrinkler_init
        ld      (bc),a
	xor	#80
	inc	bc
	ld	h,(#F400-shrinkler_pr)>>8
	add	hl,bc
	jr	nc,shrinkler_init


shrinkler_lit:
        ; Literal
        scf
shrinkler_getlit:
        call    nc, shrinkler_getbit
        ld      hl, shrinkler_d6+1
        rl      (hl)
        jr      nc, shrinkler_getlit
        ldi


        ; After literal
        call    shrinkler_getkind
        jr      nc, shrinkler_lit
        ; Reference
        call    shrinkler_altgetbit
        jr      nc, shrinkler_readoffset
shrinkler_readlength:
        call    shrinkler_getnumber
shrinkler_d5:
        ld      hl, 0
        add     hl, de
        ldir
        ; After reference
        call    shrinkler_getkind
        jr      nc, shrinkler_lit
shrinkler_readoffset:
	dec a
        call    shrinkler_getnumber
        ; return without carry and HL=BC
        ld      hl, 2
        sbc     hl, bc
        ld      (shrinkler_d5+1), hl
        jr      nz, shrinkler_readlength


shrinkler_zero:
        ; oneprob = oneprob * (1 - adjust) = oneprob - oneprob * adjust
        ld      (shrinkler_d2+1), hl
        ld      hl, (shrinkler_d3+1)
        sbc     hl, de

shrinkler_d3ret:
        ld      (shrinkler_d3+1), hl
        exx
	ld a,4
        ret


shrinkler_pr	EQU $

