*****************************************************************************
* DataDecrunch					                d0 Destroyed!
* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
* Checks for known data decrunchers then attempts to decrunch the data if
* it recognises the cruncher it was compressed with.
*
* Please note that when unpacking "CrunchMania" data the DESTINATION can be
* as little as 14 bytes infront of the SOURCE. Also note that only a SOURCE
* ptr is required when exploding "Imploded" data, as source=destination.
*
* INPUTS ; a0=Source Packdata pointer	a1=Destination Adr for Unpacked data
* OUTPUTS; d0=If failed returns error code of -1 in d0
*****************************************************************************
		XDEF	_Decrunch

_Decrunch:	movem.l	d1-d7/a0-a6,-(sp)	; save registers
		lea	IDJmp(pc),a6		; get ptr to ID`s Table
		move.l	a6,a5			; make copy of ptr
		move.l	(a0),d1			; source ID to check against

search_id:	cmpa.l	(a5)+,d1		; check an ID Entry from table
		beq.s	CallIt			; found the correct ID?
		tst.w	(a5)+			; is this last entry in table?
		bne.s	search_id		; if not.. keep searching...

		moveq	#-1,d0			; must be an unknown cruncher
		movem.l	(sp)+,d1-d7/a0-a6	; restore registers
		rts

CallIt		move.w	(a5)+,d1
		jsr	(a6,d1.w)		; call decruncher routine
		movem.l	(sp)+,d1-d7/a0-a6	; restore registers
		rts
			
IDJmp:		dc.l	"CrM2"			;00 - "CrunchMania LZHuffman"
		dc.w	LZHuffman-IDJmp
		dc.l	"CrM!"			;01 - "CrunchMania Normal"
		dc.w	CrunchMania-IDJmp
		dc.l	"IMP!"			;02 - "Imploder Data"
		dc.w	Explode-IDJmp	
		dc.l	0			;ID - "End of table"
		
CrunchMania	addq.l	#6,a0		; skip min 2nd dist & header
		move.l	(a0)+,d1	; get Original Length (unpacked Size)
		move.l	(a0)+,d2	; get Crunched Length (packed Size)
		move.l	a0,a2

		move.l	a1,a5		;Decrunched Anfang (hier Ende des Decrunchens)
		add.l	d1,a1
		add.l	d2,a2
		move.w	-(a2),d0	;Anz Bits in letztem Wort
		move.l	-(a2),d6	;1.LW
		moveq	#16,d7		;Anz Bits
		sub.w	d0,d7		;Anz Bits, die rotiert werden müssen
		lsr.l	d7,d6		;1.Bits an Anfang bringen
		move.w	d0,d7		;Anz Bits, die noch im Wort sind
		moveq	#16,d3
		moveq	#0,d4
.DecrLoop:	cmp.l	a5,a1
		ble.w	.DecrEnd	;a1=a5: fertig (a1<a5: eigentlich Fehler)

		bsr.s	.BitTest
		bcc.s	.InsertSeq	;1.Bit 0: Sequenz
		moveq	#0,d4
** einzelne Bytes einfügen **
.InsertBytes:	moveq	#8,d1
		bsr.w	.GetBits
		move.b	d0,-(a1)
		dbf	d4,.InsertBytes
		bra.s	.DecrLoop

.SpecialInsert:	moveq	#14,d4
		moveq	#5,d1
		bsr.s	.BitTest
		bcs.s	.IB1
		moveq	#14,d1
.IB1:		bsr.s	.GetBits
		add.w	d0,d4
		bra.s	.InsertBytes

** Anzahl der gleichen Bits holen **
.InsertSeq:	bsr.s	.BitTest
		bcs.s	.AB1
		moveq	#1,d1		;Maske: 0 (1 AB)
		moveq	#1,d4		;normal: Summe 1
		bra.s	.ABGet
.AB1:		bsr.s	.BitTest
		bcs.s	.AB2
		moveq	#2,d1		;Maske: 01 (2 ABs)
		moveq	#3,d4		;ab hier: Summe mindestens 3
		bra.s	.ABGet
.AB2:		bsr.s	.BitTest
		bcs.s	.AB3
		moveq	#4,d1		;Maske: 011 (4 ABs)
		moveq	#7,d4		;hier: Summe 11
		bra.s	.ABGet
.AB3:		moveq	#8,d1		;Maske: 111 (8 ABs)
		moveq	#$17,d4		;hier: Summe 11
.ABGet:		bsr.s	.GetBits
		add.w	d0,d4		;d0: Länge der Sequenz - 1
		cmp.w	#22,d4
		beq.s	.SpecialInsert
		blt.s	.Cont
		subq.w	#1,d4
** SequenzAnbstand holen **
.Cont:		bsr.s	.BitTest
		bcs.s	.DB1
		moveq	#9,d1		;Maske: 0 (9 DBs)
		moveq	#$20,d2
		bra.s	.DBGet
.DB1:		bsr.s	.BitTest
		bcs.s	.DB2
		moveq	#5,d1		;Maske: 01 (5 DBs)
		moveq	#0,d2
		bra.s	.DBGet
.DB2:		moveq	#14,d1		;Maske: 11 (12 DBs)
		move.w	#$220,d2
.DBGet:		bsr.s	.GetBits
		add.w	d2,d0
		lea	0(a1,d0.w),a3	;a3 auf Anf zu kopierender Seq setzten

.InsSeqLoop:	move.b	-(a3),-(a1)	;Byte kopieren
		dbf	d4,.InsSeqLoop

		bra.w	.DecrLoop

.BitTest:	subq.w	#1,d7
		bne.s	.BTNoLoop
		moveq	#16,d7		;hier kein add notwendig: d7 vorher 0
		move.w	d6,d0
		lsr.l	#1,d6		;Bit rausschieben und Flags setzen
		swap	d6		;ror.l	#16,d6
		move.w	-(a2),d6	;nächstes Wort holen
		swap	d6		;rol.l	#16,d6
		lsr.w	#1,d0		;Bit rausschieben und Flags setzen
		rts
.BTNoLoop:	lsr.l	#1,d6		;Bit rausschieben und Flags setzen
.DecrEnd:	rts

.GetBits:	move.w	d6,d0		;d1:AnzBits->d0:Bits  d6:Akt Wort
		lsr.l	d1,d6		;nächste Bits nach vorne bringen
		sub.w	d1,d7		;d7:Anz Bits, die noch im Wort sind
		bgt.s	.GBNoLoop
;		add.w	#16,d7		;BitCounter korrigieren
		add.w	d3,d7		;BitCounter korrigieren
		ror.l	d7,d6		;restliche Bits re rausschieben
		move.w	-(a2),d6	;nächstes Wort holen
		rol.l	d7,d6		;und zurückrotieren
.GBNoLoop:	add.w	d1,d1		;*2 (in Tab sind Ws)
		and.w	.AndData-2(pc,d1.w),d0	;unerwünschte Bits rausschmeißen
		rts
.AndData:	dc.w	%1,%11,%111,%1111,%11111,%111111,%1111111
		dc.w	%11111111,%111111111,%1111111111
		dc.w	%11111111111,%111111111111
		dc.w	%1111111111111,%11111111111111

*******************************************************************************
* CrunchMania LZHuffman Decompression
* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
* INPUTS :	a1	=	Destination
*		a2	=	Source
*******************************************************************************

LZHuffman:	move.l	a0,a2
		addq.l	#6,a2		;skip ID & Minimum 2nd distance
		move.l	(a2)+,d1	;original size
		move.l	(a2)+,d2	;packed length
		move.l	a1,a5		;Decrunched Anfang (hier Ende des Decrunchens)

		add.l	d1,a1
		add.l	d2,a2
		lea	2(a1),a6
		move.w	-(a2),d0
		move.l	-(a2),d6
		moveq	#$10,d7
		sub.w	d0,d7
		lsr.l	d7,d6
		move.w	d0,d7
		moveq	#$10,d3
lz2:		lea	$49E(a6),a0
		move.l	d2,(a0)+
		move.l	d2,(a0)+
		move.l	d2,(a0)+
		move.l	d2,(a0)+

		move.l	d2,(a0)+
		move.l	d2,(a0)+
		move.l	d2,(a0)+
		move.l	d2,(a0)+

		move.l	d2,(a0)+
		move.l	d2,(a0)+
		move.l	d2,(a0)+
		move.l	d2,(a0)+

		move.l	d2,(a0)+
		move.l	d2,(a0)+
		move.l	d2,(a0)+
		move.l	d2,(a0)+

		lea	$4BE(a6),a0
		lea	$9E(a6),a4
		moveq	#9,d2
		bsr.w	lz15

		lea	$49E(a6),a0
		lea	$80(a6),a4
		moveq	#4,d2
		bsr.w	lz15

		lea	$4BE(a6),a3
		lea	-2(a6),a4
		bsr.w	lz19

		lea	$49E(a6),a3
		lea	$1E(a6),a4
		bsr.w	lz19

		moveq	#$10,d1
		bsr.s	lz12

		move.w	d0,d5
		lea	$9E(a6),a0
		lea	-$1E(a0),a5
lz4:		move.l	a6,a4
		bsr.s	lz8
		btst	#8,d0
		bne.s	lz7
		move.w	d0,d4
		lea	$20(a6),a4
		exg	a0,a5
		bsr.s	lz8
		exg	a0,a5
		move.w	d0,d1
		move.w	d0,d2
		bne.s	lz5
		moveq	#1,d1
		moveq	#$10,d2
lz5:		bsr.s	lz12

		bset	d2,d0
		lea	1(a1,d0.w),a3
lz6:		move.b	-(a3),-(a1)
		dbra	d4,lz6

		move.b	-(a3),-(a1)
		move.b	-(a3),d0
lz7:		move.b	d0,-(a1)
		dbra	d5,lz4

		moveq	#1,d1
		bsr.s	lz12
		bne.w	lz2
		rts				;all done.. exit here!

lz8:		moveq	#0,d1
lz9:		subq.w	#1,d7
		beq.s	lz10
		lsr.l	#1,d6
		bra.s	lz11

lz10:		moveq	#$10,d7
		move.w	d6,d0
		lsr.l	#1,d6
		swap	d6
		move.w	-(a2),d6
		swap	d6
		lsr.w	#1,d0
lz11:		addx.w	d1,d1
		move.w	(a4)+,d0
		cmp.w	d1,d0
		bls.s	lz9
		add.w	$3E(a4),d1
		add.w	d1,d1
		move.w	(a0,d1.w),d0
		rts

lz12:		move.w	d6,d0
		lsr.l	d1,d6
		sub.w	d1,d7
		bgt.s	lz13
		add.w	d3,d7
		ror.l	d7,d6
		move.w	-(a2),d6
		rol.l	d7,d6
lz13:		add.w	d1,d1
		and.w	.AndData-2(pc,d1.w),d0
		rts
.AndData:	dc.w	%1,%11,%111,%1111,%11111,%111111,%1111111
		dc.w	%11111111,%111111111,%1111111111
		dc.w	%11111111111,%111111111111
		dc.w	%1111111111111,%11111111111111
		dc.w	%111111111111111,%1111111111111111

lz15:		movem.l	d1-d5/a3,-(sp)
		moveq	#4,d1
		bsr.s	lz12
		move.w	d0,d5
		subq.w	#1,d5
		moveq	#0,d4
		sub.l	a3,a3
lz16:		addq.w	#1,d4
		move.w	d4,d1
		cmp.w	d2,d1
		ble.s	lz17
		move.w	d2,d1
lz17:		bsr.s	lz12
		move.w	d0,(a0)+
		add.w	d0,a3
		dbra	d5,lz16

		move.w	a3,d5
		subq.w	#1,d5
lz18:		move.w	d2,d1
		bsr.s	lz12
		move.w	d0,(a4)+
		dbra	d5,lz18
		movem.l	(sp)+,d1-d5/a3
		rts

lz19:		movem.l	d0-d7,-(sp)
		moveq	#14,d7
		moveq	#-1,d4
		moveq	#0,d2
		move.l	d2,d3
		moveq	#1,d1
		move.w	d2,(a4)+
lz20:		move.w	(a3)+,d6
		move.w	d3,$40(a4)
		move.w	-2(a4),d0
		add.w	d0,d0
		sub.w	d0,$40(a4)
		add.w	d6,d3
		mulu	d1,d6
		add.w	d6,d2
		move.w	d2,(a4)+
		add.w	d2,d2
		dbra	d7,lz20
		movem.l	(sp)+,d0-d7
		rts


;
; explode:
;
; In:	a0.l=*buffer
; Out:	d0.l=0:Error; -1:Ok
;

Explode:	movem.l	d2-d5/a2-a4,-(sp)
		move.l	a0,a3
		move.l	a0,a4
		tst.l	(a0)+
		add.l	(a0)+,a4
		add.l	(a0)+,a3
		move.l	a3,a2
		move.l	(a2)+,-(a0)
		move.l	(a2)+,-(a0)
		move.l	(a2)+,-(a0)
		move.l	(a2)+,d2
		move.w	(a2)+,d3
		bmi.s	ex00
		subq.l	#1,a3
ex00:		lea	-28(sp),sp
		move.l	sp,a1
		moveq	#6,d0
ex01:		move.l	(a2)+,(a1)+
		dbf	d0,ex01
		move.l	sp,a1
		moveq	#0,d4
ex02:		tst.l	d2
		beq.s	ex04
ex03:		move.b	-(a3),-(a4)
		subq.l	#1,d2
		bne.s	ex03
ex04:		cmp.l	a4,a0
		blo.s	ex07
		lea	28(sp),sp
		moveq	#-1,d0
		cmp.l	a3,a0
		beq.s	ex06
ex05:		moveq	#0,d0
ex06:		movem.l	(sp)+,d2-d5/a2-a4
		tst.l	d0
		rts
ex07:		add.b	d3,d3
		bne.s	ex08
		move.b	-(a3),d3
		addx.b	d3,d3
ex08:		bcc.s	ex20
		add.b	d3,d3
		bne.s	ex09
		move.b	-(a3),d3
		addx.b	d3,d3
ex09:		bcc.s	ex19
		add.b	d3,d3
		bne.s	ex10
		move.b	-(a3),d3
		addx.b	d3,d3
ex10:		bcc.s	ex18
		add.b	d3,d3
		bne.s	ex11
		move.b	-(a3),d3
		addx.b	d3,d3
ex11:		bcc.s	ex17
		add.b	d3,d3
		bne.s	ex12
		move.b	-(a3),d3
		addx.b	d3,d3
ex12:		bcc.s	ex13
		move.b	-(a3),d4
		moveq	#3,d0
		bra.s	ex21
ex13:		add.b	d3,d3
		bne.s	ex14
		move.b	-(a3),d3
		addx.b	d3,d3
ex14:		addx.b	d4,d4
		add.b	d3,d3
		bne.s	ex15
		move.b	-(a3),d3
		addx.b	d3,d3
ex15:		addx.b	d4,d4
		add.b	d3,d3
		bne.s	ex16
		move.b	-(a3),d3
		addx.b	d3,d3
ex16:		addx.b	d4,d4
		addq.b	#6,d4
		moveq	#3,d0
		bra.s	ex21
ex17:		moveq	#5,d4
		moveq	#3,d0
		bra.s	ex21
ex18:		moveq	#4,d4
		moveq	#2,d0
		bra.s	ex21
ex19:		moveq	#3,d4
		moveq	#1,d0
		bra.s	ex21
ex20:		moveq	#2,d4
		moveq	#0,d0
ex21:		moveq	#0,d5
		move.w	d0,d1
		add.b	d3,d3
		bne.s	ex22
		move.b	-(a3),d3
		addx.b	d3,d3
ex22:		bcc.s	ex25
		add.b	d3,d3
		bne.s	ex23
		move.b	-(a3),d3
		addx.b	d3,d3
ex23:		bcc.s	ex24
		move.b	extab0(pc,d0.w),d5
		addq.b	#8,d0
		bra.s	ex25
ex24:		moveq	#2,d5
		addq.b	#4,d0
ex25:		move.b	extab1(pc,d0.w),d0
ex26:		add.b	d3,d3
		bne.s	ex27
		move.b	-(a3),d3
		addx.b	d3,d3
ex27:		addx.w	d2,d2
		subq.b	#1,d0
		bne.s	ex26
		add.w	d5,d2
		moveq	#0,d5
		move.l	d5,a2
		move.w	d1,d0
		add.b	d3,d3
		bne.s	ex28
		move.b	-(a3),d3
		addx.b	d3,d3
ex28:		bcc.s	ex31
		add.w	d1,d1
		add.b	d3,d3
		bne.s	ex29
		move.b	-(a3),d3
		addx.b	d3,d3
ex29:		bcc.s	ex30
		move.w	8(a1,d1.w),a2
		addq.b	#8,d0
		bra.s	ex31
ex30:		move.w	0(a1,d1.w),a2
		addq.b	#4,d0
ex31:		move.b	$10(a1,d0.w),d0
ex32:		add.b	d3,d3
		bne.s	ex33
		move.b	-(a3),d3
		addx.b	d3,d3
ex33:		addx.l	d5,d5
		subq.b	#1,d0
		bne.s	ex32
		addq.w	#1,a2
		add.l	d5,a2
		add.l	a4,a2
ex34:		move.b	-(a2),-(a4)
		subq.b	#1,d4
		bne.s	ex34
		bra	ex02
extab0:		dc.l	$60A0A12
extab1:		dc.l	$1010101,$2030304,$405070E

