include	clib.inc
include	iost.inc
include	unzip.inc
include	string.inc
include	errno.inc
include	math.inc
include	conio.inc

	public	unzip

WSIZE	  = 8000h

_DATA	SEGMENT

key0	dd ?
key1	dd ?
key2	dd ?

	extrn	password:	byte
	extrn	enterpassword:	byte
	extrn	cp_warning: 	byte
	extrn	zip_attrib: 	word
	extrn	IDD_UnzipCRCError:dword

format_sL_02X	db "%s",10,"'%02X'",0

_DATA	ENDS

_TEXT	SEGMENT

CRC32:
      ifdef __386__
	xor ax,dx
	xor ah,ah
	shl ax,2
	mov bx,ax
	mov eax,[bx+crctab]
	shr edx,8
	xor eax,edx
      else
	mov dx,bx	; cx:bx, ax
	xor ax,dx
	xor ah,ah
	shl ax,2
	mov bx,ax
	mov dl,dh
	mov dh,cl
	mov cl,ch
	mov ch,0
	mov ax,word ptr [bx+crctab]
	xor ax,dx
	mov dx,word ptr [bx+crctab+2]
	xor dx,cx
      endif
	ret

update_keys:
      ifdef __386__
	push ax
	mov edx,key0
	call CRC32
	mov key0,eax
	and eax,000000FFh
	add eax,key1
	mov edx,134775813
	mul edx
	inc eax
	mov key1,eax
	mov edx,key2
	shr eax,24
	call CRC32
	mov key2,eax
	pop ax
      else
	push cx
	mov bx,word ptr key0
	mov cx,word ptr key0+2
	push ax
	call CRC32
	mov word ptr key0,ax
	mov word ptr key0+2,dx
	mov dx,word ptr key1+2
	mov ah,0
	add ax,word ptr key1
	adc dx,0
	mov cx,0808h
	mov bx,8405h
	call MUL32
	add ax,1
	adc dx,0
	mov word ptr key1,ax
	mov word ptr key1+2,dx
	mov bx,word ptr key2
	mov cx,word ptr key2+2
	mov al,dh
	xor dx,dx
	mov ah,00h
	call CRC32
	mov word ptr key2,ax
	mov word ptr key2+2,dx
	pop ax
	pop cx
      endif
	ret

decryptbyte:
	mov bx,word ptr key2
	or  bx,2
	mov dx,bx
	xor dx,1
	mov ax,bx
	mul dx
	mov al,ah
	ret

init_keys:
      ifdef __386__
	mov key0,12345678h
	mov key1,23456789h
	mov key2,34567890h
      else
	mov word ptr key0,5678h
	mov word ptr key0+2,1234h
	mov word ptr key1,6789h
	mov word ptr key1+2,2345h
	mov word ptr key2,7890h
	mov word ptr key2+2,3456h
      endif
	push si
	mov si,offset password
	.repeat
	    xor ax,ax
	    mov al,[si]
	    inc si
	    .break .if !al
	    call update_keys
	.until 0
	pop si
	ret

	public	odecrypt

odecrypt proc
	push si
	xor si,si
      @@:
	call decryptbyte
	les bx,dword ptr STDI
	add bx,si
	xor es:[bx],al
	mov al,es:[bx]
	call update_keys
	inc si
	cmp si,STDI.ios_c
	jl @B
	pop si
	ret
odecrypt endp

test_password proc pascal uses si di string:dword
local	b[12]:byte
	call init_keys
	lea di,b
	invoke memcpy, ss::di, string, 12
	xor si,si
	.repeat
	    call decryptbyte
	    xor [di],al
	    mov al,[di]
	    call update_keys
	    inc di
	    inc si
	.until si == 12
	lea di,b
	mov ax,zip_local.lz_time
	.if !(zip_attrib & _A_EXTLOCHD)
	    mov ax,word ptr zip_local.lz_crc+2
	.endif
	.if ah != [di+11]
	    xor ax,ax
	.else
	    mov cx,STDI.ios_c
	    sub cx,12
	    les si,dword ptr STDI
	    add si,12
	    .repeat
		call decryptbyte
		xor es:[si],al
		mov al,es:[si]
		call update_keys
		inc si
	    .untilcxz
	    mov ax,cx
	    inc ax
	.endif
	ret
test_password endp

zip_decrypt proc pascal uses si di
local	b[12]:byte
	mov si,12
	lea di,b
      @@:
	call ogetc
	mov [di],al
	inc di
	dec si
	jnz @B
	.if !func(test_password, addr b)
	    mov password,0
	    .if func(tgetline, addr enterpassword, addr password, 32, 80)
		xor ax,ax
		.if password != al
		    invoke test_password, addr b
		.endif
	    .endif
	.endif
	or ax,ax
	ret
zip_decrypt endp

unzip proc dist
	push si
	mov si,ER_MEM
	mov STDI.ios_file,ax	; zip file handle
	mov STDO.ios_file,dx	; out file handle
	invoke oinitst,addr STDO,WSIZE
	jz @F
	invoke oinitst,addr STDI,64000
	.if ZERO?
	    invoke oinitst,addr STDI,8000h
	.endif
	jz @F
	mov si,-1
	mov STDI.ios_flag,IO_USEBITS
	mov STDO.ios_flag,IO_UPDTOTAL or IO_USEUPD or IO_USECRC
	.if zip_attrib & _A_ENCRYPTED
	    call ogetc
	    jz @F
	    dec STDI.ios_i
	    call zip_decrypt
	    or ax,ax
	    jz @F
	    or STDI.ios_flag,IO_CRYPT
	.endif
	mov ax,zip_local.lz_method
	.if !ax
	    mov STDI.ios_flag,IO_USECRC
	    xor si,si
	    .if !func(ocopy, zip_local.lz_fsize)
		mov si,ax
	    .endif
	.elseif ax == 8
	    call zip_inflate
	    mov si,ax
	.elseif ax == 6
	    call zip_explode
	    mov si,ax
	.else
	    push zip_local.lz_method
	    pushm [sys_errlist+(ENOSYS*DPTRZ)]
	    mov dx,offset format_sL_02X
	    mov ax,offset cp_warning
	    call @ermsgt
	    add sp,6
	    mov si,3
	.endif
      @@:
	invoke ofreest,addr STDI
	invoke ofreest,addr STDO
	.if STDO.ios_flag & IO_ERROR
	    mov si,ER_DISK
	.elseif !si
	ifdef __386__
	    mov eax,STDO.ios_bb
	    not eax
	    cmp eax,zip_local.lz_crc
	else
	    lodm STDO.ios_bb
	    not ax
	    not dx
	    cmprm zip_local.lz_crc
	endif
	    .if !ZERO?
		.if !func(rsmodal, IDD_UnzipCRCError)
		    mov si,ER_CRCERR
		.endif
	    .endif
	.endif
	mov ax,si
	pop si
	ret
unzip endp

_TEXT	ENDS

	END
