;_ args ":t/xx" :t/yy ram:z
; Patch File Generator
; (c) 1993 MJSoft System Software
; Martin Mares

;debug	set	1
;	opt	x+

threshold	equ	7	; Critical size of compared block
	ifnd	LARGE
firstmax	equ	512	; Parameters of first pass
firstdepth	equ	2048
	elseif
firstmax	equ	2048	; Parameters of LARGE mode
firstdepth	equ	8192
	endc

	include	"macros.h"

	arg	arg_from,<FROM/A>
	arg	arg_to,<TO/A>
	arg	arg_topatch,<PTAB/A>
	arg	arg_change,<CHANGE/S>
	ifnd	LARGE
	extrahelp	<Patch File Generator 1.1         (c) 1993 MJSoft System Software, Martin Mares>
	elseif
	extrahelp	<Patch File Generator 1.1L        (c) 1993 MJSoft System Software, Martin Mares>
	endc

	start

	get.l	arg_from,a2
	bsr	loadfile
	put.l	d0,fromfile
	put.l	d1,fromlen
	dv.l	fromfile
	dv.l	fromlen

	get.l	arg_to,a2
	bsr	loadfile
	put.l	d0,tofile
	put.l	d1,tolen
	dv.l	tofile
	dv.l	tolen

	move.l	d1,d0
	add.l	#1024,d0
	call	ArpAlloc
	put.l	d0,patchto
	dv.l	patchto

	move.l	d0,a6	; A6 points to patch table

	get.l	fromlen,d5	; D5 points to 1st byte after src file
	get.l	tolen,d6	; D6 ... dest file
	move.l	#'MJPa',(a6)+
	move.l	#'tch'*256+1,(a6)+
	move.l	d5,(a6)+
	move.l	d6,(a6)+
	get.l	fromfile,a2	; A2 points to source file contents
	get.l	tofile,a3	; A3 points to dest. file contents
	move.l	a2,a0
	move.l	d5,d0
	moveq	#0,d1
	moveq	#0,d2
chs1	move.b	(a0)+,d2
	add.l	d2,d1
	ror.l	#1,d1
	subq.l	#1,d0
	bne.s	chs1
	move.l	d1,(a6)+

	add.l	a2,d5
	add.l	a3,d6
	tsv.l	arg_change
	beq.s	compare
	move.l	a2,a0
	move.l	a3,a1
change1	cmp.l	d6,a1
	bcc.s	change0
	cmp.l	d5,a0
	bcs.s	1$
	move.l	a2,a0
1$	move.b	(a0)+,d0
	eor.b	d0,(a1)+
	bra.s	change1

change0	moveq	#3,d1
	move.l	d5,d0
	sub.l	a2,d0
	sub.l	a0,a0
	bsr	writechunk
	moveq	#5,d1
	move.l	d6,d0
	sub.l	a3,d0
	move.l	a3,a0
	bsr	writechunk
	bra	totalend

compare

	mpush	d1-d7/a0-a6
	write	<.>
	lea	msgfail(pc),a1
	call	CheckAbort
	mpop	d1-d7/a0-a6

	moveq	#-1,d0		; Identical bytes
comp1	addq.l	#1,d0
	cmp.l	d5,a2
	bcc.s	comp3
	cmp.l	d6,a3
	bcc.s	comp3
	cmp.b	(a2)+,(a3)+
	beq.s	comp1
comp3	tst.l	d0
	beq.s	comp2
	sub.l	a0,a0
	moveq	#4,d1
	bsr	writechunk

comp2	cmp.l	d5,a2	; End of source file ?
	bcc	srcend
	cmp.l	d6,a3	; End of dest file ?
	bcc	destend
	subq.l	#1,a2
	subq.l	#1,a3
	put.l	a2,olda2
	dv.l	olda2
	dv.l	currmax
	put.l	#firstmax,currmax
	move.l	#firstdepth,d7
comp4	moveq	#1,d0
	move.l	d5,d1
	sub.l	a2,d1
	move.l	d6,d3	; D3=bytes to end
	sub.l	a3,d3
	cmp.l	d1,d3
	bcs.s	compit0
	exg.l	d1,d3
compit0	cmp.l	currmax-v(a4),d3
	bcs.s	compit2
	get.l	currmax,d3
	bra.s	compit2

compit1	move.b	0(a2,d0.l),d1
	move.b	0(a3,d0.l),d2
	cmp.b	d1,d2
	beq.s	comppt1
	cmp.b	(a2),d2
	beq.s	compin1
	cmp.b	(a3),d1
	beq.s	compde1
compnext	addq.l	#1,d0
compit2	subq.l	#1,d3
	bne.s	compit1
	bra.s	comptrx

comppt1	moveq	#threshold,d1	; Critical size
	lea	0(a2,d0.l),a0
	lea	0(a3,d0.l),a1
1$	cmp.b	(a0)+,(a1)+
	dbne	d1,1$
	bne.s	compnext
comppt2	moveq	#1,d1
	move.l	a3,a0
	bsr	writechunkz
	add.l	d0,a2
	add.l	d0,a3
	bra	compare

compin1	moveq	#threshold,d1
	move.l	a2,a0
	lea	0(a3,d0.l),a1
1$	cmp.b	(a0)+,(a1)+
	dbne	d1,1$
	bne.s	compnext
	moveq	#2,d1
	move.l	a3,a0
	bsr	writechunkz
	add.l	d0,a3
	bra	compare

compde1	moveq	#threshold,d1
	lea	0(a2,d0.l),a0
	move.l	a3,a1
1$	cmp.b	(a0)+,(a1)+
	dbne	d1,1$
	bne.s	compnext
	moveq	#3,d1
	sub.l	a0,a0
	bsr	writechunkz
	add.l	d0,a2
	bra	compare

comptrx	addq.l	#1,a2
	addq.l	#1,a3
	subq.l	#1,d7
	beq.s	compit3
	cmp.l	d5,a2
	bcc.s	compit3
	cmp.l	d6,a3
	bcs	comp4
compit3	move.l	a2,d0
	sub.l	olda2-v(a4),d0
	sub.l	d0,a2
	sub.l	d0,a3
	cmp.l	#firstmax,currmax-v(a4)
	bne.s	comppt2
	moveq	#-1,d7
	put.l	d7,currmax
	bra	comp4

srcend	cmp.l	d6,a3	; End of dest file ?
	bcc.s	totalend
	moveq	#2,d1
	move.l	d6,d0
	sub.l	a3,d0
	move.l	a3,a0
	bsr	writechunk
totalend	sf	(a6)+
	move.l	a6,d3
	get.l	arg_topatch,d1
	move.l	#1006,d2
	call	arp,ArpOpen
	move.l	d0,d1
	errc.ne	<Unable to open destination file!>
	get.l	patchto,d2
	sub.l	d2,d3
	call	Write
	cmp.l	d0,d3
	errc.eq	<Error writing destination file!>

	push	copied-v(a4)
	dv.l	copied
	push	tolen-v(a4)
	push	fromlen-v(a4)
	push	d3
	move.l	a7,a1
	dm	finalt,<Done. Patch file size=%ld (original=%ld, new=%ld, changed=%ld)',10,'>
	gett	finalt,a0
	call	Printf
	lea	16(a7),a7
	rts

destend	moveq	#3,d1
	move.l	d5,d0
	sub.l	a2,d0
	sub.l	a0,a0
	bsr.s	writechunk
	bra.s	totalend

writechunkz	cmp.l	olda2-v(a4),a2
	beq.s	writechunk
	mpush	d0-d1/a0
	move.l	a2,d0
	sub.l	olda2-v(a4),d0
	moveq	#1,d1
	move.l	a3,a0
	sub.l	d0,a0
	put.l	a2,olda2
	bsr.s	writechunk
	mpop	d0-d1/a0

writechunk
	ifd	debug
	mpush	d0-d7/a0-a6
	push	d0
	move.l	a0,d0
	sub.l	tofile-v(a4),d0
	bcc.s	1$
	moveq	#-1,d0
1$	push	d0
	push	d1
	dm	msg1,<%ld	@%ld	l=%ld',10,'>
	gett	msg1,a0
	move.l	a7,a1
	call	arp,Printf
	lea	12(a7),a7
	mpop	d0-d7/a0-a6
	endc

wrch	mpush	d0-d7/a0-a5
	move.l	d0,d2
	cmp.l	#32,d0
	bcs.s	1$
	moveq	#0,d2
1$	lsl.b	#5,d1
	or.b	d1,d2
	move.b	d2,(a6)+
	cmp.l	#32,d0
	bcs.s	2$
	cmp.l	#65536,d0
	bcs.s	5$
	sf	(a6)+
	sf	(a6)+
	swap	d0
	bsr.s	putword
	swap	d0
5$	bsr.s	putword
2$	move.l	a0,d1
	beq.s	3$
	add.l	d0,copied-v(a4)
4$	move.b	(a0)+,(a6)+
	subq.l	#1,d0
	bne.s	4$
3$	mpop	d0-d7/a0-a5
	rts

putword	ror.w	#8,d0
	move.b	d0,(a6)+
	ror.w	#8,d0
	move.b	d0,(a6)+
	rts

loadfile	move.l	a2,d1
	move.l	#1005,d2
	call	arp,Open
	move.l	d0,d7
	bne.s	load1
	dm	errf1,<Unable to open %s!',10,'>
	gett	errf1,a0
loaderr	push	a2
	move.l	a7,a1
	call	arp,Printf
	bra	failed	

load1	move.l	d7,d1
	moveq	#0,d2
	moveq	#1,d3
	call	Seek
	move.l	d7,d1
	moveq	#-1,d3
	call	Seek
	move.l	d0,d3
	addq.l	#8,d0
	call	ArpAlloc
	move.l	d0,d2
	bne.s	load2
	move.l	d7,d1
	call	Close
	dm	errf2,<No memory for %s!',10,'>
	gett	errf2,a0
	bra.s	loaderr

load2	move.l	d7,d1
	call	Read
	move.l	d0,d6
	move.l	d7,d1
	call	Close
	cmp.l	d6,d3
	dm	errf3,<Error reading %s!',10,'>
	gett	errf2,a0
	bne.s	loaderr
	move.l	d2,d0
	move.l	d3,d1
	rts
