;---------------------------------------------------------------------------;
;									    ;
; This is the Ross Data Compression implemented in 68000 assembler          ;
; by Niklas Sjöberg, 2:203/415.3@Fidonet				    ;
;									    ;
;									    ;
; The source is fully in the Public Domain. If you think you can improve    ;
; some parts, feel free to modify the code. HOWEVER, be carefull to comment ;
; the parts where you change!						    ;
;									    ;
; On entry:								    ;
; a0 points to XpkSubParams						    ;
;---------------------------------------------------------------------------;
; 921205 - Due to optimization comments may seem a bit weird.. Just try
;          to read 5-10 lines at the time I'm sure you'll get it right..
	

	xdef _unpack			; The only function called from
					; the C-part of the library

	INCLUDE "libraries/xpksub.i"

	section	code

_unpack

	movem.l	a2-a6/d2-d7,-(SP)
	move.l	xsp_InBuf(a0),a1	; source pointer
	move.l	xsp_InLen(a0),d1	; source len
	move.l	xsp_OutBuf(a0),a2	; destination

	move.l	a1,a3			; inbuff_idx  = inbuff
	move.l	a2,a4			; outbuff_idx = outbuff
	move.l	a1,a5			; inbuff_end  = inbuff
	adda.l	d1,a5			; + inbuff_len

	moveq	#0,d0
	moveq	#0,d2
	moveq	#0,d3
	moveq	#0,d4
	moveq	#0,d5
	moveq	#0,d6
	moveq	#0,d7
	
mloop	
	subq.b	#1,d3
;	lsr.w	#1,d3			; Check if we need to get a load of
					; control bits
	bpl.s	no_ctrlbits
	move.w	(a3)+,d2		; new load ctrl-bits
					; 
	moveq	#15,d3			; ctrl_mask = 0x8000
; This is ugly. Since (in worst case) we may overrun the buffer by
; 15 bytes by not checking source and source-end. However, empty
; control-word means that we only copy 15 in worst case. Hell, we
; have 256 XPK_MARGIN bytes to play with :=) (I hope...)
	cmp.l	a5,a3			; main-loop. Go on until end of
	bge.w	loopend			; source buffer

no_ctrlbits
					; First we have to check if data is
					; compressed
;	move.w	d2,d7			; If bits & mask turns out to be one
;	and.w	d3,d7			; then data is compressed
	btst	d3,d2
	bne.s	crunched		; char is crunched
	move.b	(a3)+,(a4)+		; otherwise, copy char and advance
	bra.s	mloop			; 

crunched
	moveq	#0,d4			; First find out what compressions method
					; that was used.
	move.b	(a3)+,d4		; d4 will eventually contain 0-15
	move.w	d4,d5			; d5, contains count (further count may
	and.b	#$f,d5			; be needed for some methods.
	lsr.b	#4,d4			; The higher 4 bits of d4 is type, and
;	and.w	#$f,d4			; the lower count

	cmpi.b	#2,d4			; cmd > 2 then it's a short pattern
	bls.s	no_spat			; (3-15)
;	move.w	d5,d6			; count is 3 chars higher actually
	addq.b	#3,d5			; d5 is never >15+3
	moveq	#0,d7			; to use d4 as loop-register
	move.b	(a3)+,d7		; decode offset
	asl.w	#4,d7
	add.w	d5,d7
	move.l	a4,a6			; Next copy d4 characters from a6
	sub.l	d7,a6			; to a4
	subq.b	#1,d4
s_loop	move.b	(a6)+,(a4)+		;
	dbf	d4,s_loop
	bra.s 	mloop			; Jump to main loop

					
no_spat	tst.b	d4
	;cmpi.b	#0,d4			;is it short rle?
	bne.s	no_srle
	addq.b	#2,d5			; cnt += 3 (-1 for dbf loop)
	move.b	(a3)+,d7		; char to repeat d5 times
sr_loop	move.b	d7,(a4)+		; 
	dbf	d5,sr_loop
	bra.s	mloop			; Main loop


no_srle cmpi.b	#1,d4			; is it a long rle?
	bne.s	no_lrle
	moveq	#0,d7
	move.b	(a3)+,d7		; if so, decode high/low count
	asl.w	#4,d7			; and add them since long RLE
	add.w	d7,d5			; is least 19 :
	addi.w	#18,d5			; cnt +=19 (-1 for dbf loop)
	move.b	(a3)+,d7		; char to set
lr_loop	move.b	d7,(a4)+		; 
	dbf	d5,lr_loop
	bra.s	mloop			; Main loop


no_lrle					; only one case left, long pattern
	move.w	d5,d6			; 
	addq.w	#3,d6			; at least 3 chars long pattern
	moveq	#0,d7
	move.b	(a3)+,d7		; Decode and add high and low
	asl.w	#4,d7			; offset
	add.w	d7,d6			; 
	moveq	#0,d5
	move.b	(a3)+,d5		; Next, get count
	addi.w	#15,d5			; which is at least 16 (-1 for loop)
	move.l	a4,a6			; source
	sub.l	d6,a6			; destination
rl_loop	move.b	(a6)+,(a4)+
	dbf	d5,rl_loop
	bra.w	mloop

loopend
	suba.l	a2,a4			; This is the only exit point
	move.l	a4,xsp_OutBufLen(a0)	; return length to xpkmaster
	movem.l	(SP)+,a2-a6/d2-d7
	moveq	#0,d0
	rts
	END
