;*---------------------------------------------------------------------------
;  :Program.	wpatch.asm
;  :Contents.	apply wdelta file
;  :Author.	Bert Jahn
;  :EMail.	wepl@kagi.com
;  :Address.	Franz-Liszt-Straße 16, Rudolstadt, 07404, Germany
;  :Version.	$Id: wpatch.asm 1.0 1999/07/06 21:58:56 jah Exp jah $
;  :History.	06.07.99 separated from wdelta
;  :Requires.	OS V37+
;  :Copyright.
;		WPatch is Copyright © 1999 Bert Jahn <wepl@kagi.com>
;
;		This program is free software; you can redistribute it and/or
;		modify it under the terms of the GNU General Public License as
;		published by the Free Software Foundation; either version 2 of
;		the License, or (at your option) any later version.
;
;		This program is distributed in the hope that it will be
;		useful, but WITHOUT ANY WARRANTY; without even the implied
;		warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
;		PURPOSE. See the GNU General Public License for more details.
;
;		You can find the full GNU GPL online at: http://www.gnu.org/
;
;  :Language.	68000/68020 Assembler
;  :Translator.	Barfly V2.9
;---------------------------------------------------------------------------*
;##########################################################################

	INCDIR	Includes:
	INCLUDE	lvo/exec.i
	INCLUDE	exec/execbase.i
	INCLUDE	lvo/dos.i

	INCLUDE	wdelta.i
	INCLUDE	macros/ntypes.i

;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

GL	EQUR	A4		;a4 ptr to Globals
LOC	EQUR	A5		;a5 for local vars

 ENUM 0
 EITEM WDLT_OK
 EITEM WDLT_NOWDELTA
 EITEM WDLT_HEADCHKSUM
 EITEM WDLT_INCHKSUM
 EITEM WDLT_OUTCHKSUM
 EITEM WDLT_WDLTCHKSUM
 EITEM WDLT_ERROR

	STRUCTURE	ReadArgsArray,0
		ULONG	rda_inname
		ULONG	rda_outname
		ULONG	rda_wdname
		LABEL	rda_SIZEOF

	NSTRUCTURE	Globals,0
		NAPTR	gl_execbase
		NAPTR	gl_dosbase
		NAPTR	gl_rdargs
		NSTRUCT	gl_rdarray,rda_SIZEOF
		NLONG	gl_insize
		NLONG	gl_inptr
		NLONG	gl_outsize
		NLONG	gl_outptr
		NLONG	gl_wdsize
		NLONG	gl_wdptr
		NALIGNLONG
		NLABEL	gl_SIZEOF

;##########################################################################

	PURE
	SECTION	"",CODE
	OUTPUT	C:WPatch

VER	MACRO
		dc.b	"WPatch 1.0 "
	DOSCMD	"WDate >t:date"
	INCBIN	"t:date"
		dc.b	" by Bert Jahn <wepl@kagi.com>"
	ENDM

		bra	.start
		dc.b	"$VER: "
		VER
		dc.b	" V37+"
	CNOP 0,2
.start

;##########################################################################

		link	GL,#gl_SIZEOF		;GL = globals
		move.l	(4),(gl_execbase,GL)

		move.l	#37,d0
		lea	(_dosname),a1
		move.l	(gl_execbase,GL),a6
		jsr	(_LVOOpenLibrary,a6)
		move.l	d0,(gl_dosbase,GL)
		beq	.nodoslib

		lea	(_ver),a0
		bsr	_Print

		lea	(_template),a0
		move.l	a0,d1
		lea	(gl_rdarray,GL),a0
		move.l	a0,d2
		moveq	#0,d3
		move.l	(gl_dosbase,GL),a6
		jsr	(_LVOReadArgs,a6)
		move.l	d0,(gl_rdargs,GL)
		bne	.argsok
		lea	(_readargs),a0
		bsr	_PrintErrorDOS
		bra	.noargs
.argsok
		bsr	_apply
		move.l	d0,d7

		move.l	(gl_rdargs,GL),d1
		move.l	(gl_dosbase,GL),a6
		jsr	(_LVOFreeArgs,a6)
.noargs
		move.l	(gl_dosbase,GL),a1
		move.l	(gl_execbase,GL),a6
		jsr	(_LVOCloseLibrary,a6)
.nodoslib
		unlk	GL
		move.l	d7,d0
		rts

;##########################################################################

_apply		moveq	#20,d7			;rc

		move.l	(gl_rdarray+rda_wdname,GL),a0
		bsr	_LoadFile
		move.l	d0,(gl_wdptr,GL)
		beq	.nowd

		move.l	d1,d0			;size
		move.l	(gl_wdptr,GL),a0
		bsr	_wdelta_chk
		move.l	d0,(gl_outsize,GL)
		bpl	.wdok
		neg.l	d0
		move.l	d0,d7			;rc
		bsr	.error
		bra	.badwd
.wdok
		move.l	#MEMF_ANY,d1
		move.l	(gl_execbase,GL),a6
		jsr	(_LVOAllocVec,a6)
		move.l	d0,(gl_outptr,GL)
		beq	.noout

		move.l	(gl_rdarray+rda_inname,GL),a0
		bsr	_LoadFile
		move.l	d0,(gl_inptr,GL)
		beq	.noin

		move.l	d1,d0			;size
		move.l	(gl_inptr,GL),a0
		move.l	(gl_outptr,GL),a1
		move.l	(gl_wdptr,GL),a2
		bsr	_wdelta
		move.l	d0,d7			;rc
		beq	.ok
		bsr	.error
		bra	.err
.ok
		move.l	(gl_outsize,GL),d0
		move.l	(gl_outptr,GL),a0
		move.l	(gl_rdarray+rda_outname,GL),a1
		bsr	_SaveFile
		tst.l	d0
		bne	.err
		moveq	#20,d7			;rc
.err
		move.l	(gl_inptr,GL),a1
		move.l	(gl_execbase,GL),a6
		jsr	(_LVOFreeVec,a6)
.noin
		move.l	(gl_outptr,GL),a1
		move.l	(gl_execbase,GL),a6
		jsr	(_LVOFreeVec,a6)
.noout
.badwd
		move.l	(gl_wdptr,GL),a1
		move.l	(gl_execbase,GL),a6
		jsr	(_LVOFreeVec,a6)
.nowd
		move.l	d7,d0			;rc
		rts

.error		lea	(_wdlt_error),a0
		lsl.l	#2,d0
		move.l	(a0,d0.l),a0
		bsr	_Print
		bra	_PrintLn

;----------------------------------------
; check wdelta data and return output size
; IN:	d0 = size of wdelta data
;	a0 = wdelta data
; OUT:	d0 = output size or negative WDLT_* error

_wdelta_chk	movem.l	d1/a0-a1/a5,-(a7)

		move.l	a0,a5			;A5 = wdelta

		moveq	#-WDLT_NOWDELTA,d0	;no wdelta file
		cmp.l	#"WDLT",(a0)+
		bne	.end
		move.l	#wdlt_crchd-4,d0
		bsr	_CRC16
		move.w	d0,d1
		moveq	#-WDLT_HEADCHKSUM,d0	;header chksum
		cmp.w	(wdlt_crchd,a5),d1
		bne	.end

		move.l	(wdlt_lenwd,a5),d0
		lea	(wdlt_wdelta,a5),a0
		bsr	_CRC16
		move.w	d0,d1
		moveq	#-WDLT_WDLTCHKSUM,d0	;wdelta chksum
		cmp.w	(wdlt_crcwd,a5),d1
		bne	.end

		move.l	(wdlt_lenout,a5),d0

.end		movem.l	(a7)+,_MOVEMREGS
		rts

;----------------------------------------
; create output by applying wdelta to input
; IN:	d0 = input size
;	a0 = input data
;	a1 = output data
;	a2 = wdelta data
; OUT:	d0 = WDLT_* error

_wdelta		movem.l	d1/a0-a5,-(a7)

		move.l	a0,a3			;A3 = input
		move.l	a1,a4			;A4 = output
		move.l	a2,a5			;A5 = wdelta

		move.l	d0,d1
		moveq	#WDLT_INCHKSUM,d0	;input chksum
		cmp.l	(wdlt_lenin,a5),d1
		bne	.end

		move.l	d1,d0
		move.l	a3,a0
		bsr	_CRC16
		move.w	d0,d1
		moveq	#WDLT_INCHKSUM,d0	;input chksum
		cmp.w	(wdlt_crcin,a5),d1
		bne	.end

		move.l	a3,a0
		move.l	a4,a1
		lea	(wdlt_wdelta,a5),a2
		move.l	(wdlt_lenout,a5),a3
		add.l	a4,a3

.loop		cmp.l	a1,a3
		bls	.done
		move.b	(a2)+,d1
		move.b	d1,d0
		and.w	#$1f,d1
		tst.b	d0
		bpl	.4bit
.12bit		lsl.w	#8,d1
		move.b	(a2)+,d1
		add.w	#32,d1
.4bit
	;d0=cmd d1=length-1
		and.b	#$60,d0
		beq	.equ
		cmp.b	#$40,d0
		blo	.chg
		beq	.add

.del		lea	(1,a0,d1.w),a0
		bra	.loop

.chg		lea	(1,a0,d1.w),a0
.add		lea	(a1,d1.w),a6
		cmp.l	a6,a3
		bls	.done
.alp		move.b	(a2)+,(a1)+
		dbf	d1,.alp
		bra	.loop

.equ		lea	(a1,d1.w),a6
		cmp.l	a6,a3
		bls	.done
.elp		move.b	(a0)+,(a1)+
		dbf	d1,.elp
		bra	.loop

.done		moveq	#WDLT_ERROR,d0
		cmp.l	a3,a1
		blo	.end
		beq	.done1
		illegal
.done1		sub.l	(wdlt_lenwd,a5),a2
		sub.l	#wdlt_wdelta,a2
		cmp.l	a5,a2
		bne	.end

		move.l	(wdlt_lenout,a5),d0
		move.l	a4,a0
		bsr	_CRC16
		move.w	d0,d1
		moveq	#WDLT_OUTCHKSUM,d0	;output chksum
		cmp.w	(wdlt_crcout,a5),d1
		bne	.end

		moveq	#WDLT_OK,d0

.end		movem.l	(a7)+,_MOVEMREGS
		rts

;##########################################################################

	INCLUDE	crc16.s

	INCDIR	Sources:
	INCLUDE	dosio.i
		Print
		PrintLn
	INCLUDE	error.i
		PrintErrorDOS
	INCLUDE	files.i
		LoadFile
		SaveFile

;##########################################################################

_wdlt_error	dc.l	0
		dc.l	_wdlt_1
		dc.l	_wdlt_2
		dc.l	_wdlt_3
		dc.l	_wdlt_4
		dc.l	_wdlt_5
		dc.l	_wdlt_6
_wdlt_1		dc.b	"not a wdelta file",0
_wdlt_2		dc.b	"checksum error in wdelta file header",0
_wdlt_3		dc.b	"wrong input file",0
_wdlt_4		dc.b	"checksum error in output file",0
_wdlt_5		dc.b	"checksum error in wdelta file",0
_wdlt_6		dc.b	"internal error",0

_nomem		dc.b	"not enough free memory",10,0
_readargs	dc.b	"read arguments",0
_dosname	dc.b	"dos.library",0
_template	dc.b	"InFile/A"		;file to apply patch
		dc.b	",OutFile/A"		;resulting file
		dc.b	",WDeltaFile/A"		;wdelta file
		dc.b	0

_ver		VER
		dc.b	10,0

;##########################################################################

	END
