;************** Inflate and Explode
;
;  inflate.c -- by Mark Adler
;  explode.c -- by Mark Adler
;
; Change history:
; 03/31/2010	Removed 386 instructions
; ../../1997	Modified for Doszip

include	clib.inc
include	iost.inc
include	malloc.inc
include	string.inc
include	unzip.inc
include	errno.inc

	public	zip_inflate
	public	zip_explode

OSIZE	equ	8000h

_TEXT	SEGMENT

ifdef DEBUG
	public	getdump
	public	dumpbits
	public	getbits
	public	huft_build
	public	decode_huft
	public	get_tree
	public	explode_docopy
	public	explode_lit
	public	explode_nolit
	public	inflatecode
	public	inflate_codes
	public	inflate_fixed
	public	inflate_dynamic
	public	inflate_stored
endif

bk 	textequ	<STDI.ios_l>
bb	textequ	<STDI.ios_bb>
bb_ax	textequ	<word ptr STDI.ios_bb>
bb_dx 	textequ	<word ptr STDI.ios_bb+2>

getbits proc
	cmp byte ptr bk,al
	jb @F
	    mov cx,ax
	    mov ax,1
	    shl ax,cl
	    dec ax
	    mov dx,ax
	    and ax,bb_ax
	    test dl,dl
	    ret
	@@:
	    mov cx,bx
	    mov bx,STDI.ios_i
	    cmp bx,STDI.ios_c
	    je getbits_read
	    @@:
		push ax
		inc STDI.ios_i
		les ax,STDI.ios_bp
		add bx,ax
		mov al,es:[bx]
		mov bx,cx
		mov cx,bk
	    ifdef __386__
		movzx eax,al
		shl eax,cl
		or bb,eax
		add byte ptr bk,8
		pop ax
	    else
		mov ah,0
		mov dx,ax
		shl ax,cl
		or bb_ax,ax
		mov al,8
		add byte ptr STDI.ios_l,al
		cmp cl,al
		pop ax
		jbe getbits
		neg cl
		add cl,16
		shr dx,cl
		or bb_dx,dx
	    endif
		jmp getbits
	getbits_read:
	    push cx
	    push ax
	    call ofread
	    pop dx
	    pop cx
	    jz @F
		mov ax,dx
		mov bx,STDI.ios_i
		jmp @B
      @@:
	ret
getbits endp

dumpbits proc
	sub byte ptr bk,cl
    ifdef __386__
	shr bb,cl
    else
	mov ax,bb_dx
	shr bb_dx,cl
	shr bb_ax,cl
	neg cl
	add cl,16
	shl ax,cl
	or bb_ax,ax
    endif
	ret
dumpbits endp

getdump proc
	call getbits
	jz @F
	  ifdef __386__
	    sub byte ptr bk,cl
	    shr bb,cl
	    test dl,dl
	  else
	    push ax
	    call dumpbits
	    test dl,dl
	    pop ax
	  endif
      @@:
	ret
getdump endp

;
; Free the malloc'ed tables built by huft_build(), which makes a linked
; list of the tables it made, with the links in a dummy first entry of
; each table.
;
huft_free proc pascal huft:dword
	les bx,huft
	.while bx
	    sub bx,6
	    pushm es:[bx+2]
	    invoke free, es::bx
	    pop bx
	    pop es
	.endw
	ret
huft_free endp

BMAX	= 16	; Maximum bit length of any code (16 for explode)
N_MAX	= 288	; Maximum number of codes in any set

huft_build proc pascal uses si di ds \
    b:dword, 	; code lengths in bits (all assumed <= BMAX)
    n:word, 	; number of codes (assumed <= N_MAX)
    s:word, 	; number of simple-valued codes (0..s-1)
    d:dword, 	; list of base values for non-simple codes
    e:dword, 	; list of extra bits for non-simple codes
    t:dword, 	; result: starting table
    m:dword	; maximum lookup bits, returns actual
local \
    z:word,		; number of entries in current table
    y:word,		; number of dummy codes added
    w:word,		; bits before this table == (l * h)
    p:word,		; pointer into c[], b[], or v[]
    l:word,		; stack of bits per table
    k:word,		; number of bits in current code
    i:word,		; counter, current code
    g:word,		; maximum code length
    el:dword,		; length of EOB code (value 256)
    a:word,		; counter for codes of length k
    q:dword,		; points to current table
    r:S_HUFT,		; table entry for structure assignment
    x[BMAX+1]:word,	; bit offsets, then code stack
    lx[BMAX+1]:word,	; memory for l[-1..BMAX-1]
    _c[BMAX+1]:word,	; bit length count table
    u[BMAX]:dword,	; table stack
    v[N_MAX]:word	; values in order of bit length

	invoke memzero, addr v, 774
	;--------------------------------------------------------------------
	; Generate counts for each bit length
	;--------------------------------------------------------------------
	lea ax,lx[2]
	mov l,ax
	mov cx,n
	lds di,b
	mov ax,BMAX
	.if cx > 256	; set length of EOB code, if any
	    mov ax,[di+512]
	.endif
	mov word ptr el,ax
	lea dx,_c
	.while cx
	    mov bx,[di]
	    add di,2
	    add bx,bx
	    add bx,dx
	    inc word ptr [bx]
	    dec cx
	.endw
	mov bx,dx
	mov ax,n
	.if [bx] == ax
	    xor ax,ax	; null input -- all zero length codes
	    les bx,t
	    stoso es:[bx],ax,ax
	    les bx,m
	    mov es:[bx],ax
	    jmp huft_build_end
	.endif
	;--------------------------------------------------------------------
	; Find minimum and maximum length, bound *m by those
	;--------------------------------------------------------------------
	mov di,1
	xor ax,ax
	.while di <= BMAX
	    mov bx,di
	    add bx,bx
	    add bx,dx
	    .if [bx] == ax
		inc di
	    .else
		.break
	    .endif
	.endw
	mov k,di	; minimum code length
	les bx,m
	.if es:[bx] < di
	    mov es:[bx],di
	.endif
	mov cx,BMAX
	xor ax,ax
	.repeat
	    mov bx,cx
	    add bx,bx
	    add bx,dx
	    .break .if [bx] != ax
	.untilcxz
	mov g,cx	; maximum code length
	mov bx,word ptr m
	.if cx < es:[bx]
	    mov es:[bx],cx
	.endif
	;--------------------------------------------------------------------
	; Adjust last length count to fill out codes, if needed
	;--------------------------------------------------------------------
	mov si,cx
	mov cx,di
	mov ax,1
	shl ax,cl
	mov cx,ax
	.while di < si
	    mov bx,di
	    add bx,bx
	    add bx,dx
	    sub cx,[bx]
	    jl huft_build_erzip	; bad input: more codes than bits
	    add cx,cx
	    inc di
	.endw
	;--------------------------------------------------------------------
	; Generate starting offsets into the value table for each length
	;--------------------------------------------------------------------
	mov bx,si
	add bx,bx
	add bx,dx
	sub cx,[bx]
	jl huft_build_erzip
	add [bx],cx
	mov y,cx
	xor ax,ax
	lea bx,x[2]
	mov [bx],ax
	mov di,dx
	add di,2
	dec si
	.while si
	    add ax,[di]
	    add di,2
	    add bx,2
	    mov [bx],ax
	    dec si
	.endw
	;--------------------------------------------------------------------
	; Make a table of values in order of bit lengths
	;--------------------------------------------------------------------
	xor cx,cx
	mov si,word ptr b
	.repeat
	    mov ax,[si]
	    add si,2
	    .if ax
		add ax,ax
		lea bx,x
		add bx,ax
		mov ax,[bx]
		inc word ptr [bx]
		add ax,ax
		lea bx,v
		add bx,ax
		mov [bx],cx
	    .endif
	    inc cx
	.until cx >= n
	;--------------------------------------------------------------------
	; Generate the Huffman codes and for each, make the table entries
	;--------------------------------------------------------------------
	xor ax,ax
	mov i,ax
	mov x,ax
	mov lx,ax
	mov si,-1
	lea ax,v
	mov p,ax
	jmp HUFT_BUILD_35
    huft_build_erzip:
	mov ax,ER_ZIP
	jmp huft_build_end
	;--------------------------------------------------------------------
	; compute minimum size table less than or equal to *m bits
	;--------------------------------------------------------------------
    HUFT_BUILD_16:
	mov w,ax
	inc si
	mov ax,g	; upper limit
	sub ax,w
	mov z,ax
	les bx,m
	.if ax > es:[bx]
	    mov ax,es:[bx]
	    mov z,ax
	.endif
	mov ax,k
	sub ax,w
	mov di,ax
	mov cx,ax
	mov ax,1
	shl ax,cl
	mov cx,ax
	mov dx,a
	inc dx
	.if ax > dx
	    sub cx,dx
	    lea bx,_c
	    mov ax,k
	    add ax,ax
	    add bx,ax
	    .repeat
		mov ax,z
		inc di
		.break .if di >= ax
		mov ax,cx
		add ax,ax
		mov cx,ax
		add bx,2
		.break .if ax <= [bx]
		mov ax,[bx]
		sub cx,ax
	    .until 0
	.endif
	mov ax,w
	add ax,di
	.if ax > word ptr el
	    mov ax,word ptr el
	    .if w < ax
		sub ax,w
		mov di,ax
	    .endif
	.endif
	mov ax,1
	mov cx,di
	shl ax,cl
	mov z,ax
	mov bx,si
	add bx,bx
	add bx,l
	mov [bx],di
	inc ax
	add ax,ax
	mov dx,ax
	add ax,ax
	add ax,dx
	invoke malloc, ax
	.if ZERO?
	    .if si
		invoke huft_free, u
	    .endif
	    mov ax,ER_MEM
	    jmp huft_build_end
	.endif
	;--------------------------------------------------------------------
	; link to list for huft_free()
	;--------------------------------------------------------------------
	les bx,t
	add ax,6
	stom q
	stom es:[bx]
	sub ax,4
	stom t
	mov es,dx
	mov bx,ax
	xor ax,ax
	mov es:[bx],ax
	mov es:[bx+2],ax
	mov ax,si
	add ax,ax
	add ax,ax
	lea bx,u
	add bx,ax
	movmx [bx],q
	mov ax,si
	or  ax,ax
	jz  HUFT_BUILD_23
	add ax,ax	; connect to last table, if there is one
	lea bx,x	; save pattern for backing up
	add bx,ax
	mov dx,i
	mov [bx],dx
	mov bx,l	; bits to dump before this table
	add bx,ax
	sub bx,2
	mov cx,[bx]
	mov r.huft_b,cl
	mov bx,ax   	; bits in this table
	mov ax,16
	add ax,di
	mov r.huft_e,al
	mov ax,word ptr q	; pointer to this table
	mov r.huft_n,ax
	mov ax,word ptr q+2
	mov r.huft_seg,ax
	mov ax,w
	sub ax,cx
	mov dx,ax
	mov ax,1
	mov cx,w
	shl ax,cl
	dec ax
	mov cx,i
	and cx,ax
	mov ax,cx
	mov cx,dx
	shr ax,cl
	add ax,ax
	mov dx,ax
	add ax,ax
	add dx,ax
	mov ax,si
	dec ax
	add ax,ax
	add ax,ax
	lea bx,u	; connect to last table
	add bx,ax
	mov ax,[bx]
	add ax,dx
	mov dx,[bx+2]
	mov es,dx
	mov bx,ax
	movmx es:[bx],r
	movmw es:[bx+4],r.huft_seg
    HUFT_BUILD_23:
	mov ax,si
	add ax,ax
	mov bx,l
	add bx,ax
	mov ax,w
	add ax,[bx]
	cmp ax,k
	jl HUFT_BUILD_16
	mov ax,k
	sub ax,w
	mov r.huft_b,al
	mov ax,n
	add ax,ax
	lea dx,v
	add ax,dx
	mov bx,p
	.if bx >= ax
	    mov r.huft_e,99	; out of values--invalid code
	.else
	    mov ax,[bx]
	    .if ax < s
		add p,2
		mov r.huft_n,ax	; simple code is just the value
		mov r.huft_e,16
		.if ax >= 256	; 256 is end-of-block code
		    mov r.huft_e,15
		.endif
	    .else
		add p,2		; non-simple -- look up in lists
		sub ax,s
		add ax,ax
		les bx,e
		add bx,ax
		mov dl,es:[bx]
		mov r.huft_e,dl
		les bx,d
		add bx,ax
		mov ax,es:[bx]
		mov r.huft_n,ax
	    .endif
	.endif
	mov cx,k
	sub cx,w
	mov ax,1
	shl ax,cl
	mov word ptr el+2,ax
	mov cx,w
	mov ax,i
	shr ax,cl
	mov cx,ax
	mov ax,word ptr q+2
	mov es,ax
	.while cx < z
	    mov ax,cx
	    add ax,ax
	    mov dx,ax
	    add ax,ax
	    add ax,dx
	    mov bx,word ptr q
	    add bx,ax
	    movmx es:[bx],r
	    movmw es:[bx+4],r.huft_seg
	    add cx,word ptr el+2
	.endw
	mov cx,k
	dec cx
	mov ax,1
	shl ax,cl
	mov cx,ax
	mov di,i
	.while di & cx
	    xor di,cx
	    shr cx,1
	.endw
	xor di,cx
	mov i,di
	.repeat		; backup over finished tables
	    mov ax,1
	    mov cx,w
	    shl ax,cl
	    dec ax
	    mov dx,di
	    and dx,ax
	    mov bx,si
	    add bx,bx
	    lea ax,x
	    add bx,ax
	    .break .if dx == [bx]
	    dec si
	    mov ax,si
	    add ax,ax
	    mov bx,l
	    add bx,ax
	    mov ax,[bx]
	    sub w,ax
	.until 0
    HUFT_BUILD_33:
	mov ax,a
	dec a
	.if ax
	   jmp HUFT_BUILD_23
	.endif
	inc k
    HUFT_BUILD_35:
	mov ax,k
	cmp ax,g
	jg @F
	mov bx,ax
	add bx,bx
	lea ax,_c
	add bx,ax
	mov ax,[bx]
	mov a,ax
	jmp HUFT_BUILD_33
      @@:
	mov bx,l
	mov ax,[bx]
	les bx,m
	mov es:[bx],ax	; return actual size of base table
	mov ax,1    	; Return true (1) --warning error--
	.if y == 0 || g == 1
	    dec ax	; if we were given an incomplete table
	.endif
    huft_build_end:
	ret
huft_build endp

;************** Explode an imploded compressed stream

; Get the bit lengths for a code representation from the compressed
; stream. If gettree() returns 4, then there is an error in the data.
; Otherwise zero is returned.

ex_b	equ [bp-02]
ex_io	equ [bp-04]
ex_s	equ [bp-08]
ex_bd	equ [bp-10]
ex_bl	equ [bp-12]
ex_bb	equ [bp-14]
ex_td	equ [bp-18]
ex_tl	equ [bp-22]
ex_tb	equ [bp-26]
ex_l	equ [bp-538]

get_tree proc
	mov di,ax
	call ogetc
	inc ax
	push ax
	xor si,si
	.repeat
	    call ogetc
	    mov dx,ax
	    and ax,000Fh
	    mov cx,ax
	    inc cx
	    and dx,00F0h
	    shr dx,4
	    inc dx
	    mov ax,dx
	    add ax,si
	    .if ax <= di
		.repeat
		    lea bx,ex_l
		    mov ax,si
		    add ax,ax
		    add bx,ax
		    mov [bx],cx
		    inc si
		    dec dx
		.until !dx
		pop ax
		dec ax
		.if !ZERO?
		    push ax
		.else
		    .if si == di
			ret
		    .endif
		    .break
		.endif
	    .else
		pop ax
		.break
	    .endif
	.until 0
	mov ax,4
	or ax,ax
	ret
get_tree endp

explode_init proc
	xor ax,ax
	mov STDI.ios_l,ax
	stoso STDI.ios_bb,ax,ax
	mov ex_io,ax
	movmx ex_s,zip_local.lz_fsize
	ret
explode_init endp

decode_huft proc
	call getbits
	.repeat
	    not ax
	    and ax,dx
	    add ax,ax
	    add bx,ax
	    add ax,ax
	    add bx,ax
	    mov es,si
	    mov cl,es:[bx.huft_b]
	  ifdef __386__
	    sub byte ptr bk,cl
	    shr bb,cl
	  else
	    call dumpbits
	  endif
	    xor ax,ax
	    mov al,es:[bx.huft_e]
	    mov si,ax
	    mov al,0
	    .if si > 16
		inc ax
		.if si != 99
		    sub si,16
		    mov ax,si
		    push es
		    call getbits
		    pop es
		    mov si,es:[bx+4]
		    mov bx,es:[bx+2]
		.else
		    .break
		.endif
	    .else
		.break
	    .endif
	.until 0
	or ax,ax
	ret
decode_huft endp

explode_docopy proc
	mov ax,ex_b
	call getdump
	mov di,ax
	mov bx,ex_td
	mov si,ex_td+2
	mov ax,ex_bd
	call decode_huft
	.if ZERO?
	    mov dx,es:[bx+2]
	    mov ax,STDO.ios_i
	    sub ax,di
	    sub ax,dx
	    mov di,ax
	    mov ax,ex_bl
	    mov bx,ex_tl
	    mov si,ex_tl+2
	    call decode_huft
	    .if ZERO?
		mov ax,si
		mov si,es:[bx+2]
		.if ax
		    mov ax,8
		    call getdump
		    add si,ax
		.endif
		xor ax,ax
		lodso ex_s,bx,dx
		stoso ex_s,ax,ax
		mov ax,si
		.if bx || (!bx && dx > ax)
		    sub dx,ax
		    sbb bx,0
		    stoso ex_s,bx,dx
		.endif
	      @@:
		and di,OSIZE-1
		mov ax,di
		.if ax <= STDO.ios_i
		    mov ax,STDO.ios_i
		.endif
		mov cx,OSIZE
		sub cx,ax
		.if cx > si
		    mov cx,si
		.endif
		sub si,cx
		mov ax,STDO.ios_i
		add STDO.ios_i,cx
		push ds
		push si
		mov si,di
		add di,cx
		push di
		cld
		lodso STDO.ios_bp,dx,bx
		mov es,dx
		mov ds,dx
		mov di,bx
		add di,ax
		add bx,si
		cmp ax,si
		mov si,bx
		jbe @_docopy_io
	      @_docopy_mov:
		rep movsb
	      @_docopy_pop:
		pop di
		pop si
		pop ds
		cmp STDO.ios_i,OSIZE
		jae @_docopy_flush
	      @_docopy_lup:
		or si,si
		jnz @B
		sub ax,ax
	    .endif
	.endif
	ret
    @_docopy_io:
	mov al,ex_io
	test al,al
	jnz @_docopy_mov
	rep stosb
	jmp @_docopy_pop
    @_docopy_flush:
	call oflush
	mov ex_io,al
	jnz @_docopy_lup
	mov ax,ER_DISK
	ret
explode_docopy endp

; Decompress the imploded data using coded literals and a sliding
; window (of size 2^(6+bdl) bytes).

explode_lit proc
	call explode_init
	@@:
	    mov ax,ex_s
	    or ax,ex_s+2
	    jz explode_flush
	    mov ax,1
	    call getdump
	    test al,al
	    jz @lit_docopy
		decm ex_s
		mov bx,ex_tb
		mov si,ex_tb+2
		mov ax,ex_bb
		call decode_huft
		jnz @F
		mov al,es:[bx+2]
		call oputc
		jz explode_eof
		cmp ax,STDO.ios_i
		jbe @B
		mov ex_io,al
		jmp @B
	    @lit_docopy:
		 call explode_docopy
		 test ax,ax
		 jz @B
	@@:
	ret
explode_lit endp

explode_flush:
	call oflush

explode_eof:	; Out of space..
	dec ax
	ret

; Decompress the imploded data using uncoded literals and a sliding
; window (of size 2^(6+bdl) bytes).

explode_nolit proc
	call explode_init
	@@:
	    mov ax,ex_s
	    or ax,ex_s+2
	    jz explode_flush
	    mov ax,1
	    call getdump
	    test al,al
	    jz @nolit_docopy
		decm ex_s
		mov ax,8
		call getdump
		call oputc
		jz explode_eof
		cmp ax,STDO.ios_i
		jbe @B
		mov ex_io,al
		jmp @B
	    @nolit_docopy:
		call explode_docopy
		test ax,ax
		jz @B
	ret
explode_nolit endp

zip_explode proc dist pascal uses si di
local \
    exb:	word,	; -02
    exio:	word,	; -04
    exs:	dword,	; -08
    exbd:	word,	; -10
    exbl:	word,	; -12
    exbb:	word,	; -14
    extd:	dword,	; -18
    extl:	dword,	; -22
    extb:	dword,	; -26
    exl[256]:	word	; -538
	mov ax,7
	mov exbl,ax
	.if word ptr zip_local.lz_csize+2 >= 3 && \
	    word ptr zip_local.lz_csize > 0D40h
	    inc ax
	.endif
	mov exbd,ax
	xor ax,ax
	stoso extb,ax,ax
	.if zip_local.lz_flag & 4
	    mov exbb,9
	    mov ax,256
	    call get_tree
	    .if ax
		jmp explode_end
	    .endif
	    .if func(huft_build, addr ex_l, 256,256,0,0, addr extb, addr exbb)
		.if ax == 1
		    jmp explode_freetb
		.endif
		jmp explode_end
	    .endif
	    mov ax,64
	    call get_tree
	    .if ax
		jmp explode_freetb
	    .endif
	    mov dx,offset cplen3
	.else
	    mov ax,64
	    call get_tree
	    .if ax
		jmp explode_end
	    .endif
	    mov dx,offset cplen2
	.endif
	.if func(huft_build, addr ex_l, 64, 0, ds::dx,
		addr exextra, addr extl, addr exbl)
	    .if ax == 1
		jmp explode_freetl
	    .endif
	    jmp explode_freetb
	.endif
	mov ax,64
	call get_tree
	.if ax
	    jmp explode_freetl
	.endif
	mov exb,6
	mov dx,offset cpdist4
	.if zip_local.lz_flag & 2
	    mov dx,offset cpdist8
	    inc exb
	.endif
	.if func(huft_build, addr ex_l, 64, 0, ds::dx,
		addr exextra, addr extd, addr exbd)
	    .if ax == 1
		jmp explode_freetd
	    .endif
	    jmp explode_freetb
	.endif
	.if word ptr extb == ax
	    call explode_nolit
	.else
	    call explode_lit
	.endif
    explode_freetd:
	push ax
	invoke huft_free, addr extd
	pop ax
    explode_freetl:
	push ax
	invoke huft_free, addr extl
	pop ax
    explode_freetb:
	push ax
	invoke huft_free, addr extb
	pop ax
    explode_end:
	ret
zip_explode endp

;************** Decompress the codes in a compressed block

inflatecode proc
	call getbits
	add ax,ax
	add bx,ax
	add ax,ax
	add bx,ax
	mov es,si
	sub ax,ax
	mov al,es:[bx.huft_e]
	mov si,ax
	cmp al,16
	ja @F
	mov cl,es:[bx.huft_b]
      ifdef __386__
	sub byte ptr bk,cl
	shr bb,cl
      else
	call dumpbits
      endif
	sub ax,ax
	ret
      @@:
	.while al != 99
	    mov cl,es:[bx.huft_b]
	  ifdef __386__
	    sub byte ptr bk,cl
	    shr bb,cl
	  else
	    call dumpbits
	  endif
	    sub si,16
	    mov ax,si
	    mov si,es
	    call getbits
	    mov es,si
	    les bx,es:[bx+2]
	    add ax,ax
	    add bx,ax
	    add ax,ax
	    add bx,ax
	    sub ax,ax
	    mov al,es:[bx.huft_e]
	    mov si,ax
	    .if al <= 16
		mov cl,es:[bx.huft_b]
	      ifdef __386__
		sub byte ptr bk,cl
		shr bb,cl
	      else
		call dumpbits
	      endif
		sub ax,ax
		ret
	    .endif
	.endw
	mov ax,1
	test al,al
	ret
inflatecode endp

inflate_codes proc pascal uses si di tl:dword, td:dword, wl:word, wd:word
	;
	; do until end of block
	;
	.while 1
	    lodso tl,si,bx
	    mov ax,wl
	    call inflatecode
	    .if ZERO?
		.if si == 16
		    mov al,es:[bx+2]
		    call oputc
		    jz inflate_codes_erdisk
		    .continue
		.elseif si == 15
		    xor ax,ax
		    ret
		.else
		    mov ax,si
		    mov si,es
		    call getdump
		    mov es,si
		    add ax,es:[bx+2]
		    mov di,ax
		    lodso td,si,bx
		    mov ax,wd
		    call inflatecode
		    jnz inflate_codes_end
		    push es:[bx.huft_n]
		    mov ax,si
		    call getdump
		    mov dx,ax
		    mov ax,STDO.ios_i
		    pop bx
		    sub ax,bx
		    sub ax,dx
		    mov bx,ax
		    .while 1
			and bx,OSIZE-1
			mov cx,OSIZE
			mov ax,bx
			.if ax <= STDO.ios_i
			    mov ax,STDO.ios_i
			.endif
			sub cx,ax
			.if cx > di
			    mov cx,di
			.endif
			sub di,cx
			mov ax,STDO.ios_i
			add STDO.ios_i,cx
			mov dx,di
			les di,STDO.ios_bp
			lds si,STDO.ios_bp
			add di,ax
			add si,bx
			add bx,cx
			add ax,cx
			cld
			rep movsb
			mov di,dx
			cmp ax,OSIZE;STDO.ios_size
			mov ax,ss
			mov ds,ax
			jae inflate_codes_flush
		      inflate_codes_ifdi:
			.break .if !di
		    .endw
		.endif
	    .else
		.break
	    .endif
	.endw
    inflate_codes_end:
	ret
    inflate_codes_flush:
	push bx
	call oflush
	pop bx
	jnz inflate_codes_ifdi
    inflate_codes_erdisk:
	mov ax,ER_DISK
	jmp inflate_codes_end
inflate_codes endp

;************** Decompress an inflated type 1 (fixed Huffman codes) block

inflate_fixed proc pascal uses di
local	l[288]:word	; length list for huft_build
	lea di,l
	xor ax,ax
	.if word ptr fixed_tl == ax
	    mov bx,di
	    push ss
	    pop es
	    cld
	    mov cx,144	; literal table
	    mov ax,8
	    rep stosw
	    mov cx,112
	    mov ax,9
	    rep stosw
	    mov cx,24
	    mov ax,7
	    rep stosw	; make a complete, but wrong code set
	    mov cx,8
	    mov ax,8
	    rep stosw
	    mov di,bx
	    mov fixed_bl,7
	    .if func(huft_build, ss::di, 288, 257, addr cplens,
		addr cplext, addr fixed_tl, addr fixed_bl)
		mov word ptr fixed_tl,0
		jmp @F
	    .endif
	    mov dx,di	; make an incomplete code set
	    mov cx,30
	    mov ax,5
	    push ss
	    pop es
	    cld
	    rep stosw
	    mov fixed_bd,5
	    mov di,dx
	    .if func(huft_build, ss::di, 30, 0, addr cpdist,
		addr cpdext, addr fixed_td, addr fixed_bd)
		.if ax != 1
		    push ax
		    invoke huft_free, fixed_tl
		    mov word ptr fixed_tl,0
		    pop ax
		    jmp @F
		.endif
	    .endif
	.endif
	;
	; decompress until an end-of-block code
	;
	invoke inflate_codes, fixed_tl, fixed_td, fixed_bl, fixed_bd
	or ax,ax
	jz @F
	mov ax,1
      @@:
	ret
inflate_fixed endp

;************** Decompress an inflated type 2 (dynamic Huffman codes) block

inflate_dynamic proc pascal uses si di
local	nd:word,	; number of distance codes
	nl:word,	; number of literal/length codes
	nb:word,	; number of bit length codes
	tl:dword,	; literal/length code table
	td:dword,	; distance code table
	wl:word,	; lookup bits for tl (bl)
	wd:word,	; lookup bits for td (bd)
	n:word,		; number of lengths to get
	ll[320]:word	; literal/length and distance code lengths
	mov ax,5
	call getdump
	add ax,257
	mov nl,ax	; number of literal/length codes
	mov ax,5
	call getdump
	inc ax
	mov nd,ax	; number of distance codes
	mov ax,4
	call getdump
	add ax,4
	mov nb,ax	; number of bit length codes
	;
	; PKZIP_BUG_WORKAROUND
	;
	.if nl > 288 || nd > 32
	    mov ax,1
	    jmp inflate_dynamic_end
	.endif
	xor si,si
	lea di,ll
	.while si < nb
	    mov ax,3
	    call getdump
	    mov dx,ax
	    mov bx,si
	    add bx,bx
	    mov ax,[bx+border]
	    add ax,ax
	    mov bx,di
	    add bx,ax
	    mov [bx],dx
	    inc si
	.endw
	.while si < 19
	    mov bx,si
	    add bx,bx
	    mov ax,[bx+border]
	    add ax,ax
	    mov bx,di
	    add bx,ax
	    xor ax,ax
	    mov [bx],ax
	    inc si
	.endw
	mov wl,7
	invoke huft_build, ss::di, 19, 19, 0, 0, addr tl, addr wl
	.if !wl
	    mov ax,1	; no bit lengths
	.endif
	.if ax		; incomplete code set
	    jmp inflate_dynamic_free1
	.endif
	mov ax,nl
	add ax,nd
	mov n,ax
	xor si,si
	mov di,si
	.while si < n
	    movmx td,tl
	    mov ax,wl
	    call getbits
	    add ax,ax
	    mov bx,ax
	    add ax,ax
	    add ax,bx
	    add word ptr td,ax
	    les bx,td
	    mov cl,es:[bx+1]
	  ifdef __386__
	    sub byte ptr bk,cl
	    shr bb,cl
	  else
	    call dumpbits
	  endif
	    mov ax,es:[bx+2]
	    .if ax == 16
		mov ax,2
		call getdump
		add ax,3
		mov dx,ax
		add ax,si
		.if ax > n
		    mov ax,1
		    jmp inflate_dynamic_end
		.endif
		lea ax,ll
		.while dx
		    dec dx
		    mov bx,si
		    inc si
		    add bx,bx
		    add bx,ax
		    mov [bx],di
		.endw
	    .elseif ax > 16
		.if ax != 17
		    mov ax,7
		    call getdump
		    add ax,11
		.else
		    mov ax,3
		    call getdump
		    add ax,3
		.endif
		mov dx,ax
		add ax,si
		.if ax > n
		    mov ax,1
		    jmp inflate_dynamic_end
		.endif
		xor di,di
		lea ax,ll
		.while dx
		   mov bx,si
		   inc si
		   add bx,bx
		   add bx,ax
		   mov [bx],di
		   dec dx
		.endw
	    .else
		mov di,ax
		lea ax,ll
		mov bx,si
		inc si
		add bx,bx
		add bx,ax
		mov [bx],di
	    .endif
	.endw
	invoke huft_free, tl
	mov ax,zlbits
	mov wl,ax
	invoke huft_build, addr ll, nl, 257, addr cplens,
	    addr cplext, addr tl, addr wl
	.if !wl
	    mov ax,1
	.endif
	.if ax
	    jmp inflate_dynamic_free1
	.endif
	mov ax,zdbits
	mov wd,ax
	lea ax,ll
	add ax,nl
	add ax,nl
	invoke huft_build, ss::ax, nd, 0, addr cpdist,
	    addr cpdext, addr td, addr wd
	.if !wd && nl > 257 ; ? wl
	    mov ax,1
	    jmp inflate_dynamic_free
	.endif
	.if ax == 1
	    xor ax,ax
	.endif
	.if ax
	    jmp inflate_dynamic_free
	.endif
	invoke inflate_codes, tl, td, wl, wd
	push ax
	invoke huft_free, td
	pop ax
	.if ax
	    mov ax,1
	.endif
    inflate_dynamic_free:
	push ax
	invoke huft_free, tl
	pop ax
    inflate_dynamic_end:
	ret
    inflate_dynamic_free1:
	cmp ax,1
	je  inflate_dynamic_free
	jmp inflate_dynamic_end
inflate_dynamic	endp

;****** Decompress an inflated type 0 (stored) block.

inflate_stored proc
	push si
	mov STDI.ios_l,0
	mov ax,16
	call getdump
	mov si,ax	; number of bytes in block
	mov ax,16
	call getdump
	not ax
	cmp ax,si
	jne inflate_stored_er1
	.while si	; read and output the compressed data
	    dec si
	    mov ax,8
	    call getdump
	    jz inflate_stored_er1
	    call oputc
	    jz inflate_stored_er2
	.endw
	xor ax,ax
      @@:
	pop si
	ret
inflate_stored_er1:
	mov ax,1	; error in compressed data
	jmp @B
inflate_stored_er2:
	mov ax,ER_DISK
	jmp @B
inflate_stored endp

zip_inflate proc DIST
	push si
	push di
	xor ax,ax
	stoso STDI.ios_bb,ax,ax
      @@:
	mov ax,1
	call getdump
	mov di,ax
	mov ax,2
	call getdump
	mov dx,ax
	.if ax == 2
	    call inflate_dynamic
	.elseif ax == 1
	    call inflate_fixed
	.elseif !ax
	    call inflate_stored
	.else
	    mov ax,ER_ZIP
	.endif
	mov si,ax
	or ax,ax
	jne @F
	or di,di
	jz @B
	call oflush
	jnz @F
	mov si,ER_USERABORT
	.if STDO.ios_flag & IO_ERROR
	    mov si,ER_DISK
	.endif
      @@:
	.if word ptr fixed_tl != 0
	    invoke huft_free, fixed_td
	    invoke huft_free, fixed_tl
	    mov word ptr fixed_td,0
	    mov word ptr fixed_tl,0
	.endif
	mov ax,si
	pop di
	pop si
	ret
zip_inflate endp

_TEXT	ENDS

_DATA	SEGMENT

fixed_bd	dw	0
fixed_bl	dw	0
fixed_td	dd	0
fixed_tl	dd	0

border		dw	16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15
cplens		dw	3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51
		dw	59,67,83,99,115,131,163,195,227,258,0,0
cplext		dw	0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5
		dw	5,5,5,0,99,99
cpdist		dw	1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257
		dw	385,513,769,1025,1537,2049,3073,4097,6145,8193
		dw	12289,16385,24577
cpdext		dw	0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9
		dw	10,10,11,11,12,12,13,13
zlbits		dw	9
zdbits		dw	6
cplen2		dw	2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17
		dw	18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34
		dw	35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51
		dw	52,53,54,55,56,57,58,59,60,61,62,63,64,65
cplen3		dw	3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18
		dw	19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35
		dw	36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52
		dw	53,54,55,56,57,58,59,60,61,62,63,64,65,66
exextra		dw	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
		dw	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
		dw	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
		dw	8
cpdist4		dw	1,65,129,193,257,321,385,449,513,577,641,705
		dw	769,833,897,961,1025,1089,1153,1217,1281,1345,1409,1473
		dw	1537,1601,1665,1729,1793,1857,1921,1985,2049,2113,2177
		dw	2241,2305,2369,2433,2497,2561,2625,2689,2753,2817,2881
		dw	2945,3009,3073,3137,3201,3265,3329,3393,3457,3521,3585
		dw	3649,3713,3777,3841,3905,3969,4033
cpdist8		dw	1,129,257,385,513,641,769,897,1025,1153,1281
		dw	1409,1537,1665,1793,1921,2049,2177,2305,2433,2561,2689
		dw	2817,2945,3073,3201,3329,3457,3585,3713,3841,3969,4097
		dw	4225,4353,4481,4609,4737,4865,4993,5121,5249,5377,5505
		dw	5633,5761,5889,6017,6145,6273,6401,6529,6657,6785,6913
		dw	7041,7169,7297,7425,7553,7681,7809,7937,8065

_DATA	ENDS

	END
