include clib.inc

ifdef __ZIP__

include dos.inc
include io.inc
include iost.inc
include dir.inc
include errno.inc
include string.inc
include wsub.inc
include unzip.inc
include time.inc
include fblk.inc
include	confirm.inc
include syserrls.inc
include doserrls.inc
include conio.inc
include	progress.inc

USE_DEFLATE = 1
ISIZE	equ	8000h

	extrn	cp_ziptemp:byte
	extrn	arc_flength:dword
	extrn	cp_emarchive:byte
	extrn	copy_fast:byte
  if USE_DEFLATE
	_C_BEST		= 0300h
	_C_FASTEST	= 0200h
	_C_SMALLEST	= 0100h
	extrn	file_method:byte
	extrn	compresslevel:byte
  endif

_DATA	SEGMENT

centhnd	dw -1
centtmp	db 'centtmp.$$$',0

_DATA	ENDS

_TEXT	SEGMENT

display_error:
	mov	ax,offset CP_DOSER20
	mov	dx,offset CP_ENOMEM
	test	STDO.ios_flag,IO_ERROR
	jnz	@F
	mov	ax,offset CP_ENOMEM
	cmp     errno,ENOMEM
	je	@F
	mov	ax,offset cp_emarchive
	mov	dx,offset CP_DOSER04
      @@:
      	call	@ermsgt
	ret

zip_renametemp proc
	invoke	oclose,addr STDI
	invoke	oclose,addr STDO
	invoke	filexist,ds::di		; 1 file, 2 subdir
	cmp	ax,1
	jne	@F
	invoke	remove,ds::si
	invoke	rename,ds::di,ds::si	; 0 or -1
	ret
      @@:
	mov	ax,-1
	ret
zip_renametemp endp

zip_copyendcentral proc dist public
	push	si
	push	di
	mov	si,ax
	mov	di,dx
	call	otell
	sub	ax,word ptr zip_endcent.ze_off_cent
	sbb	dx,word ptr zip_endcent.ze_off_cent+2
	stom	zip_endcent.ze_size_cent
	inv	oread, SIZE S_ZEND
	jz	copyendcentral_fail
	invoke	memcpy, es::bx, addr zip_endcent, SIZE S_ZEND
	mov	ax,zip_endcent.ze_comment_size
	add	ax,SIZE S_ZEND
	invoke	ocopy, cx::ax
	jz	copyendcentral_fail
	call	oflush
	jz	copyendcentral_fail
	movmx	arc_flength,STDO.ios_total
	call	zip_renametemp		; 0 or -1
      @@:
	pop	di
	pop	si
	ret
    copyendcentral_fail:
	dec	ax			; -1
	jmp	@B
zip_copyendcentral endp

update_local proc
	cmpmm	zip_central.cz_off_local, STDO.ios_total
	jb	@F
	sub	ax,word ptr STDO.ios_total
	mov	dx,word ptr STDO.ios_bp+2
	add	ax,word ptr STDO.ios_bp
	invoke	memcpy,dx::ax,addr zip_local,SIZE S_LZIP
	ret
      @@:
	call	oflush
	jz	@F
	invoke	lseek,STDO.ios_file,zip_central.cz_off_local,SEEK_SET
	invoke	oswrite,STDO.ios_file,addr zip_local,SIZE S_LZIP
	invoke	lseek,STDO.ios_file,0,SEEK_END
      @@:
	ret
update_local endp

mkarchivetmp proc
	invoke	strcpy,ss::ax,addr __outfile
	inv	addext,ax,offset cp_ziptemp
	ret
mkarchivetmp endp

set_progress proc
	invoke	progress_set,addr __outfile,ss::bx,dx::ax
	mov	STDO.ios_flag,IO_USEUPD or IO_UPDTOTAL
	ret
set_progress endp

initentry proc				; AX	offset file name buffer
	push	ax			; BX	time
	mov	ax,bx			; DI	date
	mov	zip_local.lz_time,ax	; CX:DX	size
	mov	zip_central.cz_time,ax	; SI	attrib
	mov	ax,di
	mov	zip_local.lz_date,ax
	mov	zip_central.cz_date,ax
  ifdef __386__
	mov	eax,edx
	mov	zip_local.lz_fsize,eax
	mov	zip_local.lz_csize,eax
	mov	zip_central.cz_fsize,eax
	mov	zip_central.cz_csize,eax
  else
	mov	ax,cx
	mov	word ptr zip_local.lz_fsize+2,ax
	mov	word ptr zip_local.lz_csize+2,ax
	mov	word ptr zip_central.cz_fsize+2,ax
	mov	word ptr zip_central.cz_csize+2,ax
	mov	ax,dx
	mov	word ptr zip_local.lz_fsize,ax
	mov	word ptr zip_local.lz_csize,ax
	mov	word ptr zip_central.cz_fsize,ax
	mov	word ptr zip_central.cz_csize,ax
  endif
	mov	ax,si
	and	ax,_A_FATTRIB
	mov	zip_central.cz_ext_attrib,ax
	pop	ax
	invoke	strcpy,ss::ax,addr __outpath
	test	si,_A_SUBDIR
	jnz	@F
	invoke	unixtodos,dx::ax
	push	ax
	invoke	strfn,addr __srcfile
	pop	cx
	invoke	strfcat,ss::cx,0,dx::ax
	invoke	dostounix,dx::ax
      @@:
	invoke	strlen,dx::ax
	mov	zip_local.lz_fnsize,ax
	mov	zip_central.cz_fnsize,ax
	ret
initentry endp

clearentry proc
	invoke	memzero,addr zip_local,SIZE S_LZIP
	invoke	memzero,addr zip_central,SIZE S_CZIP
	mov	zip_local.lz_pkzip,ZIPHEADERID
	mov	zip_local.lz_zipid,ZIPLOCALID
	mov	byte ptr zip_local.lz_version,20
	mov	zip_central.cz_pkzip,ZIPHEADERID
	mov	zip_central.cz_zipid,ZIPCENTRALID
	mov	byte ptr zip_central.cz_version_made,20
	mov	byte ptr zip_central.cz_version_need,10
	ret
clearentry endp

compress proc
  ifdef __386__
	cmp	zip_local.lz_fsize,2
	jb	@F
  else
	cmp	word ptr zip_local.lz_fsize+2,0
	jne	compress_00
	cmp	word ptr zip_local.lz_fsize,2
	jb	@F
    compress_00:
  endif
  if USE_DEFLATE
	cmp	compresslevel,0
	je	@F
	mov	STDI.ios_size,8000h
	invoke	zip_deflate,compresslevel
	ret
  endif
      @@:
	invoke	ocopy,zip_local.lz_fsize
	ret
compress endp

initcrc	proc
  if USE_DEFLATE
	sub	ax,ax
	mov	al,file_method
	mov	zip_local.lz_method,ax
	mov	zip_central.cz_method,ax
  endif
  ifdef __386__
	mov	eax,STDI.ios_bb
	not	eax
	mov	zip_local.lz_crc,eax
	mov	zip_central.cz_crc,eax
  else
	mov	ax,word ptr STDI.ios_bb
	not	ax
	mov	word ptr zip_local.lz_crc,ax
	mov	word ptr zip_central.cz_crc,ax
	mov	ax,word ptr STDI.ios_bb+2
	not	ax
	mov	word ptr zip_local.lz_crc+2,ax
	mov	word ptr zip_central.cz_crc+2,ax
  endif
	invoke	oclose,addr STDI
	ret
initcrc	endp

popstdi	proc
	mov	ax,OSTDI
	invoke	memcpy,ds::ax,ss::si,SIZE S_IOST
	sub	ax,ax
	ret
popstdi	endp

wzipopen proc dist pascal public uses si di
local	arch[384]:byte
	call	clearentry
	mov	si,offset entryname
	invoke	strcpy,ds::si,addr __outfile
	lea	ax,arch
	mov	di,ax
	call	mkarchivetmp
	invoke	strfn,ds::si
	invoke	strcpy,dx::ax,addr centtmp
	inv	wscopy_open,offset __outfile,di
	inc	ax		; (-1) -> (0)
	jz	wzipopen_end	; error
	dec	ax		; (1) --> (0)
	jnz	wzipopen_openc	; cancel
    wzipopen_end:
	test	ax,ax
	ret
    wzipopen_ioerror:
	invoke	close,centhnd
	invoke	remove,ds::si
    wzipopen_eropen:
	inv	wscopy_remove,di
	sub	ax,ax
	jmp	wzipopen_end
    wzipopen_openc:
	invoke	ogetouth,ds::si
	mov	centhnd,ax
	dec	ax
	jz	wzipopen_eropen
	lea	bx,arch
	lodm	arc_flength
	call	set_progress
	invoke	ocopy,zip_endcent.ze_off_cent
	jz	wzipopen_ioerror
	call	oflush
	jz	wzipopen_ioerror
    wzipopen_lzero:
	push	STDO.ios_file
	mov	ax,centhnd
	mov	STDO.ios_file,ax
	invoke	ocopy,zip_endcent.ze_size_cent
	jz	wzipopen_errcpy
	call	oflush
	jz	wzipopen_errcpy
	pop	ax
	mov	STDO.ios_file,ax
  ifdef __386__
	mov	eax,zip_endcent.ze_size_cent
	sub	STDO.ios_total,eax
  else
	lodm	zip_endcent.ze_size_cent
	sub	word ptr STDO.ios_total,ax
	sbb	word ptr STDO.ios_total+2,dx
  endif
    wzipopen_zero:
	mov	STDO.ios_flag,0
	invoke	oclose,addr STDI
	mov	ax,1
	jmp	wzipopen_end
    wzipopen_errcpy:
	pop	ax
	mov	STDO.ios_file,ax
	jmp	wzipopen_ioerror
wzipopen endp

wzipclose proc dist pascal public uses si di
local	arch[384]:byte
	mov	si,ax		; result
	lea	ax,arch
	mov	di,ax
	call	mkarchivetmp
	test	si,si
	jnz	wzipclose_remove
	mov	bx,centhnd
	mov	ax,4200h + SEEK_CUR
	xor	cx,cx
	mov	dx,cx
	int	21h
	jc	wzipclose_remove
	stom	zip_endcent.ze_size_cent
	lea	bx,arch
	call	set_progress
	invoke	close,centhnd
	mov	STDI.ios_size,8000h
	invoke	oopen,addr entryname, M_RDONLY
	inc	ax
	jz	wzipclose_remove
	invoke	ocopy,zip_endcent.ze_size_cent
	test	ax,ax
	jz	wzipclose_close
	push	ds
	pop	es
	mov	cx,SIZE S_ZEND
	mov	bx,offset zip_endcent
	call	owrite
	jz	wzipclose_close
	mov	si,zip_endcent.ze_comment_size
	test	si,si
	jnz	wzipclose_comment
    wzipclose_rename:
	call	oflush
	jz	wzipclose_close
	mov	si,offset __outfile
	call	zip_renametemp
	inc	ax
	jz	wzipclose_remove
    wzipclose_remcent:
	invoke	remove,addr entryname
    wzipclose_end:
	ret
    wzipclose_remove:
	invoke	close,centhnd
    wzipclose_remout:
	inv	wscopy_remove,di
	call	display_error
	jmp	wzipclose_remcent
    wzipclose_close:
	invoke	oclose,addr STDI
	jmp	wzipclose_remout
    wzipclose_comment:
	invoke	close,STDI.ios_file
	invoke	openfile,addr __outfile,M_RDONLY,A_OPEN
	mov	STDI.ios_file,ax
	mov	bx,ax
	inc	ax
	jz	wzipclose_close
	mov	ax,4200h + SEEK_END
	xor	cx,cx
	mov	dx,cx
	sub	dx,si
	sbb	cx,0
	int	21h
	jc	wzipclose_close
	sub	ax,ax
	mov	STDI.ios_c,ax
	mov	STDI.ios_i,ax
	invoke	ocopy, ax::si
	jz	wzipclose_close
	jmp	wzipclose_rename
wzipclose endp

wzipadd proc dist pascal public uses si di \
	fsize:dword, fdate:word, ftime:word, fattrib:word
local	ios:S_IOST
local	ztemp[384]:byte
local	zpath[384]:byte
local	copyl_ax:word
local	copyl_cx:word
local	copyl_dx:word
local	local_size:dword
local	deflate_begin:dword
	mov	di,fdate
	mov	si,fattrib
	xor	ax,ax
	mov	errno,ax
  if USE_DEFLATE
	mov	file_method,al
  endif
	cmp	copy_fast,0
	jne	@F
	jmp	wzipadd_slow
      @@:
	lea	ax,zpath
	mov	bx,ftime
  ifdef __386__
	mov	edx,fsize
  else
	mov	dx,word ptr fsize
	mov	cx,word ptr fsize+2
  endif
	call	initentry
  ifdef __386__
	xor	eax,eax
	mov	zip_local.lz_crc,eax
	mov	zip_central.cz_crc,eax
	mov	zip_central.cz_off_local,eax
  else
	sub	ax,ax
	mov	word ptr zip_local.lz_crc,ax
	mov	word ptr zip_local.lz_crc+2,ax
	mov	word ptr zip_central.cz_crc,ax
	mov	word ptr zip_central.cz_crc+2,ax
	mov	word ptr zip_central.cz_off_local,ax
	mov	word ptr zip_central.cz_off_local+2,ax
  endif
	test	si,_A_SUBDIR
	jnz	wzipfast_subdir
  if USE_DEFLATE
	dec	ax
	mov	STDI.ios_size,ax
  endif
	call	otell
	stom	zip_central.cz_off_local
	invoke	oopen,addr __srcfile,M_RDONLY
  if USE_DEFLATE
	mov	STDI.ios_size,ISIZE
  endif
	inc	ax
	jnz	@F
	;
	; v2.33 continue if error open source
	;
	jmp	wzipfast_end
    wzipfast_error:
	invoke	oclose,addr STDO
	invoke	close,centhnd
	invoke	remove,addr entryname
	mov	ax,-1
	jmp	wzipfast_end
    wzipfast_ercopy:
	invoke	oclose,addr STDI
	jmp	wzipfast_error
      @@:
	push	ds
	pop	es
	mov	bx,offset zip_local
	mov	cx,SIZE S_LZIP
	call	owrite
	jz	wzipfast_ercopy
	lea	bx,zpath
	mov	cx,zip_local.lz_fnsize
	call	owrite
	jz	wzipfast_ercopy
	mov	STDI.ios_flag,IO_USECRC or IO_USEUPD or IO_UPDTOTAL
	call	otell
	stom	deflate_begin
	call	compress
	test	ax,ax
	jz	wzipfast_ercopy
	call	initcrc
    wzipfast_subdir:
	call	otell
	stom	zip_endcent.ze_off_cent
	test	byte ptr fattrib,_A_SUBDIR
	jnz	@F
	sub	ax,word ptr deflate_begin
	sbb	dx,word ptr deflate_begin+2
	stom	zip_local.lz_csize
	stom	zip_central.cz_csize
	call	update_local
      @@:
	invoke	oswrite,centhnd,addr zip_central,SIZE S_CZIP
	cmp	ax,SIZE S_CZIP
	je	@F
	jmp	wzipfast_error
      @@:
	invoke	oswrite,centhnd,addr zpath,zip_central.cz_fnsize
	cmp	ax,zip_central.cz_fnsize
	je	@F
	jmp	wzipfast_error
      @@:
	inc	zip_endcent.ze_entry_cur
	inc	zip_endcent.ze_entry_dir
	sub	ax,ax
	jmp	wzipfast_end
    ;--------------------------------------------------------------
    wzipadd_slow:	; do slow copy
    ;--------------------------------------------------------------
	movmx	progress_size,arc_flength
	call	clearentry
	invoke	strcpy, addr zpath, addr __outpath
	mov	ax,offset __outpath
	mov	bx,ftime
  ifdef __386__
	mov	edx,fsize
  else
	mov	dx,word ptr fsize
	mov	cx,word ptr fsize+2
  endif
	call	initentry
	lea	ax,ztemp
	call	mkarchivetmp
	mov	dx,ax
	mov	ax,offset __outfile
	call	wscopy_open
	cmp	ax,-1
	jne	@F
	jmp	wzipfast_end
      @@:
	mov	STDO.ios_flag,IO_USEUPD or IO_UPDTOTAL
	test	ax,ax
	jnz	@F
	inc	ax
	jmp	wzipfast_end
      @@:
	xor	ax,ax
	mov	word ptr local_size,ax
	mov	word ptr local_size+2,ax
	invoke	zip_copylocal,1
	mov	copyl_ax,ax	; result: 1 found, 0 not found, -1 error
	mov	copyl_cx,cx	; [cx:dx] offset local directory if found
	mov	copyl_dx,dx
	mov	cx,ax
	inc	ax
	jz	wzipadd_error
;	test	si,_A_SUBDIR
;	jnz	@F
	call	otell
	stom	zip_central.cz_off_local
      @@:
	dec	cx
	jnz	@F
	mov	cx,word ptr zip_endcent.ze_off_cent+2
	mov	bx,word ptr zip_endcent.ze_off_cent
	sub	bx,ax
	sbb	cx,dx
	mov	word ptr local_size+2,cx
	mov	word ptr local_size,bx
;	test	si,_A_SUBDIR
;	jz	@F
;	jmp	wzipadd_skip
      @@:
	invoke	memcpy,addr ios,addr STDI,SIZE S_IOST
	test	si,_A_SUBDIR
	lea	si,ios
	jnz	@F;wzipslow_subdir
  if USE_DEFLATE
	mov	file_method,0
	mov	STDI.ios_size,-1
  endif
	invoke	oopen,addr __srcfile,M_RDONLY
  if USE_DEFLATE
	mov	STDI.ios_size,ISIZE
  endif
	cmp	ax,-1
	jne	@F
	call	popstdi
	;
	; v2.33 continue if error open source
	;
	jmp	wzipadd_skip
      @@:
	push	ds
	pop	es
	mov	bx,offset zip_local
	mov	cx,SIZE S_LZIP
	call	owrite
	jz	wzipadd_ersource
	mov	bx,offset __outpath
	mov	cx,zip_local.lz_fnsize
	call	owrite
	jz	wzipadd_ersource
	mov	STDI.ios_flag,IO_USECRC or IO_USEUPD or IO_UPDTOTAL
	and	STDO.ios_flag,not IO_USEUPD
	call	otell
	stom	deflate_begin
	invoke	progress_set,addr __srcfile,addr __outfile,fsize
	jnz	wzipadd_ersource
	test	byte ptr fattrib,_A_SUBDIR
	jnz	wzipslow_subdir
	call	compress
	test	ax,ax
	jnz	wzipadd_zerofile
   wzipadd_ersource:
	invoke	oclose,addr STDI
	call	popstdi
	jmp	wzipadd_error
   wzipadd_zerofile:
	call	initcrc
	call	popstdi
	lea	bx,ztemp
	lodm	arc_flength
	call	set_progress
    wzipslow_subdir:
	call	otell
	stom	zip_endcent.ze_off_cent
;	test	byte ptr fattrib,_A_SUBDIR
;	jnz	@F
	sub	ax,word ptr deflate_begin
	sbb	dx,word ptr deflate_begin+2
	stom	zip_local.lz_csize
	stom	zip_central.cz_csize
	add	word ptr progress_size,ax
	adc	word ptr progress_size+2,dx
	call	update_local
      @@:
	mov	dx,copyl_dx
	mov	ax,copyl_cx
	invoke	zip_copycentral,dx::ax,local_size,1
	inc	ax
	jz	wzipadd_ioerror
	dec	ax			; if file or directory deleted
	jz	@F			; -- ask user to overwrite
	dec	zip_endcent.ze_entry_dir
	dec	zip_endcent.ze_entry_cur
	invoke	confirm_delete_file,addr __outpath,zip_central.cz_ext_attrib
	inc	ax
	jz	wzipadd_ioerror		; Cancel (-1)
	dec	ax
	jz	wzipadd_skip		; Jump (0)
	jmp	wzipslow_czip
      @@:
	cmp	copyl_ax,ax
	je	wzipslow_czip
	jmp	wzipadd_ioerror	; found local, not central == error
    wzipslow_czip:
	push	ds
	pop	es
	mov	bx,offset zip_central
	mov	cx,SIZE S_CZIP
	call	owrite
	jz	wzipadd_ioerror
	mov	bx,offset __outpath
	mov	cx,zip_central.cz_fnsize
	call	owrite
	jz	wzipadd_ioerror
	inc	zip_endcent.ze_entry_cur
	inc	zip_endcent.ze_entry_dir
	mov	ax,offset __outfile
	lea	dx,ztemp
	call	zip_copyendcentral
	inc	ax
	jz	wzipadd_ioerror
	jmp	wzipadd_ok
    wzipfast_end:
	test	ax,ax
	ret
    wzipadd_skip:
	invoke	oclose,addr STDI
	lea	ax,ztemp
	call	wscopy_remove
    wzipadd_ok:
	invoke	strcpy,addr __outpath,addr zpath
	sub	ax,ax
	jmp	wzipfast_end
    wzipadd_ioerror:
	sub	ax,ax
    wzipadd_error:
	mov	di,ax
	invoke	oclose,addr STDI
	lea	ax,ztemp
	call	wscopy_remove
	mov	ax,di
	inc	di
	jz	wzipfast_end
	call	display_error
	dec	ax
	jmp	wzipfast_end
wzipadd endp

_TEXT	ENDS
endif
	END
