**********************************************************
**       XFD external decruncher for Switch files       **
**       written and © 1998 by Codetapper/Action!       **
**                                                      **
**   This decrunches old files crunched by the group    **
**    Switch who trained many games around 1990. The    **
**  cruncher they seemed to use most of the time is a   **
**     standard address type, and this program will     **
**         decrunch the 2 versions I have seen.         **
**                                                      **
**          Contact me: codetapper@hotmail.com          **
**      Visit the Action HQ: http://zap.to/action/      **
**                                                      **
**           Greetings to all Action members:           **
**        Tachyon, Elp, Legionary, DJ DeCreator,        **
**                  Hoju, and Shastar!                  **
**********************************************************


SwitchMinLen	equ	$156		;Min. file length for header and data

		SECTION	SWITCH,CODE

		INCLUDE	AINCLUDE:IncDirs.i	;change this as you need it
		INCLUDE	"libraries/xfdmaster.i"

; xfdForeman structure MUST be first thing in all external decrunchers

F_XPK		moveq	#-1,d0		;security
		rts
		dc.l	XFDF_ID		;id
		dc.w	1		;version
		dc.w	0
		dc.l	0,0		;private
		dc.l	S_Switch	;first slave

		dc.b	"$VER: Switch 1.3 (25.07.1999) by Codetapper/Action!",13,10,0
		cnop	0,4

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

; xfdSlave structure: this one doesn't support segment decrunching

S_Switch	dc.l	S_SwitchAlt	;next slave
		dc.w	2		;version
		dc.w	36		;master version
		dc.l	N_Switch	;name
		dc.w	XFDPFF_ADDR	;flags
		dc.w	0
		dc.l	RB_Switch	;recog buffer
		dc.l	DB_Switch	;decrunch buffer
		dc.l	0		;recog segment
		dc.l	0		;decrunch segment
		dc.w	0,0		;slave/replace id
		dc.l	SwitchMinLen	;min. file length for header and data

N_Switch	dc.b	'Switch Cruncher',0
		even

;---------------------------------------------------------
; Recog buffer function: receives buffer + length in a0/d0
;---------------------------------------------------------
RB_Switch	cmp.l	#$41fa0134,(a0)		;lea $136(pc),a0
		bne.s	.Exit
		cmp.w	#$d1fc,4(a0)		;add.l	#xxxxxxxx,a0
		bne.s	.Exit
		cmp.w	#$43f9,10(a0)		;lea	xxxxx,a1
		bne.s	.Exit
		cmp.l	#$2460d5c9,$10(a0)	;move.l	-(a0),a2
						;add.l	a1,a2
		bne.s	.Exit
		cmp.l	#$20207203,$14(a0)	;move.l	-(a0),d0
						;moveq	#3,d1
		bne.s	.Exit
		cmp.l	#$610000fc,$18(a0)	;bsr	Dec18	;Start+$116
		bne.s	.Exit
		cmp.l	#$53414282,$116(a0)	;subq.w	#1,d1
						;clr.l	d2
		bne.s	.Exit
		cmp.l	#$51c9ffe8,$130(a0)	;dbra	d1,Dec19
		bne.s	.Exit
		cmp.w	#$4e75,$134(a0)	;rts
		bne.s	.Exit
		moveq	#1,d0
		rts

.Exit		moveq	#0,d0
		rts

;---------------------------------------------------------
; Decrunch buffer function: receives bufferinfo in a0
;---------------------------------------------------------
DB_Switch	movem.l	d2-d7/a2-a6,-(a7)
		move.l	a0,a5
		move.l	xfdbi_SourceBuffer(a5),a2

; first of all, we calculate the length of the decrunched file

		move.l	6(a2),d0	; a2 = source
		add.l	d0,a2
		move.l	#$136,d0
		add.l	d0,a2
		move.l	-(a2),d0

; now we have the desired length and allocate the buffer

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

		move.l	xfdbi_SourceBuffer(a5),a2
		move.l	12(a2),xfdbi_DecrAddress(a5);
		move.l	$108(a2),xfdbi_JmpAddress(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.b	.Exit

; let's fill the buffer

		move.l	d0,a1
		move.l	xfdbi_SourceBuffer(a5),a0
		bsr.b	D_Switch

; successful exit

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

;---------------------------------------------------------
; Switch decruncher (ripped from Puzznic, Helter Skelter
; and Rush Hour from Switch Game Pack 12)
;
; Inputs:
; a0 = Source data (originally)
; a1 = Destination address (added by Codetapper!)
;
; Returns:
; None
;---------------------------------------------------------
D_Switch
	move.l	6(a0),d0	; a0 = source, a1 = dest
	add.l	d0,a0
	move.l	#$136,d0
	add.l	d0,a0
	move.l	-(a0),a2
	add.l	a1,a2
	move.l	-(a0),d0
Dec1	moveq	#3,d1
	bsr	Dec18
	tst.b	d2
	beq.s	Dec8
	cmp.w	#7,d2
	bne.s	Dec4
	lsr.l	#1,d0
	bne.s	Dec2
	bsr	Read32bits
Dec2	bcc.s	Dec3
	moveq	#10,d1
	bsr	Dec18
	tst.w	d2
	bne.s	Dec4
	moveq	#$12,d1
	bsr	Dec18
	bra.s	Dec4

Dec3	moveq	#4,d1
	bsr	Dec18
	addq.w	#7,d2
Dec4	subq.w	#1,d2
Dec5	moveq	#7,d1
Dec6	lsr.l	#1,d0
	beq.s	Dec7
	roxl.l	#1,d3
	dbra	d1,Dec6

	move.b	d3,-(a2)
;	move.b	d3,$dff180		; In (Alt) version only!
	dbra	d2,Dec5

	bra.s	Dec8

Dec7	move.l	-(a0),d0
;	move.w	d0,$DFF180		; In normal version only!
	move	#$10,CCR
	roxr.l	#1,d0
	roxl.l	#1,d3
	dbra	d1,Dec6

	move.b	d3,-(a2)
	dbra	d2,Dec5

Dec8	cmp.l	a2,a1
	bge.b	StartGame
	moveq	#2,d1
	bsr	Dec18
	moveq	#2,d3
	moveq	#8,d1
	tst.w	d2
	beq.s	Dec16
	moveq	#4,d3
	cmp.w	#2,d2
	beq.b	Dec13
	moveq	#3,d3
	cmp.w	#1,d2
	beq.b	Dec11
	moveq	#2,d1
	bsr.b	Dec18
	cmp.w	#3,d2
	beq.s	Dec10
	cmp.w	#2,d2
	beq.s	Dec9
	addq.w	#5,d2
	move.w	d2,d3
	bra.b	Dec13

Dec9	moveq	#2,d1
	bsr.s	Dec18
	addq.w	#7,d2
	move.w	d2,d3
	bra.b	Dec13

Dec10	moveq	#8,d1
	bsr.s	Dec18
	move.w	d2,d3
	bra.b	Dec13

Dec11	moveq	#8,d1
	lsr.l	#1,d0
	bne.s	Dec12
	bsr.s	Read32bits
Dec12	bcs.s	Dec16
	moveq	#14,d1
	bra.s	Dec16

Dec13	moveq	#$10,d1
	lsr.l	#1,d0
	bne.s	Dec14
	bsr.s	Read32bits
Dec14	bcc.s	Dec16
	moveq	#8,d1
	lsr.l	#1,d0
	bne.s	Dec15
	bsr.s	Read32bits
Dec15	bcs.s	Dec16
	moveq	#12,d1
Dec16	bsr.s	Dec18
	subq.w	#1,d3
Dec17	move.b	-1(a2,d2.l),-(a2)
	dbra	d3,Dec17

	bra	Dec1

StartGame	rts	;jmp	$71000

Read32bits	move.l	-(a0),d0
	move	#$10,CCR
	roxr.l	#1,d0
	rts

Dec18	subq.w	#1,d1
	clr.l	d2
Dec19	lsr.l	#1,d0
	beq.s	Dec20
	roxl.l	#1,d2
	dbra	d1,Dec19

	rts

Dec20	move.l	-(a0),d0
	move	#$10,CCR
	roxr.l	#1,d0
	roxl.l	#1,d2
	dbra	d1,Dec19

	rts

	even

;---------------------------------------------------------
; Switch alternate decruncher (ripped from Sword and the
; Rose and Scrabble from Switch Game Pack 12)
;
; Inputs:
; a0 = Source data (originally)
; a1 = Destination address (added by Codetapper!)
;
; Returns:
; None
;---------------------------------------------------------
D_SwitchAlt
	;lea	SwitchAltData(pc),a3
	move.l	a0,a3		; Codetapper
	add.w	2(a0),a3		; modified
	addq.w	#2,a3		; this!

	move.l	a3,d0
	move.l	8(a3),d1	; d1 = Length of crunched data
	;lea	ActualAltData(pc),a0
	move.l	a0,a4		; Codetapper
	add.w	$c(a0),a4		; modified
	add.w	#$c,a4		; this
	move.l	a4,a0		; bit!

	add.l	d1,a0		; a0 = End of crunched data
	;move.l	4(a3),a1		; a1 already points to destination
	move.l	-(a0),a2
	add.l	a1,a2
	move.l	-(a0),d0
.Dec1	moveq	#3,d1
	bsr	.Dec19
	tst.b	d2
	beq.s	.Dec8
	cmp.w	#7,d2
	bne.s	.Dec4
	lsr.l	#1,d0
	bne.s	.Dec2
	bsr	.Read32bits
.Dec2	bcc.b	.Dec3
	moveq	#10,d1
	bsr	.Dec19
	tst.w	d2
	bne.s	.Dec4
	moveq	#$12,d1
	bsr	.Dec19
	bra.s	.Dec4

.Dec3	moveq	#4,d1
	bsr	.Dec19
	addq.w	#7,d2
.Dec4	subq.w	#1,d2
.Dec5	moveq	#7,d1
.Dec6	lsr.l	#1,d0
	beq.b	.Dec7
	roxl.l	#1,d3
	dbra	d1,.Dec6

	move.b	d3,-(a2)
	;move.b	d3,$DFF180
	dbra	d2,.Dec5

	bra.s	.Dec8

.Dec7	move.l	-(a0),d0
	move	#$10,CCR
	roxr.l	#1,d0
	roxl.l	#1,d3
	dbra	d1,.Dec6

	move.b	d3,-(a2)
	dbra	d2,.Dec5

.Dec8	cmp.l	a2,a1
	bge.b	.StartGame
	moveq	#2,d1
	bsr	.Dec19
	moveq	#2,d3
	moveq	#8,d1
	tst.w	d2
	beq.s	.Dec16
	moveq	#4,d3
	cmp.w	#2,d2
	beq.s	.Dec13
	moveq	#3,d3
	cmp.w	#1,d2
	beq.s	.Dec11
	moveq	#2,d1
	bsr.b	.Dec19
	cmp.w	#3,d2
	beq.s	.Dec10
	cmp.w	#2,d2
	beq.s	.Dec9
	addq.w	#5,d2
	move.w	d2,d3
	bra.s	.Dec13

.Dec9	moveq	#2,d1
	bsr.s	.Dec19
	addq.w	#7,d2
	move.w	d2,d3
	bra.s	.Dec13

.Dec10	moveq	#8,d1
	bsr.s	.Dec19
	move.w	d2,d3
	bra.s	.Dec13

.Dec11	moveq	#8,d1
	lsr.l	#1,d0
	bne.s	.Dec12
	bsr.s	.Read32bits
.Dec12	bcs.s	.Dec16
	moveq	#14,d1
	bra.s	.Dec16

.Dec13	moveq	#$10,d1
	lsr.l	#1,d0
	bne.s	.Dec14
	bsr.s	.Read32bits
.Dec14	bcc.s	.Dec16
	moveq	#8,d1
	lsr.l	#1,d0
	bne.s	.Dec15
	bsr.s	.Read32bits
.Dec15	bcs.s	.Dec16
	moveq	#12,d1
.Dec16	bsr.s	.Dec19
	subq.w	#1,d3
.Dec17	move.b	-1(a2,d2.l),-(a2)
	dbra	d3,.Dec17

	bra	.Dec1

.StartGame	rts	;jmp	$75000

.Read32bits	move.l	-(a0),d0
	move	#$10,CCR
	roxr.l	#1,d0
	rts

.Dec18	move.l	-(a0),d0
	move	#$10,CCR
	roxr.l	#1,d0
	roxl.l	#1,d2
	dbra	d1,.Dec20

	rts

.Dec19	subq.w	#1,d1
	clr.l	d2
.Dec20	lsr.l	#1,d0
	beq.s	.Dec18
	roxl.l	#1,d2
	dbra	d1,.Dec20

	rts

;SwitchAltData
;	dc.l	$40624
;	dc.l	$20000
;	dc.l	$2EAD4
;ActualAltData
;	dc.l	$61BE4FF
;	dc.l	$E599A04E
;	dc.l	$51571861

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

S_SwitchAlt
	dc.l	0		;next slave
	dc.w	2		;version
	dc.w	36		;master version
	dc.l	N_SwitchAlt	;name
	dc.w	XFDPFF_ADDR	;flags
	dc.w	0
	dc.l	RB_SwitchAlt	;recog buffer
	dc.l	DB_SwitchAlt	;decrunch buffer
	dc.l	0		;recog segment
	dc.l	0		;decrunch segment
	dc.w	0,0		;slave/replace id
	dc.l	SwitchMinLen    ;min. file length for header and data

N_SwitchAlt
	dc.b	'Switch Cruncher Alternate',0
	even

;---------------------------------------------------------
; Recog buffer function: receives buffer + length in a0/d0
;---------------------------------------------------------
RB_SwitchAlt	cmp.l	#$47fa0132,(a0)		;lea	$134(pc),a3
		bne.s	.Exit
		cmp.l	#$200b222b,4(a0)	;move.l	a3,d0
						;move.l	8(a3),d1
		bne.s	.Exit
		cmp.l	#$841fa,8(a0)		;lea	$140(pc),a0
		bne.s	.Exit
		cmp.l	#$0134d1c1,12(a0)	;add.l	d1,a0
		bne.s	.Exit
		cmp.l	#$226b0004,$10(a0)	;move.l	4(a3),a1
		bne.s	.Exit
		cmp.l	#$2460d5c9,$14(a0)	;move.l	-(a0),a2
						;add.l	a1,a2
		bne.s	.Exit
		cmp.l	#$61000106,$1c(a0)	;bsr	Dec18	;Start+$124
		bne.s	.Exit
		cmp.l	#$53414282,$124(a0)	;subq.w	#1,d1
						;clr.l	d2
		bne.s	.Exit
		cmp.l	#$51c9fff8,$12e(a0)	;dbra	d1,Dec19
		bne.s	.Exit
		cmp.w	#$4e75,$132(a0)		;rts
		bne.s	.Exit
		moveq	#1,d0
		rts

.Exit		moveq	#0,d0
		rts

;---------------------------------------------------------
; Decrunch buffer function: receives bufferinfo in a0
;---------------------------------------------------------
DB_SwitchAlt	movem.l	d2-d7/a2-a6,-(a7)
		move.l	a0,a5
		move.l	xfdbi_SourceBuffer(a5),a2

; first of all, we calculate the length of the decrunched file

		move.l	a2,a3
		add.w	2(a2),a3
		addq.w	#2,a3		; a3 = Pointer to load/jump/length

		move.l	8(a3),d1	; d1 = Length of crunched data

		move.l	a3,a4
		addq	#8,a4
		add.l	d1,a4
		move.l	(a4),d0		; d0 = Length of decrunched data

; now we have the desired length and allocate the buffer

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

		move.l	xfdbi_SourceBuffer(a5),a2
		move.l	4(a3),xfdbi_DecrAddress(a5);
		move.l	$106(a2),xfdbi_JmpAddress(a5);

		move.l	xfdbi_TargetBufLen(a5),d0
		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.b	.Exit

; let's fill the buffer

		move.l	xfdbi_SourceBuffer(a5),a0
		move.l	xfdbi_TargetBuffer(a5),a1
		bsr	D_SwitchAlt

; successful exit

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

	END
