; DZ7ZA.ASM--
; Copyright (c) 2011 Hjort Nidudsson
;
; Change history:
; 07/26/2012 - added support for single files (.bz2)
; 23.01.2012 - added "quotes" to <archive> name
; 12/28/2011 - added 'modified' to the read function
;

	.model	tiny
	.code
	.286

DLLVER	equ	0104h		; version 0.1.0.4
VERS?	equ     <'1.04'>
PROC?	equ	100101111B	; functions included
FLAG?	equ	100101111B	; functions that need 7ZA.EXE (all)
NAME?	equ	<'7za'>		; filename extensions
TYPE?	equ	<'.7z .bz2 .gz .xz .cab .tar .lzma'>

;DEBUG	= 1
include	inc/dll.inc

DLL_Header	PROC?, FLAG?, DLLVER
DLL_Startup	PROC?, FLAG?

include	inc/io.inc
include	inc/iost.inc
include	inc/string.inc
include	inc/stdlib.inc
include	inc/wsub.inc
include	inc/assert.inc

	.data

c_entry	db	NAME?,0
$PROG	db	NAME?,".EXE",0
$LIST	db	WMAXPATH dup(?)

; default value

ARG_01	db	'7za l -y',0	; 01 - Read
ARG_02	db	'7za x -y',0	; 02 - Copy - e if not include subdir
ARG_03	db	'7za a -y',0	; 03 - Add
ARG_04	db	'7za m -y',0	; 04 - Move
ARG_06	db	'7za d -y',0	; 06 - Delete
ARG_08	db	'7za m -e -y',0	; 08 - Edit
ARG_09	db	'7za e -y',0	; 09 - View or copy single file (02)

; format strings

CPF_02	db	' %s -o%s',0	; <archive> -o<outpath> @list
CPF_03	db	' %s',0     	; <archive> @list
CPTEMP	db	' @%%TEMP%%\ziplst',0

; from [7ZA] config value, or default value

CMD_00	db 	64 dup(?)	; ARG_09 - if files only (02)
CMD_01	db 	64 dup(?)
CMD_02	db 	64 dup(?)
CMD_03	db 	64 dup(?)
CMD_04	db 	64 dup(?)
CMD_06	db 	64 dup(?)
CMD_08	db 	64 dup(?)
CMD_09	db	64 dup(?)

config_label label word
	dw	offset ARG_09, offset CMD_00
	dw	offset ARG_01, offset CMD_01
	dw	offset ARG_02, offset CMD_02
	dw	offset ARG_03, offset CMD_03
	dw	offset ARG_04, offset CMD_04
	dw	0,0
	dw	offset ARG_06, offset CMD_06
	dw	0,0
	dw	offset ARG_08, offset CMD_08
	dw	offset ARG_09, offset CMD_09

; file types

NUMTYPE	equ	7

label_id label word
	db	'7z',0,0	; .7Z
	dd	00008B1Fh	; .GZ, .GZIP
	db	'BZ',0,0	; .BZ2
	db	'MSCF'		; .CAB
	dd	587A37FDh	; .XZ
	dd	10000000h	; .TAR
	dd	20000000h	; .LZMA

typ0	db	0
typ1	db	' -tgzip',0
typ2	db	' -tbzip2',0
typ3	db	' -tcab',0
typ4	db	' -txz',0
typ5	db	' -ttar',0
typ6	db	' -tlzma',0

label_types label word
	dw	offset typ0
	dw	offset typ1
	dw	offset typ2
	dw	offset typ3
	dw	offset typ4
	dw	offset typ5
	dw	offset typ6
$TYPE	dw	offset label_types	; current type string

label_flag label word
	dw	100101111B
	dw	100000011B
	dw	100000011B
	dw	100000011B
	dw	100000011B
	dw	100101111B
	dw	100000011B


	.code
	.386

;-------------------------------------------------------------------------
include	inc/iost.asm
include	inc/stdlib.asm
include	inc/wsub.asm
include	inc/string.asm
include	inc/dll.asm
include	inc/stdio.asm
include	inc/dos.asm
include	inc/dir.asm
include	inc/mouse.asm

;-------------------------------------------------------------------------
; Function 00 - Load
;-------------------------------------------------------------------------

dll_init:
	invoke	strfcat, addr cs:$LIST, envtemp, addr CString("ziplst.tmp")

	; All functions use 7ZA.EXE so init fail if not found

	invoke	searchp, addr cs:$PROG
	test	ax,ax
	jnz	@F
	invoke	ermsg, CStr(NAME?), CStr("File not found: 7ZA.EXE")
	mov	al,ER_EXEC
	jmp	DLL_NOTSUP
      @@:
	;
	; Signature for this archive is in SI:DI
	;
	mov	dx,si
	mov	ax,di
	mov	bx,offset label_id
	mov	cx,NUMTYPE
    dll_init_loop:
	cmp	ax,cs:[bx]
	jne	dll_init_next
	mov	ax,cs:[bx+2]
	test	al,al
	jz	@F
	cmp	al,dl
	jne	dll_init_next
      @@:
	test	ah,ah
	jz	@F
	cmp	ah,dh
	jne	dll_init_next
      @@:
	sub	bx,offset label_id
	shr	bx,1
	mov	ax,cs:[bx+label_flag]
	mov	cs:$FLAG,ax
	mov	ax,cs:[bx+label_types]
	mov	cs:$TYPE,ax
	call	init_args
	xor	ax,ax
	iret
    dll_init_next:
	mov	ax,di
	add	bx,4
	dec	cx
	jnz     dll_init_loop
    dll_init_fail:
	push	si
	push	di
	invoke	ermsg, CStr(NAME?), CStr("Filetype not supported: 0x%08lX")
	add	sp,4
	mov	al,ER_FIND
	jmp	DLL_NOTSUP

init_args:
	mov	cx,_DLL_READ
	call	init_args_find
	invoke	strcat, dx::ax, addr CString(<" ">)
	mov	cx,0
	call	init_args_find
	invoke	strcat, dx::ax, addr cs:CPF_02
	invoke	strcat, dx::ax, addr cs:CPTEMP
	mov	cx,_DLL_COPY
	call	init_args_find
	invoke	strcat, dx::ax, addr cs:CPF_02
	invoke	strcat, dx::ax, addr cs:CPTEMP
	mov	cx,_DLL_ADD
	call	init_args_find
	invoke	strcat, dx::ax, addr cs:CPF_03
	invoke	strcat, dx::ax, addr cs:CPTEMP
	mov	cx,_DLL_MOVE
	call	init_args_find
	invoke	strcat, dx::ax, addr cs:CPF_03
	invoke	strcat, dx::ax, addr cs:CPTEMP
	mov	cx,_DLL_DELETE
	call	init_args_find
	invoke	strcat, dx::ax, addr cs:CPF_03
	invoke	strcat, dx::ax, addr cs:CPTEMP
	mov	cx,_DLL_EDIT
	call	init_args_find
	invoke	strcat, dx::ax, addr CString(<" %s %s">)
	mov	cx,_DLL_VIEW
	call	init_args_find
	invoke	strcat, dx::ax, addr CString(<" %s -o%s %s">)
	ret
    init_args_find:
	push	si
	push	di
	mov	si,cx
	shl	si,2
	mov	di,cs:[si+config_label]
	mov	si,cs:[si+config_label+2]
	mov	dx,cs
	mov	bx,offset c_entry
	mov	ah,_DZ_inientryid
	int	DZ
	or	ax,ax
	jnz	init_args_found
	mov	dx,cs
	mov	ax,di
    init_args_found:
	invoke	strcpy, cs::si, dx::ax
	mov	bx,cs:$TYPE
	invoke	strcat, dx::ax, dx::bx
	pop	di
	pop	si
	ret

;-------------------------------------------------------------------------
; Function 01 - Read
;-------------------------------------------------------------------------

modified	db 1
startstring	db '------------------- '

lline_getline:
	mov	ax,si
	mov	dx,di
	mov	cx,511
	call	ogets
	ret

lline_getdate:	; 2008-04-28
	invoke	atol, addr entryname
	push	ax
	invoke	atol, addr entryname + 5
	push	ax
	invoke	atol, addr entryname + 8
	mov	dl,al
	pop	ax
	mov	dh,al
	pop	ax
	sub	ax,DT_BASEYEAR
	shl	ax,9
	xchg	ax,dx
	mov	cl,al
	mov	al,ah
	xor	ah,ah
	shl	ax,5
	xchg	ax,dx
	or	ax,dx
	or	al,cl
	ret

lline_gettime:	; 02:19:00
	invoke	atol, addr entryname + 11
	push	ax
	invoke	atol, addr entryname + 14
	push	ax
	invoke	atol, addr entryname + 17
	pop	cx
	pop	bx
	mov	ch,bl
	mov	dh,al
	xor	ax,ax	; DH = second
	mov	al,dh   ; CH = hour
	shr	ax,1    ; CL = minute
	mov	dx,ax
	mov	al,ch
	mov	ch,ah
	shl	cx,5
	shl	ax,11
	or	ax,cx
	or	ax,dx	; hhhhhmmmmmmsssss
	ret

lline_getattrib:
	xor	ax,ax
	cmp	entryname[20],'D'
	jne	@F
	mov	al,_A_SUBDIR
      @@:
    	cmp	entryname[21],'R'
	jne	@F
	or	al,_A_RDONLY
      @@:
    	cmp	entryname[22],'H'
	jne	@F
	or	al,_A_HIDDEN
      @@:
    	cmp	entryname[23],'S'
	jne	@F
	or	al,_A_SYSTEM
      @@:
    	cmp	entryname[24],'A'
	jne	@F
	or	al,_A_ARCH
      @@:
    	ret

lline_findfirst:
	call	lline_getline
	jz	@B
	cmp	entryname,'-'
	jne	lline_findfirst
	invoke	strncmp, ss::di, addr cs:startstring,
		offset lline_getline - offset startstring
	test	ax,ax
	jnz	lline_findfirst
;
;   Date      Time    Attr         Size   Compressed  Name
;------------------- ----- ------------ ------------  ------------------------
;		    .....       	     790027  7z922.tar
;------------------- ----- ------------ ------------  ------------------------
;					     790027  1 files, 0 folders
;
lline_findnext:
	call	lline_getline
	jz	lline_findnext_fail
	mov	al,entryname	; 2008-04-28
	cmp	al,' '
	jne	@F
	invoke	strlen, addr entryname
	cmp	ax,52
	jb	lline_findnext_fail
	jmp	lline_findnext_set
      @@:
	cmp	al,'0'
	jb	lline_findnext_fail
	cmp	al,'9'
	ja	lline_findnext_fail
	cmp	entryname[4],'-'
	jne	lline_findnext_fail
    lline_findnext_set:
	xor	ax,ax
	mov	entryname[4],al
	mov	entryname[7],al
	mov	entryname[10],al
	mov	entryname[13],al
	mov	entryname[16],al
	mov	entryname[19],al
	mov	entryname[38],al
	mov	entryname[51],al
	mov	al,entryname[52]
	or	al,al
	ret
    lline_findnext_fail:
	xor	ax,ax
	ret

dll_read proc pascal, wsub:dword
local	ios:S_IOST
local	fblk:dword
local	fattrib:word
local	ename:dword
local	arch[WMAXPATH]:byte
local	command[WMAXPATH]:byte
	push	si
	push	di
	invoke	wsfree, wsub
	mov	si,word ptr wsub
	invoke	fbupdir, _W_ARCHEXT
	jz	dll_read_fail
	mov	[si].ws_count,1
	les	bx,[si].ws_fcb
	stom	es:[bx]
	cmp	modified,0
	jne	@F
	invoke	osopen, addr cs:$LIST, 0, M_RDONLY, A_OPEN
	cmp	ax,-1
	jne	dll_read_handle
      @@:
    	mov	arch,'"'
	invoke	strfcat, addr arch+1, [si].ws_path, [si].ws_file
	invoke	strcat, dx::ax, addr CString('"')
	invoke	strcpy, addr command, addr cs:CMD_01
	invoke	strcat, dx::ax, addr arch
	invoke	dzexec, dx::ax, SPAWN_STDOUT
    dll_read_handle:
	test	ax,ax
	jz	dll_read_fail
	mov	ios.ios_file,ax
	xor	ax,ax
	mov	ios.ios_i,ax
	mov	ios.ios_c,ax
	mov	ios.ios_flag,ax
	mov	ios.ios_bp,DZ_bufin
	mov	ios.ios_size,4096
	lea	si,ios
	mov	di,DZ_entryname
	mov	ax,di
	add	ax,53
	mov	word ptr ename,ax
	mov	word ptr ename+2,ss
    dll_read_getstart:
	call	lline_findfirst
	jnz	dll_read_do
	jmp	dll_read_close
    dll_read_next:
	call	lline_findnext
	jz	dll_read_close
    dll_read_do:
	invoke	testentryname, wsub, ename
	jz	dll_read_next
	mov	fattrib,ax
	test	al,_A_SUBDIR
	jnz	dll_read_alloc
	mov	bx,word ptr wsub	; test panel's read mask (*.*)
	invoke	cmpwarg, ename, [bx].ws_mask
	jz	dll_read_next
    dll_read_alloc:
	invoke	strlen, ename
	add	ax,SIZE S_FBLK
	invoke	malloc, ax
	mov	cx,fattrib
	jz	dll_read_close
	stom	fblk
	les	bx,fblk
	or	cx,_A_ARCHEXT
	mov	es:[bx].fb_flag,cx
	add	ax,fb_name
	invoke	strcpy, dx::ax, ename
	invoke	atol, addr entryname + 26
	les	bx,fblk
	stom	es:[bx].fb_size
	call	lline_getdate
	les	bx,fblk
	mov	es:[bx].fb_date,ax
	call	lline_gettime
	les	bx,fblk
	mov	es:[bx].fb_time,ax
	call	lline_getattrib
	les	bx,fblk
	or	es:[bx],al
	mov	bx,word ptr wsub
	mov	ax,[bx].ws_count
	shl	ax,2
	les	bx,[bx].ws_fcb
	add	bx,ax
	movm	es:[bx],fblk
	mov	bx,word ptr wsub
	inc	[bx].ws_count
	mov	ax,[bx].ws_count
	cmp	ax,[bx].ws_maxfb
	jae	dll_read_close
	jmp	dll_read_next
    dll_read_close:
	invoke	close, ios.ios_file
	mov	modified,0
	mov	bx,word ptr wsub
	mov	ax,[bx].ws_count
    dll_read_end:
	pop	di
	pop	si
	ret
    dll_read_fail:
	mov	ax,ER_READARCH
	jmp	dll_read_end
dll_read endp

;-------------------------------------------------------------------------
; Function 02 - Copy
;-------------------------------------------------------------------------

dll_mklist:	; create list
	mov	al,1	; unix path
	mov	dl,0	; no mask in directory\[*.*]
	invoke	dzmklist, CStr(<'7ZA: Create list file'>)
	;
	; return AX result, BX directory count, DX:CX total
	;
	ret

dll_copy proc pascal, wsub:dword, fblk:dword, outp:dword
local	command[WMAXPATH]:byte
local	path[WMAXPATH]:byte
	push	si
	push	di
	lea	si,command
	mov	di,offset CMD_02
	invoke	strcpy, addr path, outp
	invoke	strlen, dx::ax	; remove '\' from end of outpath (C:\)
	mov	bx,word ptr outp
	add	bx,ax
	dec	bx
	mov	ax,'\'
	cmp	es:[bx],al
	jne	@F
	mov	es:[bx],ah
    @@:	call	dll_mklist	; make a list file
	jnz	dll_copy_end
	or	bx,bx
	jnz	@F
	mov	di,offset CMD_00
    @@:	invoke	wsclrsel, wsub	; clear selection set from panel
	push	ss
	lea	ax,path
	push	ax
	mov	bx,word ptr wsub
	pushm	[bx.ws_file]
	invoke	ssprintf, si, di
	add	sp,8
	invoke	dzexec, addr command, SPAWN_EXIT
	xor	ax,ax
    dll_copy_end:
	pop	di
	pop	si
	ret
dll_copy endp

;-------------------------------------------------------------------------
;Function 03 - Add
;
; - add files to <archive>\ root directory only
;-------------------------------------------------------------------------

IDD_ADDMSG label word
incbin <inc/addmsg.idd>

display_addmsg:
	xor	ax,ax
	mov	bx,word ptr [di.ws_arch]
	cmp	[bx],al
	je	display_addmsg_end
	invoke	rsmodal, addr cs:IDD_ADDMSG ; OK == 1, else 0
	dec	ax
	jz	display_addmsg_end
	mov	ax,ER_USERABORT
    display_addmsg_end:
	ret

make_ziplst_add:
	call	display_addmsg
	jnz	make_ziplst_end
make_ziplst:
	call	dll_mklist
	jnz	make_ziplst_end
	invoke	wsclrsel, ss::si
	xor	ax,ax
    make_ziplst_end:
	ret

dll_add proc pascal, dest:dword, wsub:dword, fblk:dword
local	command[256]:byte
local	path[WMAXPATH]:byte
	push	si
	push	di
	mov	di,word ptr dest
	mov	si,word ptr wsub
	call	make_ziplst_add
	jnz	dll_add_end
	invoke	strfcat, addr path, [di.ws_path], [di.ws_file]
	push	dx
	push	ax
	lea	ax,command
	invoke	ssprintf, ax, offset CMD_03
	add	sp,4
	invoke	dzexec, addr command, SPAWN_EXIT
	inc	modified
	xor	ax,ax
    dll_add_end:
	pop	di
	pop	si
	ret
dll_add endp

;-------------------------------------------------------------------------
; Function 04 - Move
;
; - move files to <archive>\ root directory only
;-------------------------------------------------------------------------

dll_move proc pascal, dest:dword, wsub:dword, fblk:dword
local	command[256]:byte
local	path[WMAXPATH]:byte
	push	si
	push	di
	mov	di,word ptr dest
	mov	si,word ptr wsub
	call	make_ziplst_add
	jnz	dll_move_end
	invoke	strfcat, addr path, [di.ws_path], [di.ws_file]
	push	dx
	push	ax
	lea	ax,command
	invoke	ssprintf, ax, offset CMD_04
	add	sp,4
	invoke	dzexec, addr command, SPAWN_EXIT
	inc	modified
	xor	ax,ax
    dll_move_end:
	pop	di
	pop	si
	ret
dll_move endp

;-------------------------------------------------------------------------
; Function 06 - Delete
;-------------------------------------------------------------------------

dll_delete proc pascal, wsub:dword, fblk:dword
local	command[256]:byte
	push	si
	mov	si,word ptr wsub
	call	make_ziplst
	jnz	dll_delete_end
	pushm	[si.ws_file]
	lea	ax,command
	invoke	ssprintf, ax, offset CMD_06
	add	sp,4
	invoke	dzexec, addr command, SPAWN_EXIT
	inc	modified
	xor	ax,ax
    dll_delete_end:
	pop	si
	ret
dll_delete endp

;-------------------------------------------------------------------------
; Function 09 - View
;-------------------------------------------------------------------------

dll_view proc pascal, wsub:dword, fblk:dword
local	fbname[WMAXPATH]:byte
local	command[WMAXPATH]:byte
	push	si
	push	di
	mov	si,word ptr wsub
	lea	di,command
	add     word ptr fblk,fb_name
	invoke	strfcat, addr fbname, [si.ws_arch], fblk
	push	dx
	push	ax
	pushm	envtemp
	pushm	[si.ws_file]
	invoke	ssprintf, di, offset CMD_09
	add	sp,12
	invoke	dzexec, ss::di, SPAWN_NUL
	pushm	fblk
	pushm	envtemp
	invoke	ssprintf, di, CStr(<"%s\%s">)
	add	sp,8
	invoke	filexist, ss::di
	dec	ax
	jnz	dll_view_end
	invoke	dzview, ss::di, ax::ax
	invoke	remove, ss::di
    dll_view_end:
	pop	di
	pop	si
	ret
dll_view endp

;-------------------------------------------------------------------------
; Function 11 - Exit
;-------------------------------------------------------------------------

dll_exit:
  ifndef DEBUG
	invoke remove, addr cs:$LIST
  endif
	xor ax,ax
	iret

	END	start
