*****************************************************************************
*   $Id: CrunchMania.a,v 1.2 2005/06/23 14:39:16 stoecker Exp $
*   Crunch Mania decrunching slave
*
*   XFD library system for cruncher handling
*   Copyright (C) 1994-1998 by Georg Hörmann
*   Copyright (C) 1998 by Dirk Stöcker <soft@dstoecker.de>
*
*   This library is free software; you can redistribute it and/or
*   modify it under the terms of the GNU Lesser General Public
*   License as published by the Free Software Foundation; either
*   version 2.1 of the License, or (at your option) any later version.
*
*   This library is distributed in the hope that it will be useful,
*   but WITHOUT ANY WARRANTY; without even the implied warranty of
*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
*   Lesser General Public License for more details.
*
*   You should have received a copy of the GNU Lesser General Public
*   License along with this library; if not, write to the Free Software
*   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*****************************************************************************

S_CrMData	dc.l	S_CrMEncData-Xfd68KHeader
		dc.w	2
		dc.w	39
		dc.l	N_CrMData-Xfd68KHeader
		dc.w	XFDPFF_DATA!XFDPFF_RECOGLEN!XFDPFF_USERTARGET
		dc.w	0
		dc.l	RB_CrMData-Xfd68KHeader
		dc.l	DB_CrMData-Xfd68KHeader
		dc.l	SD_CrMData-Xfd68KHeader
		dc.l	VD_CrMData-Xfd68KHeader
		dc.w	XFDID_CrunchManiaData
		dc.w	0
		dc.l	14+4+2

N_CrMData	dc.b	'CrunchMania Data',0
		even

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

RB_CrMData	BSR.B	SD_CrMData
		TST.L	D0
		BEQ.B	.Exit
		MOVEQ	#0,D0
		MOVE.L	6(A0),D1
		BEQ.B	.Exit
		CMP.L	10(A0),D1	; cr < uncr ?
		BLE.B	.Exit
		MOVE.L	D1,xfdrr_MinTargetLen(A1)
		MOVE.L	D1,xfdrr_FinalTargetLen(A1)
		MOVEQ	#14,D1
		ADD.L	10(A0),D1
		MOVE.L	D1,xfdrr_MinSourceLen(A1)
		MOVEQ	#1,D0
.Exit		RTS

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

SD_CrMData	MOVEQ	#1,D0
		CMP.L	#'CD³¹',(A0)
		BEQ.B	.Ok
		CMP.L	#'IFT?',(A0)
		BEQ.B	.Ok
		CMP.L	#'XPKZ',(A0)
		BEQ.B	.Ok
		CMP.L	#'Iron',(A0)
		BEQ.B	.Ok
		CMP.L	#'LSD!',(A0)
		BEQ.B	.Ok
		CMP.L	#'ViS1',(A0)
		BEQ.B	.Ok
		CMP.L	#'ViSL',(A0)
		BEQ.B	.Ok
		cmp.l	#'MSS!',(a0)
		beq.b	.Ok
		cmp.l	#'mss!',(a0)
		beq.b	.Ok
		cmp.l	#'CrM!',(a0)
		beq.b	.Ok
		cmp.l	#'Crm!',(a0)
		beq.b	.Ok
		cmp.l	#'CrM2',(a0)
		beq.b	.Ok
		cmp.l	#'Crm2',(a0)
		BEQ.B	.Ok
		MOVEQ	#0,D0
.Ok		RTS

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

VD_CrMData	moveq	#14,d1		;headerlen
		add.l	10(a0),d1	;crlen
		cmp.l	d0,d1		;> bufferlen??
		bgt.s	.Exit
		move.l	6(a0),d0
		sub.l	10(a0),d0	;cr > uncr ??
		bmi.s	.Exit
		move.l	d1,d0
		rts

.Exit		moveq	#0,d0
		rts

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

DB_CrMData	movem.l	d2-d7/a2-a6,-(a7)
		move.l	a0,a5

		move.l	xfdbi_SourceBuffer(a5),a2
		move.l	xfdbi_UserTargetBuf(a5),a1
		MOVE.W	#XFDERR_NOMEMORY,xfdbi_Error(A5)
		move.l	(a2),d0
		addq.w	#6,a2
		move.l	(a2)+,d1
		move.l	(a2)+,d2
		cmp.l	#'ViS1',d0
		beq.b	.Normal
		cmp.w	#'M!',d0
		beq.s	.Normal
		cmp.w	#'m!',d0
		beq.s	.NormalSamp
		cmp.w	#'m2',d0
		beq.s	.HuffSamp
		cmp.l	#'mss!',d0
		beq.b	.HuffSamp

;		cmp.l	#'CD³¹',D0
;		beq.b	.Huff
;		cmp.l	#'MSS!',D0
;		beq.b	.Huff
;		cmp.l	#'Iron',D0
;		beq.b	.Huff
;		cmp.l	#'IFT?',d0
;		beq.b	.Huff
;		cmp.l	#'XPKZ',d0
;		beq.b	.Huff
;		cmp.l	#'LSD!',d0
;		beq.b	.Huff
;		cmp.l	#'ViSL',d0
;		beq.b	.Huff
;		cmp.w	#'M2',d0
;		beq.s	.Huff
		bra.s	.Huff

.Ok		moveq	#1,d0
.Exit		movem.l	(a7)+,d2-d7/a2-a6
		rts

.NormalSamp	BSR.W	D_CrM
.Samp		move.l	xfdbi_UserTargetBuf(a5),a0
		move.l	xfdbi_TargetBufSaveLen(a5),d1
		move.b	(a0)+,d0
		subq.l	#1,d1
.Add		add.b	(a0),d0
		move.b	d0,(a0)+
		subq.l	#1,d1
		bne.s	.Add
		bra.s	.Ok		

.Huff		BSR.W	D_CrMHuff_Buffer		
		BRA.B	.Exit		* Return value is set!

.HuffSamp	BSR.W	D_CrMHuff_Buffer
		TST.L	D0
		BNE.B	.Samp
		BRA.B	.Exit		* Return value is set!

.Normal		BSR.W	D_CrM		
		BRA.B	.Ok		

**************************************************

S_CrMEncData	dc.l	S_CrMLib-Xfd68KHeader
		dc.w	2
		dc.w	39
		dc.l	N_CrMEncData-Xfd68KHeader
		dc.w	XFDPFF_DATA!XFDPFF_PASSWORD!XFDPFF_RECOGLEN!XFDPFF_USERTARGET
		dc.w	80
		dc.l	RB_CrMEncData-Xfd68KHeader
		dc.l	DB_CrMEncData-Xfd68KHeader
		dc.l	SD_CrMEncData-Xfd68KHeader
		dc.l	VD_CrMData-Xfd68KHeader
		dc.w	XFDID_CrunchManiaDataEnc
		dc.w	0
		dc.l	14+4+2

N_CrMEncData	dc.b	'CrunchMania Encrypted Data',0
		even

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

RB_CrMEncData	bsr.s	SD_CrMEncData
		beq.s	.Exit
		moveq	#0,d1
		move.w	4(a0),d1	;security
		add.l	6(a0),d1
		move.l	d1,xfdrr_MinTargetLen(a1)
		move.l	6(a0),xfdrr_FinalTargetLen(a1)
		MOVEQ	#14,D1
		ADD.L	10(A0),D1
		MOVE.L	D1,xfdrr_MinSourceLen(A1)
.Exit		rts

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

SD_CrMEncData	cmp.w	#'cr',(a0)
		bne.s	.Exit

		move.w	2(a0),d0
		cmp.w	#'M!',d0
		beq.s	.Ok
		cmp.w	#'m!',d0
		beq.s	.Ok
		cmp.w	#'M2',d0
		beq.s	.Ok
		cmp.w	#'m2',d0
		bne.s	.Exit
.Ok		moveq	#1,d0
		rts

.Exit		moveq	#0,d0
		rts

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

DB_CrMEncData	movem.l	d2-d7/a2-a6,-(a7)
		move.l	a0,a5
		move.l	xfdbi_SourceBuffer(a5),a3

		lea	14(a3),a0
		add.l	10(a3),a0
		move.w	-(a0),d2
		and.w	#$fff0,d2
		move.w	#XFDERR_WRONGPASSWORD,xfdbi_Error(a5)
		move.l	xfdbi_Special(a5),d0
		beq.b	.Exit
		move.l	d0,a0
		bsr	CrM_GetPWSum
		cmp.w	d2,d0
		beq.s	.PWOk
		moveq	#0,d0
		bra.b	.Exit

.PWOk		moveq	#0,d7
		move.w	4(a3),d7	;security

		move.w	#XFDERR_NOMEMORY,xfdbi_Error(a5)

		move.l	xfdbi_UserTargetBuf(a5),a2
		lea	14(a3),a0
		move.l	xfdbi_Special(a5),a1
		move.l	10(a3),d0
		bsr	CrM_Decrypt

		move.l	a2,a1
		add.l	d7,a1
		move.w	2(a3),d0
		move.l	6(a3),d1
		move.l	10(a3),d2

		move.l	d7,-(a7)

		cmp.w	#'M!',d0
		beq.s	.Normal		
		cmp.w	#'m!',d0
		beq.s	.NormalSamp		
		cmp.w	#'M2',d0
		beq.s	.Huff		
;		cmp.w	#'m2',d0
;		beq.s	.HuffSamp		
		bra.s	.HuffSamp

.Ok		tst.l	d7
		beq.s	.NoSec
		move.l	xfdbi_UserTargetBuf(a5),a0
		move.l	a0,a1
		add.l	d7,a0
		move.l	xfdbi_TargetBufSaveLen(a5),d0
.Copy		move.b	(a0)+,(a1)+
		subq.l	#1,d0
		bne.s	.Copy

.NoSec		moveq	#1,d0
.Exit		movem.l	(a7)+,d2-d7/a2-a6
		rts

.Normal		bsr	D_CrM		
		move.l	(a7)+,d7
		bra.s	.Ok		

.NormalSamp	bsr	D_CrM		
		move.l	(a7)+,d7
.Samp		move.l	xfdbi_UserTargetBuf(a5),a0
		add.l	d7,a0
		move.l	xfdbi_TargetBufSaveLen(a5),d1
		move.b	(a0)+,d0
		subq.l	#1,d1
.Add		add.b	(a0),d0
		move.b	d0,(a0)+
		subq.l	#1,d1
		bne.s	.Add
		bra.s	.Ok		

.Huff		bsr	D_CrMHuff_Buffer
		move.l	(a7)+,d7
		TST.L	D0
		BNE.B	.Ok
		BRA.B	.Exit

.HuffSamp	bsr	D_CrMHuff_Buffer
		move.l	(a7)+,d7
		tst.l	d0
		BNE.B	.Samp
		BRA.B	.Exit		

* a0: password

CrM_GetPWSum	movem.l	d1/a0,-(a7)
		moveq	#0,d0
		moveq	#0,d1
.Next		move.b	(a0)+,d0
		beq.s	.Exit
		add.w	d0,d1
		add.w	d1,d1
		add.w	d1,d1
		bra.s	.Next
.Exit		move.l	d1,d0
		and.w	#$fff0,d0
		and.w	#$000f,d1
		lsl.w	#4,d1
		add.w	d1,d0
		movem.l	(a7)+,d1/a0
		rts

* d0: buflen
* a0: source
* a1: password
* a2: target

CrM_Decrypt	movem.l	d0-d2/a0-a4,-(a7)
		move.l	a7,a3

		lsr.l	#1,d0
		subq.l	#2,d0
		bmi.s	.Exit
		move.w	d0,d1
		swap	d0

		move.l	a1,a4
.ClearStack	clr.b	-(a3)
		tst.b	(a1)+
		bne.s	.ClearStack
		clr.b	-(a3)
		move.l	a3,d2
		btst	#0,d2
		beq.s	.StackOk
		clr.b	-(a3)
.StackOk	exg	a3,a7
		move.l	a7,a1
.CopyStack	move.b	(a4)+,(a1)+
		bne.s	.CopyStack

		move.l	a7,a1
		move.l	a1,a4
.Next		move.w	(a1),d2
		bne.s	.NoPWEnd
		move.l	a4,a1
		move.w	(a1),d2
.NoPWEnd	eor.w	d2,(a0)
		move.w	(a0)+,d2
		move.w	d2,(a2)+
		add.w	d2,(a1)+
		dbra	d1,.Next
		dbra	d0,.Next

		move.w	(a0)+,d0
		and.w	#$000f,d0
		move.w	d0,(a2)+

		move.l	a3,a7
.Exit		movem.l	(a7)+,d0-d2/a0-a4
		rts

**************************************************

S_CrMLib	dc.l	S_CrMNormal-Xfd68KHeader
		dc.w	2
		dc.w	39
		dc.l	N_CrMLib-Xfd68KHeader
		dc.w	XFDPFF_RELOC!XFDPFF_RELMODE
		dc.w	0
		dc.l	RB_CrMLib-Xfd68KHeader
		dc.l	DB_CrMLib-Xfd68KHeader
		dc.l	RS_CrMLib-Xfd68KHeader
		dc.l	DS_CrMLib-Xfd68KHeader
		dc.w	XFDID_CrunchManiaLib
		dc.w	0
		dc.l	$6c+4+4

N_CrMLib	dc.b	'CrunchMania Library',0
		even

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

RB_CrMLib	BSR	xfdCodeBeginRecog
		TST.L	D0
		BEQ.B	.Exit

		cmp.l	#$4eaeffe2,$16(a0)
		bne.s	.Exit
		cmp.l	#'CrM.',$1a(a0)
		bne.s	.Exit

		move.b	$32(a0),d0
		beq.s	.Ok
		cmp.b	#1,d0
		bne.s	.Exit

.Ok		moveq	#1,d0
		rts

.Exit		moveq	#0,d0
		rts

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

DB_CrMLib	movem.l	d2-d7/a2-a6,-(a7)
		clr.l	-(a7)		;len buffer
		clr.l	-(a7)		;reloc buffer
		move.l	a0,a5

		move.l	xfdbi_SourceBuffer(a5),a0
		move.l	8(a0),d0
		subq.l	#1,d0
		move.l	d0,d7		;# hunks 
		bsr	xfdCodeBegin

		lea	$34(a0),a3	;hunk tabelle

		move.l	-4(a0),d0
		lsl.l	#2,d0
		add.l	d0,a0
		move.l	d7,d0
		subq.l	#1,d0	;1 weniger
		lsl.l	#3,d0
		add.l	d0,a0
		move.l	a0,a4		;hunk types

		move.w	#XFDERR_BADHUNK,xfdbi_Error(a5)
		cmp.l	#$3ea,(a0)+
		bne	.Error
		addq.w	#4,a0
		move.l	a0,a2	;data ohne lens

		move.l	a3,a0
		move.w	d7,d0
		subq.w	#1,d0
		moveq	#0,d1
.SumHunks	add.l	(a0)+,d1
		dbf	d0,.SumHunks
		lsl.l	#2,d1
		move.l	-$c(a3),d0	;uncr len
		sub.l	d1,d0
		move.l	d0,d6	;laenge reloc
		move.l	d1,d5	;offset reloc
		add.l	d0,d0	;relocs alle word, deshalb * 2
		add.l	d0,d1
		move.l	d7,d0
		lsl.l	#4,d0	;header,3e9,len,3f2
		add.l	d1,d0
		add.l	#20,d0
		move.l	d0,xfdbi_TargetBufLen(a5)

		move.l	xfdbi_TargetBufMemType(a5),d1
		move.l	4.w,a6
		jsr	-198(a6)
		move.w	#XFDERR_NOMEMORY,xfdbi_Error(a5)
		move.l	d0,xfdbi_TargetBuffer(a5)
		beq	.Error

		move.l	d6,d0
		beq.s	.NoBuf
		move.l	d7,d1
		lsl.l	#2,d1
		add.l	d1,d0
		addq.l	#4,d0
		move.l	d0,d2
		move.l	#$10001,d1
		jsr	-198(a6)
		tst.l	d0
		beq	.ErrorFree
		move.l	d0,a0
		move.l	d2,(a0)+
		move.l	a0,(a7)
		add.l	d6,a0
		move.l	a0,4(a7)

.NoBuf		move.l	xfdbi_TargetBuffer(a5),a1
		move.l	d7,d0
		lsl.w	#2,d0
		lea	28(a1,d0.w),a1

		tst.b	-2(a3)			;normal/huff
		beq.s	.Normal

		movem.l	a2-a6/d5-d7,-(a7)	;huff
		move.l	-$c(a3),d1		;uncr len
		move.l	-8(a3),d2		;cr len
		bsr	D_CrMHuff_Buffer
		movem.l	(a7)+,a2-a6/d5-d7
		tst.l	d0
		bne.s	.Continue
		bra	.ErrorFree

.Normal		movem.l	a2-a4/d5-d7,-(a7)	;normal
		move.l	-$c(a3),d1		;uncr len
		move.l	-8(a3),d2		;cr len
		bsr	D_CrM
		movem.l	(a7)+,a2-a4/d5-d7

.Continue	move.l	a4,a2
		move.l	xfdbi_TargetBuffer(a5),a0
		move.l	#$3f3,(a0)+
		clr.l	(a0)+
		move.l	d7,(a0)+
		clr.l	(a0)+
		move.l	d7,d0
		subq.l	#1,d0
		move.l	d0,(a0)+
		move.l	xfdbi_SourceBuffer(a5),a1
		lea	20(a1),a1
.CopyLens	move.l	(a1)+,(a0)+
		dbf	d0,.CopyLens
		move.l	#$3e9,(a0)+
		move.l	(a3),(a0)+

		moveq	#0,d2
		move.l	(a7),d0
		beq.s	.NoReloc1
		move.l	d0,a1
		movem.l	a0/a1,-(a7)
		lea	(a0,d5.l),a0
		move.l	d6,d0
.CopyReloc	move.w	(a0)+,(a1)+
		subq.l	#2,d0
		bne.s	.CopyReloc
		movem.l	(a7)+,a0/a1

		moveq	#0,d4
		move.l	4(a7),a6
.CountReloc	move.w	d4,d0
		bsr	CrM_CountReloc
		move.l	d0,(a6)+
		add.l	d0,d2
		addq.w	#1,d4
		cmp.w	d7,d4
		bne.s	.CountReloc

.NoReloc1	move.l	xfdbi_TargetBufLen(a5),d0
		sub.l	d6,d0
		sub.l	d6,d0	;2 * wegen fiktion oben
		add.l	d2,d0
		move.l	d0,xfdbi_TargetBufSaveLen(a5)

		move.l	xfdbi_TargetBuffer(a5),a4
		add.l	d0,a4

		move.l	d7,d0
		lsl.l	#2,d0
		add.l	d0,a3

		add.l	d5,a0

; a0 - zeiger auf decr daten ende
; a1 - zeiger auf relocs
; a2 - zeiger auf hunk types ende
; a3 - zeiger auf hunklens ende
; a4 - zeiger auf buffer ende
; a6 - zeiger auf reloclens ende

.NextHunk	subq.w	#1,d7
		bmi.s	.Ready
		move.l	#$3f2,-(a4)

		subq.w	#4,a6
		tst.l	(a7)
		beq.s	.NoReloc2
		bsr	CrM_MakeReloc

.NoReloc2	tst.w	d7
		beq.s	.Ready
		subq.w	#8,a2
		cmp.w	#$3eb,2(a2)
		bne.s	.NoBSS
		move.l	-(a3),d0
		lsl.l	#2,d0
		sub.l	d0,a0
		move.l	4(a2),-(a4)
		move.l	(a2),-(a4)
		bra.s	.NextHunk

.NoBSS		move.l	-(a3),d0
		beq.s	.EmptyCode
.CopyCode	move.l	-(a0),-(a4)
		subq.l	#1,d0
		bne.s	.CopyCode
.EmptyCode	move.l	(a3),-(a4)
		move.l	(a2),-(a4)
		bra.s	.NextHunk

.Ready		moveq	#1,d0

.Exit		move.l	d0,d2
		move.l	(a7),d0
		beq.s	.Exit1
		move.l	d0,a1
		move.l	-(a1),d0
		move.l	4.w,a6
		jsr	-210(a6)
.Exit1		addq.w	#8,a7
		move.l	d2,d0
		movem.l	(a7)+,d2-d7/a2-a6
		rts

.ErrorFree	move.l	xfdbi_TargetBuffer(a5),a1
		move.l	xfdbi_TargetBufLen(a5),d0
		move.l	4.w,a6
		jsr	-210(a6)
.Error		moveq	#0,d0
		bra.s	.Exit

* a1 - reloctable
* d0 - hunknum

CrM_CountReloc	movem.l	d2/d3/a1,-(a7)
		move.w	d0,d2
		moveq	#0,d3
		moveq	#0,d1

.NextHunk	move.w	(a1)+,d0
		bmi.s	.Exit

		cmp.w	d2,d0
		beq.s	.ThisHunk

.SkipAll	move.w	(a1)+,d0
		beq.s	.NextHunk
		subq.w	#1,d0
		addq.w	#2,a1
.Skip		tst.w	(a1)+
		bne.s	.Short
		tst.l	(a1)+
.Short		dbf	d0,.Skip
		bra.s	.SkipAll

.ThisHunk	moveq	#1,d3

.CountAll	moveq	#0,d0
		move.w	(a1)+,d0
		beq.s	.NextHunk
		addq.l	#8,d1		;amount, hunk
		lsl.l	#2,d0
		add.l	d0,d1		;relocs
		lsr.l	#2,d0
		subq.w	#1,d0
		addq.w	#2,a1
.CountRelocs	tst.w	(a1)+
		bne.s	.CountShort
		tst.l	(a1)+
.CountShort	dbf	d0,.CountRelocs
		bra.s	.CountAll

.Exit		tst.b	d3
		beq.s	.Exit1
		addq.l	#8,d1
.Exit1		move.l	d1,d0
		movem.l	(a7)+,d2/d3/a1
		rts

* a1 - reloctable
* d7 - hunknum
* a6 - reloclens

CrM_MakeReloc	movem.l	a0/a1,-(a7)
		move.l	(a6),d0		;reloclen
		beq.s	.Exit
		sub.l	d0,a4
		move.l	a4,a0
		move.l	#$3ec,(a0)+

.NextHunk	move.w	(a1)+,d0
		bmi.s	.ExEnd

		cmp.w	d7,d0
		beq.s	.ExAll

.SkipAll	move.w	(a1)+,d0
		beq.s	.NextHunk
		subq.w	#1,d0
		addq.w	#2,a1
.Skip		tst.w	(a1)+
		bne.s	.Short
		tst.l	(a1)+
.Short		dbf	d0,.Skip
		bra.s	.SkipAll

.ExAll		moveq	#0,d0
		move.w	(a1)+,d0
		beq.s	.NextHunk
		move.l	d0,(a0)+
		move.w	d0,d1
		move.w	(a1)+,d0
		move.l	d0,(a0)+

		moveq	#0,d3
		subq.w	#1,d1
.Extract	moveq	#0,d0
		move.w	(a1)+,d0
		bne.s	.ShortReloc
		move.l	(a1)+,d0
.ShortReloc	add.l	d0,d0
		add.l	d0,d3
		move.l	d3,(a0)+
		dbf	d1,.Extract
		bra.s	.ExAll

.ExEnd		clr.l	(a0)+
.Exit		movem.l	(a7)+,a0/a1
		rts

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

RS_CrMLib	add.l	a0,a0
		add.l	a0,a0
		cmp.l	#$4eaeffe2,$1a(a0)
		bne.s	.Exit
		cmp.l	#'CrM.',$1e(a0)
		bne.s	.Exit
		move.b	$36(a0),d0
		beq.s	.Ok
		cmp.b	#1,d0
		bne.s	.Exit
.Ok		moveq	#1,d0
		rts

.Exit		moveq	#0,d0
		rts

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

DS_CrMLib	movem.l	d2-d7/a2-a6,-(a7)
		move.l	a0,a5
		move.l	xfdsi_SegList(a5),a4
		add.l	a4,a4
		add.l	a4,a4

		move.w	$5c-$28(a4),d6	;hunks
		moveq	#0,d0
		move.w	d6,d0
		lsl.l	#2,d0
		sub.l	d0,a7
		move.l	a7,a1
		move.l	d0,-(a7)
		lea	$60-$28(a4),a0	;hunklens
.CopyLens	move.l	(a0)+,(a1)+
		subq.l	#4,d0
		bne.s	.CopyLens

		move.b	$5e-$28(a4),d4	;huff flag
		move.b	$5f-$28(a4),d3	;reloc flag
		move.l	$54-$28(a4),d1	;uncr
		move.l	$58-$28(a4),d2	;cr
		bsr	.GetHunk
		move.l	a1,a2
		move.w	$52-$28(a4),d0
		lea	(a2,d0.w),a1

		movem.l	d3/d6/a1,-(a7)
		tst.b	d4
		beq.s	.CrM
		bsr	D_CrMHuff_Segment
		bra.s	.Cont
.CrM		bsr	D_CrM
		moveq	#1,d0
.Cont		movem.l	(a7)+,d3/d5/a6
		tst.l	d0
		beq	.Exit

		lea	xfdsi_SegList(a5),a0
		move.w	d5,d0
		move.w	xfdsi_RelMode(a5),d1
		bsr	xfdChangeHunkMemType
		move.w	d0,xfdsi_Error(a5)
		beq.s	.ChangeOk
		moveq	#0,d0
		bra.s	.Exit

.ChangeOk	move.l	xfdsi_SegList(a5),a4
		add.l	a4,a4
		add.l	a4,a4

		lea	4(a7),a2	;hunklens
		subq.w	#1,d5
		moveq	#-1,d6

.CopyNext	addq.w	#1,d6
		move.l	(a2)+,d7
		beq.s	.Len0
		bsr.s	.GetHunk
.CopyHunk	move.l	(a6)+,(a1)+
		subq.l	#1,d7
		bne.s	.CopyHunk
.Len0		dbf	d5,.CopyNext

		btst	#0,d3
		beq.s	.SkipRelocs

		move.w	d6,d3
.NoRelocs	moveq	#0,d6
		move.w	(a6)+,d6
		bmi.s	.RelocEnd
		bsr.s	.GetHunk
		move.l	a1,a2
.NextHunk	move.w	(a6)+,d7
		beq.s	.NoRelocs
		subq.w	#1,d7
		move.w	(a6)+,d6
		bsr.s	.GetHunk
		move.l	a1,d1
		move.l	a2,a3
.NextOffset	moveq	#0,d0
		move.w	(a6)+,d0
		bne.s	.Short
		move.l	(a6)+,d0
.Short		add.l	d0,d0
		add.l	d0,a3
		add.l	d1,(a3)
		dbra	d7,.NextOffset
		bra.s	.NextHunk
.RelocEnd	move.w	d3,d6

.SkipRelocs	bsr.s	.GetHunk
		move.l	-(a1),d0
		clr.l	(a1)
		lsl.l	#2,d0
		move.l	d0,a1
		move.l	-(a1),d0
		move.l	4.w,a6
		jsr	-210(a6)

		moveq	#1,d0
.Exit		add.l	(a7)+,a7
		movem.l	(a7)+,d2-d7/a2-a6
		rts

.GetHunk	move.w	d6,d0
		move.l	a4,a1
		subq.w	#1,d0
		bmi.s	.GetHunk2
.GetHunk1	move.l	(a1),a1
		add.l	a1,a1
		add.l	a1,a1
		dbf	d0,.GetHunk1
.GetHunk2	addq.w	#4,a1
		rts

**************************************************

S_CrMNormal	dc.l	S_CrMSimple-Xfd68KHeader
		dc.w	2
		dc.w	39
		dc.l	N_CrMNormal-Xfd68KHeader
		dc.w	XFDPFF_RELOC!XFDPFF_RELMODE
		dc.w	0
		dc.l	RB_CrMNormal-Xfd68KHeader
		dc.l	DB_CrMNormal-Xfd68KHeader
		dc.l	RS_CrMNormal-Xfd68KHeader
		dc.l	DS_CrMNormal-Xfd68KHeader
		dc.w	XFDID_CrunchManiaNormal
		dc.w	0
		dc.l	$1ce+6+4

N_CrMNormal	dc.b	'CrunchMania Normal',0
		even

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

RB_CrMNormal	BSR	xfdCodeBeginRecog
		TST.L	D0
		BEQ.B	.Exit

		MOVEQ	#0,D0
		cmp.l	#$4e944e91,$c(a0)
		BEQ.B	.Next
		CMP.L	#$70074E91,$C(A0)
		BNE.B	.Exit
.Next		cmp.l	#$4e942449,$10(a0)
		BEQ.B	.Type2
		CMP.L	#$4E945246,$10(A0)
		BNE.B	.Exit
		CMP.L	#$24494E94,$14(A0)
		BNE.b	.Exit
		MOVEQ	#1,D0
		RTS

.Type2		cmp.l	#$52464e94,$14(a0)
		bne.s	.Exit
		MOVEQ	#1,D0
.Exit		RTS

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

DB_CrMNormal	movem.l	d2-d7/a2-a6,-(a7)
		clr.l	-(a7)		;len buffer
		clr.l	-(a7)		;reloc buffer
		move.l	a0,a5

		move.l	xfdbi_SourceBuffer(a5),a0
		move.l	8(a0),d0
		subq.l	#2,d0
		move.l	d0,d7		;# hunks 
		bsr	xfdCodeBegin

		cmp.w	#$3c3c,4(a0)
		bne.s	.UseHunkAmount
		move.w	6(a0),d7

.UseHunkAmount	move.l	-4(a0),d0
		lsl.l	#2,d0
		add.l	d0,a0
		move.l	d7,d0
		lsl.l	#3,d0
		add.l	d0,a0
		move.l	a0,a4		;hunk types

		move.w	#XFDERR_BADHUNK,xfdbi_Error(a5)
		cmp.l	#$3e9,(a0)+
		bne	.Error		
		addq.w	#4,a0

		moveq	#1,d4
		cmp.l	#$48e7040c,$10(a0)
		beq.s	.Huff
		moveq	#0,d4

.Huff		move.w	2(a0),d0
		lea	2(a0,d0.w),a2	;decdata
		move.l	d7,d0
		lsl.w	#2,d0
		move.l	a2,a3
		sub.w	d0,a3	;hunk tabelle		

		move.l	a3,a0
		move.w	d7,d0
		subq.w	#1,d0
		moveq	#0,d1
.SumHunks	add.l	(a0)+,d1
		dbf	d0,.SumHunks
		lsl.l	#2,d1
		move.l	(a2),d0
		sub.l	d1,d0
		move.l	d0,d6	;laenge reloc
		move.l	d1,d5	;offset reloc
		add.l	d0,d0	;relocs alle word, deshalb * 2
		add.l	d0,d1
		move.l	d7,d0
		lsl.l	#4,d0	;header,3e9,len,3f2
		add.l	d1,d0
		add.l	#20,d0
		move.l	d0,xfdbi_TargetBufLen(a5)

		move.l	xfdbi_TargetBufMemType(a5),d1
		move.l	4.w,a6
		jsr	-198(a6)
		move.w	#XFDERR_NOMEMORY,xfdbi_Error(a5)
		move.l	d0,xfdbi_TargetBuffer(a5)
		beq	.Error

		move.l	d6,d0
		beq.s	.NoBuf
		move.l	d7,d1
		lsl.l	#2,d1
		add.l	d1,d0
		addq.l	#4,d0
		move.l	d0,d2
		move.l	#$10001,d1
		jsr	-198(a6)
		tst.l	d0
		beq	.ErrorFree
		move.l	d0,a0
		move.l	d2,(a0)+
		move.l	a0,(a7)
		add.l	d6,a0
		move.l	a0,4(a7)

.NoBuf		move.l	xfdbi_TargetBuffer(a5),a1
		move.l	d7,d0
		lsl.w	#2,d0
		lea	28(a1,d0.w),a1

		tst.b	d4	;normal/huff
		beq.s	.Normal

		movem.l	a2-a6/d5-d7,-(a7)	;huff
		move.l	(a2)+,d1	;uncr len
		move.l	(a2)+,d2	;cr len
		bsr	D_CrMHuff_Buffer
		movem.l	(a7)+,a2-a6/d5-d7
		tst.l	d0
		bne.s	.Continue
		bra	.ErrorFree

.Normal		movem.l	a2-a4/d5-d7,-(a7)	;normal
		move.l	(a2)+,d1	;uncr len
		move.l	(a2)+,d2	;cr len
		bsr	D_CrM
		movem.l	(a7)+,a2-a4/d5-d7

.Continue	move.l	a4,a2
		move.l	xfdbi_TargetBuffer(a5),a0
		move.l	#$3f3,(a0)+
		clr.l	(a0)+
		move.l	d7,(a0)+
		clr.l	(a0)+
		move.l	d7,d0
		subq.l	#1,d0
		move.l	d0,(a0)+
		move.l	xfdbi_SourceBuffer(a5),a1
		lea	24(a1),a1
.CopyLens	move.l	(a1)+,(a0)+
		dbf	d0,.CopyLens
		move.l	#$3e9,(a0)+
		move.l	(a3),(a0)+

		moveq	#0,d2
		move.l	(a7),d0
		beq.s	.NoReloc1
		move.l	d0,a1
		movem.l	a0/a1,-(a7)
		lea	(a0,d5.l),a0
		move.l	d6,d0
.CopyReloc	move.w	(a0)+,(a1)+
		subq.l	#2,d0
		bne.s	.CopyReloc
		movem.l	(a7)+,a0/a1

		moveq	#0,d4
		move.l	4(a7),a6
.CountReloc	move.w	d4,d0
		bsr	CrM_CountReloc
		move.l	d0,(a6)+
		add.l	d0,d2
		addq.w	#1,d4
		cmp.w	d7,d4
		bne.s	.CountReloc

.NoReloc1	move.l	xfdbi_TargetBufLen(a5),d0
		sub.l	d6,d0
		sub.l	d6,d0	;2 * wegen fiktion oben
		add.l	d2,d0
		move.l	d0,xfdbi_TargetBufSaveLen(a5)

		move.l	xfdbi_TargetBuffer(a5),a4
		add.l	d0,a4

		move.l	d7,d0
		lsl.l	#2,d0
		add.l	d0,a3

		add.l	d5,a0

; a0 - zeiger auf decr daten ende
; a1 - zeiger auf relocs
; a2 - zeiger auf hunk types ende
; a3 - zeiger auf hunklens ende
; a4 - zeiger auf buffer ende
; a6 - zeiger auf reloclens ende

.NextHunk	subq.w	#1,d7
		bmi.s	.Ready
		move.l	#$3f2,-(a4)

		subq.w	#4,a6
		tst.l	(a7)
		beq.s	.NoReloc2
		bsr	CrM_MakeReloc

.NoReloc2	tst.w	d7
		beq.s	.Ready
		subq.w	#8,a2
		cmp.w	#$3eb,2(a2)
		bne.s	.NoBSS
		move.l	-(a3),d0
		lsl.l	#2,d0
		sub.l	d0,a0
		move.l	4(a2),-(a4)
		move.l	(a2),-(a4)
		bra.s	.NextHunk

.NoBSS		move.l	-(a3),d0
		beq.s	.EmptyCode
.CopyCode	move.l	-(a0),-(a4)
		subq.l	#1,d0
		bne.s	.CopyCode
.EmptyCode	move.l	(a3),-(a4)
		move.l	(a2),-(a4)
		bra.s	.NextHunk

.Ready		moveq	#1,d0

.Exit		move.l	d0,d2
		move.l	(a7),d0
		beq.s	.Exit1
		move.l	d0,a1
		move.l	-(a1),d0
		move.l	4.w,a6
		jsr	-210(a6)
.Exit1		addq.w	#8,a7
		move.l	d2,d0
		movem.l	(a7)+,d2-d7/a2-a6
		rts

.ErrorFree	move.l	xfdbi_TargetBuffer(a5),a1
		move.l	xfdbi_TargetBufLen(a5),d0
		move.l	4.w,a6
		jsr	-210(a6)
.Error		moveq	#0,d0
		bra.s	.Exit

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

RS_CrMNormal	add.l	a0,a0
		add.l	a0,a0

		cmp.l	#($12*4)+8,-4(a0)
		beq.s	.Ok
		cmp.l	#($1c*4)+8,-4(a0)
		bne.s	.Exit

.Ok		cmp.l	#$4e944e91,$10(a0)
		bne.s	.Exit
		cmp.l	#$4e942449,$14(a0)
		bne.s	.Exit
		cmp.l	#$52464e94,$18(a0)
		bne.s	.Exit
		moveq	#1,d0
		rts

.Exit		moveq	#0,d0
		rts

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

DS_CrMNormal	movem.l	d2-d7/a2-a6,-(a7)
		move.l	a0,a5
		move.l	xfdsi_SegList(a5),a4
		add.l	a4,a4
		add.l	a4,a4
		move.w	$a(a4),d6	;hunknum

		move.l	a4,a0
		move.w	d6,d0
		move.w	xfdsi_RelMode(a5),d1
		bsr	xfdChangeHunkMemType
		move.w	d0,xfdsi_Error(a5)
		beq.s	.ChangeOk
		moveq	#0,d0
		bra	.Exit

.ChangeOk	bsr	.GetHunk
		moveq	#1,d4
		cmp.l	#$48e7040c,$10(a1)
		beq.s	.Huff
		moveq	#0,d4

.Huff		move.w	$a(a1),d0
		addq.w	#2,a1
		add.w	(a1),a1

		move.l	a1,a6
		moveq	#0,d1
		move.w	d6,d1
		lsl.l	#2,d1
		sub.l	d1,a6		;hunklens

		move.l	(a1)+,d1
		move.l	(a1)+,d2
		move.l	a1,a2
		add.w	d0,a1
		movem.l	d6/a1/a4/a6,-(a7)
		tst.b	d4
		beq.s	.CrM
		bsr	D_CrMHuff_Segment
		bra.s	.Cont
.CrM		bsr	D_CrM
		moveq	#1,d0
.Cont		movem.l	(a7)+,d5/a1/a4/a6
		tst.l	d0
		beq.s	.Exit

		move.l	a6,a2
		move.l	a1,a6
		subq.w	#1,d5
		moveq	#-1,d6

.CopyNext	addq.w	#1,d6
		move.l	(a2)+,d7
		beq.s	.Len0
		bsr.s	.GetHunk
.CopyHunk	move.l	(a6)+,(a1)+
		subq.l	#1,d7
		bne.s	.CopyHunk
.Len0		dbf	d5,.CopyNext

.NoRelocs	moveq	#0,d6
		move.w	(a6)+,d6
		bmi.s	.RelocEnd
		bsr.s	.GetHunk
		move.l	a1,a2
.NextHunk	move.w	(a6)+,d7
		beq.s	.NoRelocs
		subq.w	#1,d7
		move.w	(a6)+,d6
		bsr.s	.GetHunk
		move.l	a1,d1
		move.l	a2,a3
.NextOffset	moveq	#0,d0
		move.w	(a6)+,d0
		bne.s	.Short
		move.l	(a6)+,d0
.Short		add.l	d0,d0
		add.l	d0,a3
		add.l	d1,(a3)
		dbra	d7,.NextOffset
		bra.s	.NextHunk

.RelocEnd	move.w	$a(a4),d6	;hunknum
		subq.w	#1,d6
		bsr.s	.GetHunk
		move.l	-(a1),d0
		clr.l	(a1)
		lsl.l	#2,d0
		move.l	d0,a1
		move.l	-(a1),d0
		move.l	4.w,a6
		jsr	-210(a6)

		move.l	a4,a1
		move.l	(a4),xfdsi_SegList(a5)
		move.l	-(a1),d0
		jsr	-210(a6)

		moveq	#1,d0
.Exit		movem.l	(a7)+,d2-d7/a2-a6
		rts

.GetHunk	move.w	d6,d0
		move.l	a4,a1
.GetHunk1	move.l	(a1),a1
		add.l	a1,a1
		add.l	a1,a1
		dbf	d0,.GetHunk1
		addq.w	#4,a1
		rts

**************************************************

S_CrMSimple	dc.l	S_CrMAddr-Xfd68KHeader
		dc.w	2
		dc.w	39
		dc.l	N_CrMSimple-Xfd68KHeader
		dc.w	XFDPFF_RELOC!XFDPFF_RELMODE
		dc.w	0
		dc.l	RB_CrMSimple-Xfd68KHeader
		dc.l	DB_CrMSimple-Xfd68KHeader
		dc.l	RS_CrMSimple-Xfd68KHeader
		dc.l	DS_CrMSimple-Xfd68KHeader
		dc.w	XFDID_CrunchManiaSimple
		dc.w	0
		dc.l	$198+6+12

N_CrMSimple	dc.b	'CrunchMania Simple',0
		even

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

RB_CrMSimple	BSR	xfdCodeBeginRecog
		TST.L	D0
		BEQ.B	.Exit

		cmp.l	#$221a241a,$8(a0)
		bne.s	.Exit
		cmp.l	#$224a287a,$c(a0)
		bne.s	.Exit
		cmp.l	#$d9cc2a49,$14(a0)
		bne.s	.Exit
		cmp.l	#$30222c22,$1c(a0)
		bne.s	.Exit

		moveq	#1,d0
		rts

.Exit		moveq	#0,d0
		rts

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

DB_CrMSimple	movem.l	d2-d7/a2-a6,-(a7)
		clr.l	-(a7)		;len buffer
		clr.l	-(a7)		;reloc buffer
		move.l	a0,a5

		move.l	xfdbi_SourceBuffer(a5),a0
		move.l	8(a0),d0
		subq.l	#1,d0
		move.l	d0,d7		;# hunks 
		bsr	xfdCodeBegin

		move.w	6(a0),d0
		lea	6(a0,d0.w),a2	;decdata
		move.l	d7,d0
		lsl.w	#2,d0
		move.l	a2,a3
		sub.w	d0,a3	;hunk tabelle		
				
		move.l	a3,a0
		move.w	d7,d0
		subq.w	#1,d0
		moveq	#0,d1
.SumHunks	add.l	(a0)+,d1
		dbf	d0,.SumHunks
		lsl.l	#2,d1
		move.l	(a2),d0
		sub.l	d1,d0
		move.l	d0,d6	;laenge reloc
		move.l	d1,d5	;offset reloc
		add.l	d0,d0	;relocs alle word, deshalb * 2
		add.l	d0,d1
		move.l	d7,d0
		lsl.l	#4,d0	;header,3e9,len,3f2
		add.l	d1,d0
		add.l	#20,d0	;3f3		
		move.l	d0,xfdbi_TargetBufLen(a5)

		move.l	xfdbi_TargetBufMemType(a5),d1
		move.l	4.w,a6
		jsr	-198(a6)
		move.w	#XFDERR_NOMEMORY,xfdbi_Error(a5)
		move.l	d0,xfdbi_TargetBuffer(a5)
		beq	.Error

		move.l	d6,d0
		beq.s	.NoBuf
		move.l	d7,d1
		lsl.l	#2,d1
		add.l	d1,d0
		addq.l	#4,d0
		move.l	d0,d2
		move.l	#$10001,d1
		jsr	-198(a6)
		tst.l	d0
		beq	.ErrorFree
		move.l	d0,a0
		move.l	d2,(a0)+
		move.l	a0,(a7)
		add.l	d6,a0
		move.l	a0,4(a7)

.NoBuf		move.l	xfdbi_TargetBuffer(a5),a1
		move.l	d7,d0
		lsl.w	#2,d0
		lea	28(a1,d0.w),a1

		movem.l	a2-a4/d5-d7,-(a7)
		move.l	(a2)+,d1
		move.l	(a2)+,d2
		bsr	D_CrM
		movem.l	(a7)+,a2-a4/d5-d7

		addq.w	#4,a2
		move.l	(a2)+,d0
		addq.l	#3,d0
		and.w	#$fffc,d0
		add.l	d0,a2
		move.l	d7,d0
		lsl.w	#3,d0
		add.l	d0,a2

		move.l	xfdbi_TargetBuffer(a5),a0
		move.l	#$3f3,(a0)+
		clr.l	(a0)+
		move.l	d7,(a0)+
		clr.l	(a0)+
		move.l	d7,d0
		subq.l	#1,d0
		move.l	d0,(a0)+
		move.l	xfdbi_SourceBuffer(a5),a1
		lea	24(a1),a1
.CopyLens	move.l	(a1)+,(a0)+
		dbf	d0,.CopyLens
		move.l	#$3e9,(a0)+
		move.l	(a3),(a0)+

		moveq	#0,d2
		move.l	(a7),d0
		beq.s	.NoReloc1
		move.l	d0,a1
		movem.l	a0/a1,-(a7)
		lea	(a0,d5.l),a0
		move.l	d6,d0
.CopyReloc	move.w	(a0)+,(a1)+
		subq.l	#2,d0
		bne.s	.CopyReloc
		movem.l	(a7)+,a0/a1

		moveq	#0,d4
		move.l	4(a7),a6
.CountReloc	move.w	d4,d0
		bsr	CrM_CountReloc
		move.l	d0,(a6)+
		add.l	d0,d2
		addq.w	#1,d4
		cmp.w	d7,d4
		bne.s	.CountReloc

.NoReloc1	move.l	xfdbi_TargetBufLen(a5),d0
		sub.l	d6,d0
		sub.l	d6,d0	;2 * wegen fiktion oben
		add.l	d2,d0
		move.l	d0,xfdbi_TargetBufSaveLen(a5)

		move.l	xfdbi_TargetBuffer(a5),a4
		add.l	d0,a4

		move.l	d7,d0
		lsl.l	#2,d0
		add.l	d0,a3

		add.l	d5,a0

; a0 - zeiger auf decr daten ende
; a1 - zeiger auf relocs
; a2 - zeiger auf hunk types ende
; a3 - zeiger auf hunklens ende
; a4 - zeiger auf buffer ende
; a6 - zeiger auf reloclens ende

.NextHunk	subq.w	#1,d7
		bmi.s	.Ready
		move.l	#$3f2,-(a4)

		subq.w	#4,a6
		tst.l	(a7)
		beq.s	.NoReloc2
		bsr	CrM_MakeReloc

.NoReloc2	tst.w	d7
		beq.s	.Ready
		subq.w	#8,a2
		cmp.w	#$3eb,2(a2)
		bne.s	.NoBSS
		move.l	-(a3),d0
		lsl.l	#2,d0
		sub.l	d0,a0
		move.l	4(a2),-(a4)
		move.l	(a2),-(a4)
		bra.s	.NextHunk

.NoBSS		move.l	-(a3),d0
		beq.s	.EmptyCode
.CopyCode	move.l	-(a0),-(a4)
		subq.l	#1,d0
		bne.s	.CopyCode
.EmptyCode	move.l	(a3),-(a4)
		move.l	(a2),-(a4)
		bra.s	.NextHunk

.Ready		moveq	#1,d0

.Exit		move.l	d0,d2
		move.l	(a7),d0
		beq.s	.Exit1
		move.l	d0,a1
		move.l	-(a1),d0
		move.l	4.w,a6
		jsr	-210(a6)
.Exit1		addq.w	#8,a7
		move.l	d2,d0
		movem.l	(a7)+,d2-d7/a2-a6
		rts

.ErrorFree	move.l	xfdbi_TargetBuffer(a5),a1
		move.l	xfdbi_TargetBufLen(a5),d0
		move.l	4.w,a6
		jsr	-210(a6)
.Error		moveq	#0,d0
		bra.s	.Exit

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

RS_CrMSimple	add.l	a0,a0
		add.l	a0,a0

		cmp.l	#$221a241a,$c(a0)
		bne.s	.Exit
		cmp.l	#$224a287a,$10(a0)
		bne.s	.Exit
		cmp.l	#$d9cc2a49,$18(a0)
		bne.s	.Exit
		cmp.l	#$30222c22,$20(a0)
		bne.s	.Exit
		moveq	#1,d0
		rts

.Exit		moveq	#0,d0
		rts

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

DS_CrMSimple	movem.l	d2-d7/a2-a6,-(a7)
		move.l	a0,a5
		move.l	xfdsi_SegList(a5),a4
		add.l	a4,a4
		add.l	a4,a4

		move.l	a4,a1
		moveq	#0,d0
.CountNext	move.l	(a1),d1
		beq.s	.CountEnd
		lsl.l	#2,d1
		move.l	d1,a1
		addq.w	#1,d0
		bra.s	.CountNext
.CountEnd	move.l	a4,a0
		move.w	xfdsi_RelMode(a5),d1
		bsr	xfdChangeHunkMemType
		move.w	d0,xfdsi_Error(a5)
		beq.s	.ChangeOk
		moveq	#0,d0
		bra.b	.Exit

.ChangeOk	lea	4+6(a4),a2
		add.w	(a2),a2
		move.l	(a2)+,d1
		move.l	(a2)+,d2
		move.l	a2,a1
		movem.l	a1/a4,-(a7)
		bsr	D_CrM
		movem.l	(a7)+,a1/a4

		lea	$134-$28(a4),a2
		add.w	(a2),a2

		move.l	a1,a6
		moveq	#-1,d6

.CopyNext	addq.w	#1,d6
		move.l	(a2)+,d7
		beq.s	.Len0
		bsr.s	.GetHunk
		tst.l	d1
		beq.s	.CopyExit
.CopyHunk	move.l	(a6)+,(a1)+
		subq.l	#1,d7
		bne.s	.CopyHunk
.Len0		bra.s	.CopyNext
.CopyExit

.NoRelocs	moveq	#0,d6
		move.w	(a6)+,d6
		bmi.s	.RelocEnd
		bsr.s	.GetHunk
		move.l	a1,a2
.NextHunk	move.w	(a6)+,d7
		beq.s	.NoRelocs
		subq.w	#1,d7
		move.w	(a6)+,d6
		bsr.s	.GetHunk
		move.l	a1,d1
		move.l	a2,a3
.NextOffset	moveq	#0,d0
		move.w	(a6)+,d0
		bne.s	.Short
		move.l	(a6)+,d0
.Short		add.l	d0,d0
		add.l	d0,a3
		add.l	d1,(a3)
		dbra	d7,.NextOffset
		bra.s	.NextHunk

.RelocEnd	move.l	a4,a1
		move.l	(a4),xfdsi_SegList(a5)
		move.l	-(a1),d0
		move.l	4.w,a6
		jsr	-210(a6)

		moveq	#1,d0
.Exit		movem.l	(a7)+,d2-d7/a2-a6
		rts

.GetHunk	move.l	a4,a1
		move.w	d6,d0
.GetHunk1	move.l	(a1),d1
		beq.s	.GetHunk2
		lsl.l	#2,d1
		move.l	d1,a1
		dbf	d0,.GetHunk1
.GetHunk2	addq.w	#4,a1
		rts

**************************************************

S_CrMAddr
		IFND	XFD_LASTSLAVE
		dc.l	S_CrM_END-Xfd68KHeader
		ELSE
		dc.l	0
		ENDIF
		dc.w	2
		dc.w	39
		dc.l	N_CrMAddr-Xfd68KHeader
		dc.w	XFDPFF_ADDR
		dc.w	0
		dc.l	RB_CrMAddr-Xfd68KHeader
		dc.l	DB_CrMAddr-Xfd68KHeader
		dc.l	0
		dc.l	0
		dc.w	XFDID_CrunchManiaAddr
		dc.w	0
		dc.l	$148+14+4

N_CrMAddr	dc.b	'CrunchMania Addr',0
		even

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

RB_CrMAddr	add.w	#$20,a0

		moveq	#44-1,d0
.Next1		cmp.w	#$45fa,(a0)+
		dbeq	d0,.Next1	
		tst.w	d0
		bmi.s	.Exit

		moveq	#16-1,d0
.Next2		cmp.w	#$221a,(a0)+
		dbeq	d0,.Next2		
		tst.w	d0
		bmi.s	.Exit

		cmp.w	#$241a,(a0)+
		bne.s	.Exit

		moveq	#30-1,d0
.Next3		cmp.l	#$30222c22,(a0)
		beq.s	.Ok
		addq.w	#2,a0
		dbf	d0,.Next3
		bra.s	.Exit

.Ok		moveq	#1,d0
		rts

.Exit		moveq	#0,d0
		rts

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

DB_CrMAddr	movem.l	d2-d7/a2-a6,-(a7)
		move.l	a0,a5

		move.l	xfdbi_SourceBuffer(a5),a0
		add.w	#$20,a0
		moveq	#44-1,d0
.Next1		cmp.w	#$45fa,(a0)+				
		dbeq	d0,.Next1

		move.l	a0,a1
		add.w	(a0),a0
		moveq	#-1,d0
		cmp.w	#$4ef9,-6(a0)
		bne.s	.NoJmp
		move.l	-4(a0),d0
.NoJmp		move.l	d0,xfdbi_JmpAddress(a5)

		moveq	#13-1,d0
.Next2		cmp.w	#$43f9,(a1)+				
		dbeq	d0,.Next2
		tst.w	d0
		bmi.s	.NoAddr
		move.l	(a1)+,xfdbi_DecrAddress(a5)
		bra.s	.Start
.NoAddr		moveq	#-1,d0
		move.l	d0,xfdbi_DecrAddress(a5)

.Start		moveq	#1,d7
		moveq	#40-1,d0
.Next3		cmp.l	#$41ee049e,(a1)
		beq.s	.IsHuff
		addq.w	#2,a1
		dbf	d0,.Next3
		moveq	#0,d7

.IsHuff		move.l	a0,a2

		move.l	(a0)+,d0
		move.l	d0,xfdbi_TargetBufSaveLen(a5)
		move.l	d0,xfdbi_TargetBufLen(a5)

		move.l	xfdbi_TargetBufMemType(a5),d1
		move.l	4.w,a6
		jsr	-198(a6)
		move.w	#XFDERR_NOMEMORY,xfdbi_Error(a5)
		move.l	d0,xfdbi_TargetBuffer(a5)
		beq.s	.Exit
		
		move.l	d0,a1
		move.l	(a2)+,d1
		move.l	(a2)+,d2
		tst.w	d7
		bne.s	.Huff
		bsr.b	D_CrM	
		bra.s	.Ok

.Huff		bsr	D_CrMHuff_Buffer
		tst.l	d0
		bne.s	.Ok
		move.l	xfdbi_TargetBuffer(a5),a1
		move.l	xfdbi_TargetBufLen(a5),d0
		move.l	4.w,a6
		jsr	-210(a6)
		moveq	#0,d0
		bra.s	.Exit		

.Ok		moveq	#1,d0
.Exit		movem.l	(a7)+,d2-d7/a2-a6
		rts

;=================================================

D_CrM		moveq	#-1,d5
		move.l	a1,a4
		add.l	d1,a1
		add.l	d2,a2
		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
		moveq	#0,d4
.Decr1		bsr.s	.Decr13
		bcc.s	.Decr6
		moveq	#0,d4
.Decr2		moveq	#8,d1
		bsr	.Decr18
		move.b	d0,-(a1)
		cmp.l	a4,a1
		dbeq	d4,.Decr2
.Decr3		cmp.w	d5,d4
		beq.s	.Decr1
		rts

.Decr4		moveq	#14,d4
		moveq	#5,d1
		bsr.s	.Decr13
		bcs.s	.Decr5
		moveq	#14,d1
.Decr5		bsr.s	.Decr18
		add.w	d0,d4
		bra.s	.Decr2

.Decr6		bsr.s	.Decr13
		bcs.s	.Decr7
		moveq	#1,d1
		moveq	#1,d4
		bra.s	.Decr10

.Decr7		bsr.s	.Decr13
		bcs.s	.Decr8
		moveq	#2,d1
		moveq	#3,d4
		bra.s	.Decr10

.Decr8		bsr.s	.Decr13
		bcs.s	.Decr9
		moveq	#4,d1
		moveq	#7,d4
		bra.s	.Decr10

.Decr9		moveq	#8,d1
		moveq	#$17,d4
.Decr10		bsr.s	.Decr18
		add.w	d0,d4
		cmp.w	#$16,d4
		beq.s	.Decr4
		blt.s	.Decr11
		subq.w	#1,d4
.Decr11		bsr.s	.Decr13
		bcs.s	.Decr12
		moveq	#9,d1
		moveq	#$20,d2
		bra.s	.Decr16

.Decr12		bsr.s	.Decr13
		bcs.s	.Decr15
		moveq	#5,d1
		moveq	#0,d2
		bra.s	.Decr16

.Decr13		subq.w	#1,d7
		bne.s	.Decr14
		moveq	#$10,d7
		move.w	d6,d0
		lsr.l	#1,d6
		swap	d6
		move.w	-(a2),d6
		swap	d6
		lsr.w	#1,d0
		rts

.Decr14		lsr.l	#1,d6
		rts

.Decr15		moveq	#14,d1
		move.w	#$220,d2
.Decr16		bsr.s	.Decr18
		add.w	d2,d0
		lea	(a1,d0.w),a3
.Decr17		move.b	-(a3),-(a1)
		cmp.l	a4,a1
		dbeq	d4,.Decr17
		bra	.Decr3

.Decr18		move.w	d6,d0
		lsr.l	d1,d6
		sub.w	d1,d7
		bgt.s	.Decr19
		add.w	d3,d7
		ror.l	d7,d6
		move.w	-(a2),d6
		rol.l	d7,d6
.Decr19		add.w	d1,d1
		and.w	.Decr20(pc,d1.w),d0
.Decr20		rts

		dc.w	1
		dc.w	3
		dc.w	7
		dc.w	15
		dc.w	$1f
		dc.w	$3f
		dc.w	$7f
		dc.w	$ff
		dc.w	$1ff
		dc.w	$3ff
		dc.w	$7ff
		dc.w	$fff
		dc.w	$1fff
		dc.w	$3fff

;=================================================

D_CrMHuff_Buffer
		bsr.s	D_CrMHuff
		move.w	d0,xfdbi_Error(a5)
		beq.s	.Ok
		moveq	#0,d0
		rts
.Ok		moveq	#1,d0
		rts

D_CrMHuff_Segment
		bsr.s	D_CrMHuff
		move.w	d0,xfdsi_Error(a5)
		beq.s	.Ok
		moveq	#0,d0
		rts
.Ok		moveq	#1,d0
		rts

D_CrMHuff	movem.l	d1/d2/a1/a2,-(sp)
		move.l	#$4e0+4,d0
		move.l	#$10001,d1
		move.l	4.W,a6
		JSR	_LVOAllocMem(A6)
		movem.l	(sp)+,d1/d2/a1/a2
		tst.l	d0
		beq.s	.ErrorMem
		MOVEM.L	D0/A5/A6,-(sp)
		move.l	d0,a6
		addq.w	#2+4,a6
		bsr.s	.Decr0
		MOVEM.L	(A7)+,A1/A5/A6
		move.l	d0,-(a7)
		move.l	#$4e0+4,d0
		JSR	_LVOFreeMem(a6)
		move.l	(a7)+,d0
		beq.s	.ErrorData
		moveq	#XFDERR_OK,d0
		rts

.ErrorMem	moveq	#XFDERR_NOMEMORY,d0
		rts

.ErrorData	moveq	#XFDERR_CORRUPTEDDATA,d0
		rts

.Decr0		move.l	a1,d3
		add.l	d1,a1
		move.l	a2,-6(a6)
		add.l	d2,a2
		move.w	-(a2),d0
		move.l	-(a2),d6
		moveq	#$10,d7
		sub.w	d0,d7
		lsr.l	d7,d6
		move.w	d0,d7
.Decr1		lea	$49e(a6),a0
		moveq	#15,d2
.Decr2		clr.l	(a0)+
		dbra	d2,.Decr2
		lea	$4be(a6),a0
		lea	$9e(a6),a4
		moveq	#9,d2
		bsr	.Decr14
		lea	$49e(a6),a0
		lea	$80(a6),a4
		moveq	#4,d2
		bsr	.Decr14
		lea	$4be(a6),a3
		lea	-2(a6),a4
		bsr	.Decr18
		lea	$49e(a6),a3
		lea	$1e(a6),a4
		bsr	.Decr18
		moveq	#$10,d1
		bsr	.getbits
		move.w	d0,d5
		lea	$9e(a6),a0
		lea	-$1e(a0),a5
.Decr3		move.l	a6,a4
		bsr.s	.Decr7
		btst	#8,d0
		bne.s	.Decr6
		move.w	d0,d4
		lea	$20(a6),a4
		exg	a0,a5
		bsr.s	.Decr7
		exg	a0,a5
		move.w	d0,d1
		move.w	d0,d2
		bne.s	.Decr4
		moveq	#1,d1
		moveq	#$10,d2
.Decr4		bsr.s	.getbits
		bset	d2,d0
		lea	1(a1,d0.w),a3
.Decr5		move.b	-(a3),-(a1)
		cmp.l	d3,a1
		dbeq	d4,.Decr5
		cmp.w	#-1,d4
		bne.s	.Error
		move.b	-(a3),-(a1)
		cmp.l	d3,a1
		beq.s	.Error
		move.b	-(a3),d0
.Decr6		move.b	d0,-(a1)
		cmp.l	d3,a1
		dbeq	d5,.Decr3
		moveq	#1,d1
		bsr.s	.getbits
		beq.s	.Ok
		cmp.l	-6(a6),a2
		bcs.s	.Error
		addq.w	#1,d5
		beq	.Decr1
.Error		moveq	#0,d0
		rts
.Ok		moveq	#1,d0
		rts

.Decr7		moveq	#0,d1
.Decr8		subq.w	#1,d7
		beq.s	.Decr9
		lsr.l	#1,d6
		bra.s	.Decr10
.Decr9		moveq	#$10,d7
		move.w	d6,d0
		lsr.l	#1,d6
		swap	d6
		move.w	-(a2),d6
		swap	d6
		lsr.w	#1,d0
.Decr10		roxl.w	#1,d1
		move.w	(a4)+,d0
		cmp.w	d1,d0
		bls.s	.Decr8
		add.w	$3e(a4),d1
		add.w	d1,d1
		move.w	0(a0,d1.w),d0
		rts

.getbits	move.w	d6,d0
		lsr.l	d1,d6
		sub.w	d1,d7
		bgt.s	.getbitsmask
		add.w	#$10,d7
		ror.l	d7,d6
		move.w	-(a2),d6
		rol.l	d7,d6
.getbitsmask	add.w	d1,d1
		and.w	.masktable-2(pc,d1.w),d0
		rts

.masktable	dc.w	$0001,$0003,$0007,$000f,$001f,$003f,$007f,$00ff
		dc.w	$01ff,$03ff,$07ff,$0fff,$1fff,$3fff,$7fff,$ffff

.Decr14		movem.l	d1-d5/a3/a6,-(sp)
		lea	$4e0-2(a6),a6
		moveq	#4,d1
		bsr.s	.getbits
		move.w	d0,d5
		subq.w	#1,d5
		moveq	#0,d4
		sub.l	a3,a3
.Decr15		addq.w	#1,d4
		move.w	d4,d1
		cmp.w	d2,d1
		ble.s	.Decr16
		move.w	d2,d1
.Decr16		bsr.s	.getbits
		CMP.L	A6,A0
		BGE.B	.ErrorDecr14
		move.w	d0,(a0)+
		add.w	d0,a3
		dbra	d5,.Decr15
		move.w	a3,d5
		subq.w	#1,d5
.Decr17		move.w	d2,d1
		bsr.s	.getbits
		CMP.L	A6,A4
		BGE.B	.ErrorDecr14
		move.w	d0,(a4)+
		dbra	d5,.Decr17
		movem.l	(sp)+,d1-d5/a3/a6
		rts
.ErrorDecr14	movem.l	(sp)+,d1-d5/a3/a6
		addq.l	#4,A7		; bsr return address
		moveq	#0,d0
		rts

.Decr18		movem.l	d0-d7/a6,-(sp)
		lea	$4e0-$40-2(a6),a6
		clr.w	(a4)+
		moveq	#14,d7
		moveq	#-1,d4
		moveq	#0,d2
		moveq	#0,d3
		moveq	#1,d1
.Decr19		CMP.L	A6,A4
		BGE.B	.ErrorDecr14
		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)+
		lsl.w	#1,d2
		dbra	d7,.Decr19
		movem.l	(sp)+,d0-d7/a6
		rts
.ErrorDecr18	movem.l	(sp)+,d0-d7/a6
		addq.l	#4,A7		; bsr return address
		moveq	#0,d0
		rts

S_CrM_END

