*-----------------------------------------------------------------------*
*
*  xpkRDCN v3.0
*
*  This xpk sublibrary was written by Daniel Frey, it is based on
*  the v2.2 by Niklas Sjoberg and John Harris, I rewrote the C-part
*  in assembler and made some optimizations, especially I optimized
*  the crunching-routine. A 68020+ version will follow...
*
*  The actual Ross data compression algorithm is (c) by Ed Ross.
*
*-----------------------------------------------------------------------*
	INCLUDE	"exec/exec_lib.i"

	INCLUDE	"exec/lists.i"
	INCLUDE	"exec/libraries.i"
	INCLUDE	"exec/initializers.i"
	INCLUDE	"exec/resident.i"
*-----------------------------------------------------------------------*
	STRUCTURE	MyLibBase,LIB_SIZE
	APTR		mlb_SegList
	APTR		mlb_GfxBase
	APTR		mlb_IntBase
	APTR		mlb_DosBase
	UBYTE		mlb_Flags
	LABEL		mlb_SIZEOF
*-----------------------------------------------------------------------*
CALL	MACRO
	jsr	_LVO\1(a6)
	ENDM
*-----------------------------------------------------------------------*
Start	moveq	#0,d0
	rts
*-----------------------------------------------------------------------*
Resident
	dc.w	RTC_MATCHWORD
	dc.l	Resident
	dc.l	Init_Table
	dc.b	RTF_AUTOINIT
	dc.b	3	; Version
	dc.b	NT_LIBRARY
	dc.b	0	; Pri
	dc.l	Library_Name
	dc.l	Library_ID
	dc.l	Init_Table
*-----------------------------------------------------------------------*
Library_Name
	dc.b	"xpkRDCN.library",0
	dc.b	"$VER: "
Library_ID
	dc.b	"xpkRDCN 3.0 (4 Aug 93) by Daniel Frey",13,10,0
*-----------------------------------------------------------------------*
Init_Table
	dc.l	mlb_SIZEOF	; Größe meiner Struktur
	dc.l	Func_Table
	dc.l	Data_Table
	dc.l	Init_Routine
*-----------------------------------------------------------------------*
Data_Table
	INITBYTE	LH_TYPE,NT_LIBRARY
	INITLONG	LN_NAME,Library_Name
	INITBYTE	LIB_FLAGS,LIBF_SUMUSED|LIBF_CHANGED
	INITWORD	LIB_VERSION,3
	INITWORD	LIB_REVISION,0
	INITLONG	LIB_IDSTRING,Library_ID
	dc.l	0
*-----------------------------------------------------------------------*
DosName	dc.b	"dos.library",0
IntName	dc.b	"intuition.library",0
GfxName	dc.b	"graphics.library",0
	dc.b	0
*-----------------------------------------------------------------------*
Init_Routine
	move.l	a5,-(a7)
	move.l	d0,a5
	move.l	a0,mlb_SegList(a5)
	lea	GfxName,a1
	CALL	OldOpenLibrary
	move.l	d0,mlb_GfxBase(a5)
	bne.s	.GfxOpen
	move.l	#$38002,d0
	bra.s	.Error
.GfxOpen
	lea	IntName,a1
	CALL	OldOpenLibrary
	move.l	d0,mlb_IntBase(a5)
	bne.s	.IntOpen
	move.l	#$38004,d0
	bra.s	.Error
.IntOpen
	lea	DosName,a1
	CALL	OldOpenLibrary
	move.l	d0,mlb_DosBase(a5)
	bne.s	.DosOpen
	move.l	#$38007,d0
.Error
	movem.l	d7,-(a7)
	move.l	d0,d7
	bsr.s	RemoveBase
	CALL	Alert
	movem.l	(a7)+,d7
	sub.l	a5,a5
.DosOpen
	move.l	a5,d0
	move.l	(a7)+,a5
	rts
*-----------------------------------------------------------------------*
Open	addq.w	#1,LIB_OPENCNT(a6)
	bclr	#LIBB_DELEXP,mlb_Flags(a6)
	move.l	a6,d0
Return	rts
*-----------------------------------------------------------------------*
Close	moveq	#0,d0
	subq.w	#1,LIB_OPENCNT(a6)
	bne.s	Return
	btst	#LIBB_DELEXP,mlb_Flags(a6)
	beq.s	Return
*-----------------------------------------------------------------------*
Expunge	movem.l	a5-a6,-(a7)
	move.l	a6,a5
	move.l	4.w,a6
	tst.w	LIB_OPENCNT(a5)
	beq.s	.DoIt
	bset	#LIBB_DELEXP,mlb_Flags(a5)
	moveq	#0,d0
	bra.s	.ExpungeEnd
.DoIt	move.l	mlb_SegList(a5),-(a7)
	move.l	a5,a1
	CALL	Remove
	bsr.s	RemoveBase
	move.l	(a7)+,d0
.ExpungeEnd
	movem.l	(a7)+,a5-a6
	rts
*-----------------------------------------------------------------------*
RemoveBase
	move.l	mlb_DosBase(a5),d0
	beq.s	.NoDos
	move.l	d0,a1
	CALL	CloseLibrary
.NoDos	move.l	mlb_IntBase(a5),d0
	beq.s	.NoInt
	move.l	d0,a1
	CALL	CloseLibrary
.NoInt	move.l	mlb_GfxBase(a5),d0
	beq.s	.NoGfx
	move.l	d0,a1
	CALL	CloseLibrary
.NoGfx	moveq	#0,d0
	move.l	a5,a1
	move.w	LIB_NEGSIZE(a5),d0
	sub.l	d0,a1
	add.w	LIB_POSSIZE(a5),d0
	CALL	FreeMem
	rts
*-----------------------------------------------------------------------*
Func_Table
	dc.l	Open
	dc.l	Close
	dc.l	Expunge
	dc.l	Start	; This isn't used, so...
*-----------------------------------------------------------------------*
	dc.l	PackInfo
	dc.l	PackChunk
	dc.l	PackFree
	dc.l	PackReset
	dc.l	UnpackChunk
	dc.l	Start	; UnpackFree is empty, returns zero...
	dc.l	-1
*-----------------------------------------------------------------------*
PackInfo
	lea	RdcnInfo(pc),a0
	move.l	a0,d0
	rts
*-----------------------------------------------------------------------*
RdcnInfo
	dc.w	1
	dc.w	3
	dc.w	0
	dc.w	0
	dc.l	ShortName
	dc.l	LongName
	dc.l	Description
	dc.b	"RDCN"
	dc.l	9	; XPKIF_PK_CHUNK | XPKIF_UP_CHUNK
	dc.l	65535
	dc.l	16
	dc.l	65500
	dc.l	PackMsg
	dc.l	UnpackMsg
	dc.l	PackDone
	dc.l	UnpackDone
	dc.w	100
	dc.w	0
	dc.l	Modes
	dc.l	0,0,0,0,0,0

Modes	dc.l	0	; Next
	dc.l	100	; Upto
	dc.l	1	; Flags (A3000_SPEED)
	dc.l	16	; Packmem (about 16K)
	dc.l	0	; Unpackmem
	dc.l	250	; Packspeed   - Unreliable
	dc.l	920	; Unpackspeed - Really unreliable
	dc.w	320	; Ratio *0.1% - Completely random
	dc.w	0	; Reserved
	dc.b	"normal",0,0,0,0

ShortName
	dc.b	"RDCN",0
LongName
	dc.b	"Ross Data Compression v3.0",0
Description
	dc.b	"Very fast but yet efficient packer",0
PackMsg
	dc.b	"Crunching",0
UnpackMsg
	dc.b	"Decrunching",0
PackDone
	dc.b	"Crunched",0
UnpackDone
	dc.b	"Decrunched",0
	dc.b	0
*-----------------------------------------------------------------------*
HASHSIZE	EQU	4096

PackChunk
	move.l	52(a0),d0
	bne.s	.AllocOK
	move.l	#HASHSIZE*4,d0
	moveq	#1,d1
	swap	d1
	movem.l	a0/a6,-(a7)
	move.l	4.w,a6
	CALL	AllocMem
	movem.l	(a7)+,a0/a6
	move.l	d0,52(a0)
	bne.s	.AllocOK
	moveq	#-7,d0	; XPKERR_NOMEM
	rts
.AllocOK
	movem.l	a0/a2-a6/d2-d7,-(a7)

	move.l	d0,a6
	movem.l	(a0)+,a1/a3-a4	; InBuf, InLen, OutBuf
	lea	2(a4),a2
	add.l	a1,a3
	move.l	(a0),d0
	move.l	a4,a0
	lea	-48(a0,d0.l),a4
	move.l	a4,d6
	bra.s	Pack_Entry

Pack_Done
	move.w	d3,-(a7)
	move.b	(a7)+,(a0)+
	move.b	d3,(a0)

	move.l	a2,d0
	movem.l	(a7)+,a0/a2-a6/d2-d7
	sub.l	8(a0),d0
	move.l	d0,16(a0)
	moveq	#0,d0
	rts

Expansion
	movem.l	(a7)+,a0/a2-a6/d2-d7
	moveq	#-17,d0	; XPKERR_EXPANSION
	rts

LongRLE	move.b	d2,d7
	and.b	#15,d7
	add.b	#16,d7
	move.b	d7,(a2)+

	asr.w	#4,d2
	subq.b	#1,d2
ShortRLE
	move.b	d2,(a2)+
	move.b	d1,(a2)+
Pack_LoopC
	bset	d0,d3
Pack_LoopNC
	cmp.l	a1,a3
	bls.s	Pack_Done

	dbf	d0,NoNewBits

	move.w	d3,-(a7)
	move.b	(a7)+,(a0)+
	move.b	d3,(a0)
	move.l	a2,a0
	addq.w	#2,a2
	cmp.l	d6,a2
	bhi.s	Expansion

Pack_Entry
	moveq	#0,d3
	moveq	#15,d0

NoNewBits
	move.l	a1,a4
	move.b	(a1)+,d1
	cmp.b	(a1)+,d1
	bne.s	NoRLE
	cmp.b	(a1)+,d1
	bne.s	NoRLE
	cmp.l	a1,a3
	bcs.s	NotCompressable

	move.w	#4111,d2
	move.w	d2,d7
rep1
	cmp.b	(a1)+,d1
	bne.s	adj_a1
	cmpa.l	a1,a3
	dbcs	d7,rep1
	bcs.s	adj_a1
	moveq	#0,d7
adj_a1	subq.w	#1,a1
	sub.w	d7,d2
	cmpi.w	#15,d2
	ble.s	ShortRLE
	bra.s	LongRLE

NotCompressable
	lea	1(a4),a1
	move.b	d1,(a2)+
	bra.s	Pack_LoopNC

IsLongPat
	move.b	d4,d7
	and.b	#15,d7
	add.b	#$20,d7
	move.b	d7,(a2)+
	asr.w	#4,d4
	move.b	d4,(a2)+
	sub.w	#16,d2
	move.b	d2,(a2)+
	bra.s	Pack_LoopC

NoRLE	move.w	a3,d5
	sub.w 	a4,d5
	subq.w	#2,d5
	bls.s	NotCompressable
	move.l	a4,a1

; Hash start

	move.b	(a1)+,-(a7)
	move.w	(a7)+,d5
	move.b	(a1)+,d5
	move.w	d5,d7
	move.b	(a1),d7
	rol.w	#4,d7
	eor.w	d7,d5
	move.l	#4095,d7
	and.w	d7,d5

; Hash done...

	asl.w	#2,d5
	move.l	0(a6,d5.w),a5
	move.l	a4,d4
	move.l	d4,0(a6,d5.w)
	sub.l	a5,d4
	subq.l	#3,d4
	cmp.l	d7,d4
	bgt.s	NotCompressable

	move.l	a4,a1
	cmp.b	(a5)+,(a1)+
	bne.s	NotCompressable
	cmp.b	(a5)+,(a1)+
	bne.s	NotCompressable
	move.w	#271,d2
	move.w	#269,d7
rep2
	cmp.b	(a5)+,(a1)+
	bne.s   adj2_a1
	cmp.l	a5,a4
	bcs.s	adj2_a1
	cmp.l	a1,a3
	dbcs	d7,rep2
	bcs.s	adj2_a1

	moveq	#0,d7

adj2_a1	sub.w	d7,d2
	cmpi.w	#2,d2
	bls.w	NotCompressable
	subq.w	#1,a1
	cmpi.w	#15,d2
	bgt.w	IsLongPat
	asl.b	#4,d2
	move.b	d4,d7
	and.b	#15,d7
	add.b	d7,d2
	move.b	d2,(a2)+
	asr.w	#4,d4
	move.b	d4,(a2)+
	bra.w	Pack_LoopC
*-----------------------------------------------------------------------*
PackFree
	move.l	52(a0),d0	; xsp_Sub[0]
	beq.s	.Return
	clr.l	52(a0)		; xsp_Sub[0]
	move.l	d0,a1
	move.l	#HASHSIZE*4,d0
	move.l	a6,-(a7)
	move.l	4.w,a6
	CALL	FreeMem
	move.l	(a7)+,a6
.Return	rts
*-----------------------------------------------------------------------*
PackReset
	move.l	52(a0),d0	; xsp_Sub[0]
	beq.s	.Retur
	move.l	d0,a0
	move.w	#HASHSIZE-1,d0
.Loop	clr.l	(a0)+
	dbf	d0,.Loop
	moveq	#0,d0
.Retur	rts
*-----------------------------------------------------------------------*
upc_loopend
	suba.l	a2,a4
	move.l	a4,(a0)
	movem.l	(a7)+,a2-a5/d2-d4
	moveq	#0,d0
	rts

UnpackChunk
	movem.l	a2-a5/d2-d4,-(a7)
	movem.l	(a0)+,d1/a3-a4
	move.l	a4,a2
	lea	0(a3,d1.l),a5
	move.l	d1,a3
	moveq	#0,d1
	moveq	#0,d4

upc_new_ctrlbits
	move.b	(a3)+,-(a7)	; Slighly faster than shifting
	move.w	(a7)+,d2	; and works on 68000.
	move.b	(a3)+,d2
	cmp.l	a5,a3
	bge.s	upc_loopend

upc_new_ctrl2
	moveq	#15,d3
	btst	d3,d2
	bne.s	upc_crunched
upc_CopyChar
	move.b	(a3)+,(a4)+
upc_Loop
	subq.b	#1,d3
	bmi.s	upc_new_ctrlbits
	btst	d3,d2
	beq.s	upc_CopyChar

upc_crunched
	move.b	(a3)+,d4
	move.w	d4,d1
	and.w	#15,d1
	lsr.b	#4,d4

	subq.b	#2,d4
	bls.s	upc_no_spat

	moveq	#-1,d0
	sub.b	(a3)+,d0
	rol.w	#4,d0
	sub.w	d1,d0
	lea	-2(a4,d0.w),a1
	move.b	(a1)+,(a4)+
	ext.w	d4
upc_s_loop
	move.b	(a1)+,(a4)+
	dbf	d4,upc_s_loop
	bra.s	upc_Loop

upc_no_spat
	addq.b	#1,d4
	bpl.s	upc_no_srle
	move.b	(a3)+,d0
	move.b	d0,(a4)+
	move.b	d0,(a4)+
upc_sr_loop
	move.b	d0,(a4)+
	dbf	d1,upc_sr_loop
	bra.s	upc_Loop

upc_no_srle
	bne.s	upc_no_lrle
	moveq	#0,d0
	move.b	(a3)+,d0
	asl.w	#4,d0
	add.w	d0,d1
	move.b	(a3)+,d0
	move.b	d0,-(a7)
	move.w	(a7)+,d4
	move.b	d0,d4
	move.w	d4,d0
	swap	d0
	move.w	d4,d0
	move.w	a4,d4
	lsr.b	#1,d4
	bcc.s	upc_a4_even

	move.b	d0,(a4)+
	subq.w	#1,d1

upc_a4_even
	move.l	d0,(a4)+
	move.l	d0,(a4)+
	move.l	d0,(a4)+
	move.l	d0,(a4)+
	move.w	d0,(a4)+
	move.w	d1,d4
	bmi.s	upc_Loop

	and.w	#3,d4
	lsr.w	#2,d1
	subq.w	#1,d1
	bmi.s   upc_lr_lp2
upc_lr_loop
	move.l	d0,(a4)+
	dbf	d1,upc_lr_loop
upc_lr_lp2
	move.b	d0,(a4)+
	dbf	d4,upc_lr_lp2
	bra.w	upc_Loop

upc_no_lrle
	addq.w	#3,d1
	moveq	#0,d0
	move.b	(a3)+,d0
	asl.w	#4,d0
	add.w	d0,d1

	moveq	#0,d4
	move.b	(a3)+,d4
	add.w	#15,d4
	move.l	a4,a1
	sub.l	d1,a1
	lsr.b	#1,d1
	bcs.s	upc_rl_lp2

	move.w	a1,d1
	lsr.b	#1,d1
	bcc.s	upc_a1_even
	move.b	(a1)+,(a4)+
	subq.w	#1,d4
upc_a1_even
	move.w	d4,d1
	and.w	#3,d4
	lsr.w	#2,d1
	subq.w	#1,d1
upc_rl_loop
	move.l	(a1)+,(a4)+
	dbf	d1,upc_rl_loop
upc_rl_lp2
	move.b	(a1)+,(a4)+
	dbf	d4,upc_rl_lp2
	bra.w	upc_Loop
*-----------------------------------------------------------------------*
	END
