	XDEF	compress_slow

;On entry:
;	a0 = InBuf
;	a1 = OutBuf
;	a2 = HashTab
;	d0 = InLen

	CODE

COMPRESSREGS	reg	a3-a6/d1-d7
compress_slow:
	movem.l COMPRESSREGS,-(sp)
	move.l	a0,d1		; d1=src+src_len+2
	add.l	d0,d1		; since all srcpointers are
	addq.l	#2,d1		; 2 to big we need this +2 !

	moveq.l #$FFFFFFFC,d2
	and.l	d0,d2
	add.l	a1,d2
	move.l	d2,a4		; a4=dst+(src_len & ~3)

	movem.l a1/a4,-(sp)     ; save dst and dst_end for later use

;;;	lea	$40000(a2),a6   ; a6=hh a6-$40000 == hash
	moveq.l #4,d0
	swap	d0
	move.l	a2,a6
	add.l	d0,a6

	moveq.l #0,d0
	move.w	#$10FF,d2
hfill:	move.l	d0,(a2)+        ; fill hash with $00000000
	move.l	d0,(a2)+        ; hash is $1100*$10 = $11000 longs big
	move.l	d0,(a2)+
	move.l	d0,(a2)+
	move.l	d0,(a2)+
	move.l	d0,(a2)+
	move.l	d0,(a2)+
	move.l	d0,(a2)+
	move.l	d0,(a2)+
	move.l	d0,(a2)+
	move.l	d0,(a2)+
	move.l	d0,(a2)+
	move.l	d0,(a2)+
	move.l	d0,(a2)+
	move.l	d0,(a2)+
	move.l	d0,(a2)+
	dbra	d2,hfill

	moveq.l #-1,d0		; d0 = 4*hash_fkt(s,s+1,s+2)
	move.b	(a0)+,d0        ; a0 += 2
	lsl.w	#8,d0
	move.b	(a0)+,d0
	add.b	(a0),d0
	lsl.l	#2,d0

	move.l	a0,0(a6,d0.l)   ; hash[hash_val]=s

	move.l	#$00000FFF,d4

	subq.l	#2,a4
	move.l	a4,a3		; get place to put next ctrl_word
	moveq.l #1,d7		; initialize ctrl_word with $0001

	move.l	a0,d2
	sub.l	d4,d2		; d2 = src - 4095

;;here:	bra.s	here

;	bra.s	do_literal	; The first one is always a literal.

				;REGISTER MAP
				;============

;	a0 source
;	a1 destination byte stream	(post increment)
;	a2 Temporary
;	a3 place to put control word in output
;	a4 destination word stream	(pre decrement)
;	a5 Temporary
;	a6 hashtable
;	a7 Stack pointer. Don't touch!

;	d0 Temporary
;	d1 End of input+2
;	d2 src - 4095
;	d3 match_offset , match_len
;	d4 Constant 4095
;	d5 work pointer into LZ77-window
;	d6 Temporary
;	d7 Buffers the current control word.

;;;---------------------------------------------------------------------------

do_literal:
	move.b	-2(a0),(a1)+    ; write literal

	moveq.l #-1,d0		; increment src
	move.b	-1(a0),d0
	lsl.w	#8,d0
	move.b	(a0)+,d0	; ++a0
	addq.l	#1,d2		; d2+=1  d2==src-4095
	add.b	(a0),d0
	lsl.l	#2,d0		; d0 = hash_fkt(src[-2],src[-1],src[0])

	move.l	0(a6,d0.l),d5   ; d5 = wrk = hash[hash_val]
	move.l	a0,0(a6,d0.l)   ; hash[hash_val] = src

	move.l	a0,d0
	and.l	d4,d0
	asl.w	#2,d0		; clears X
	move.l	d5,0(a6,d0.l)   ; hh[src&$FFF] = [old]hash[hash_val] {== wrk}

insctl:	addx.w	d7,d7		; inject X-Flag into ctrl_word
	bcc.s	eloop		; control not full

	move.w	d7,(a3)         ; write ctrl_word to it's place
	subq.l	#2,a4
	move.l	a4,a3		; get place to put next ctrl_word

	moveq.l #1,d7		; initialize ctrl_word with $0001
	cmp.l	d1,a0		; Has src reached src_end?
	bcc	end_control_done

eloop:	cmp.l	d2,d5			; is wrk below the limit
	bcs.s	do_literal		; is wrk < src - 4095
	moveq.l	#1,d3		; Initializations for iloop
				; match_ofs,match_len-1 = 0,1

iloop:	move.l	a0,a2
	move.l	d5,a5

MATCH	MACRO
	cmp.b	(a2)+,(a5)+
	bne.s	\1
	ENDM

	MATCH	next	; 2
	MATCH	mism	; 3
	MATCH	mism	; 4
	MATCH	mism	; 5
	MATCH	mism	; 6
	MATCH	mism	; 7
	MATCH	mism	; 8
	MATCH	mism	; 9
	MATCH	mism	;10
	MATCH	mism	;11
	MATCH	mism	;12
	MATCH	mism	;13
	MATCH	mism	;14
	MATCH	mism	;15
	MATCH	mism	;16
	MATCH	mism	;17
	addq.l	#1,a5	;18
mism:	sub.l	d5,a5		; a5=match_len-1

	cmp.w	a5,d3
	bcc.s	next		; new match is not longer than old one

	move.l	a0,d3
	sub.l	d5,d3		; d3 = src - wrk = match_ofs
	swap	d3
	move.w	a5,d3		; match_ofs,match_len-1 is updated.

	cmp.b	#17,d3
	bcc.s	docopy		; match_len-1 >= 18-1

next:	and.l	d4,d5			; d5=wrk & $00000FFF
	lsl.w	#2,d5
	move.l	0(a6,d5.l),d5           ; wrk=hh[wrk & $00000FFF]

	cmp.l	d2,d5			; is wrk in range?
	bcc.s	iloop			; is wrk >= src - 4095 ?


finished_chain:
	cmp.b	#2,d3
	bcs	do_literal

docopy:	moveq.l #17,d0
	add.l	d0,d2
	sub.b	d3,d0		; d0=17-(match_len-1)
	sub.l	d0,d2
	addq.l	#1,d2		; d2+=match_len

	swap	d3
	asl.w	#4,d3
	or.b	d0,d3		; d3 = OOOOOOOO OOOOLLLL

	move.w	d3,-(a4)        ; write copyinfo

	swap	d3		; d3.w = match_len - 1

incsrc: moveq.l #-1,d0		; increment src
	move.b	-1(a0),d0
	lsl.w	#8,d0
	move.b	(a0)+,d0
	add.b	(a0),d0         ; ++a0

	move.l	a0,d6
	and.l	d4,d6
	asl.w	#2,d6

	asl.l	#2,d0		; d0 = hash_fkt(src[-2],src[-1],src[0])
				; Does set the X-Flag
	move.l	0(a6,d0.l),d5   ; d5 = wrk = hash[hash_val]
	move.l	a0,0(a6,d0.l)   ; hash[hash_val] = src

	move.l	d5,0(a6,d6.l)   ; hh[src&$FFF] = [old]hash[hash_val] {== wrk}

	dbra	d3,incsrc

	cmp.l	d1,a0		; Has src reached src_end?
	bcs	insctl		; Insert the X-Flag[=1] into control

;;;The main loop ends here.
;;;---------------------------------------------------------------------------
				;FINALIZATION
				;============

	add.l	d0,d0		; Just set the Carry [d0 is junked]
; Fill the rest of the control.  Since the carry is set the 1st control
; inserted will be a copy item and the rest literals.
FillControl:
	addx.w	d7,d7
	bcc.s	FillControl

	move.w	d7,(a3)         ;Write it to its output position
	
	subq.l	#2,a4		; reserve space for next controlword
end_control_done:
	addq.l	#2,a4		; Junk new controlword
	movem.l (sp)+,d6/d7     ; Pop dst and dst_end

	;Copy the literals after the word stream pointed to by a1.
	move.l	a4,d0		;d0:=Number of Bytes to increase a1
	sub.l	a1,d0		;till a1 and a4 are equally aligned.
	bcc.s	did_compress

;byte- and wordstream together do exceede the size of the output buffer.
	moveq	#0,d0		; return 0 to indicate overrun
	bra.s	finish

did_compress:
	moveq	#3,d1
	and.w	d0,d1

	moveq.l #0,d0		;pad a1 up to make a1 and a4 equally aligned.
	bra.s	EFLoop
FLoop:	move.b	d0,(a1)+
EFLoop: dbra	d1,FLoop

	sub.l	a4,d7		;d7:=size of wordstream

	lsr.l	#2,d7
	bcc.s	ECLoop		;make sure we do the move.l longword aligned.
	move.w	(a4)+,(a1)+
NoWord: bra.s	ECLoop
CLoopH: swap	d7
CLoop:	move.l	(a4)+,(a1)+
ECLoop: dbra	d7,CLoop
	swap	d7
	dbra	d7,CLoopH

	move.l	a1,d0
	sub.l	d6,d0			;d0:=Final output length
finish: movem.l (sp)+,COMPRESSREGS
	rts

;;;---------------------------------------------------------------------------

    END

