**********************************************************
**     XFD external decruncher for Il Scuro/Defjam!     **
**       written and © 1998 by Codetapper/Action!       **
**                                                      **
**    This decrunches old games crunched by Il Scuro    **
**    of Defjam. The cruncher used has a bytekiller     **
**      type address cruncher followed by a (lame)      **
**    run length encoded variant. I've called it the    **
**     $B2 RLE decruncher as the RLE flag is a byte     **
**                   encoded as $b2.                    **
**                                                      **
**    Files packed with this often require a little     **
**    disassembling to setup intena/intreq and very     **
**       occasionally a hunk of memory is further       **
**    encrypted. You'll have to disasseble the main     **
**              program to check for this.              **
**                                                      **
**     This was the case with Army Moves and a few      **
**                 other older cracks.                  **
**                                                      **
**      Detection is based on finding all cruncher      **
**    sections (main cruncher, $b2 RLE, jump address    **
**      info and the long 'PROG' before the data).      **
**     Sometimes it will not detect it (Arkanoid 2)     **
**     due to different ordering and the load/jump      **
**   addresses in weird locations.  You'll just have    **
**            to disassemble these yourself!            **
**                                                      **
**          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!                  **
**********************************************************

		INCLUDE	AINCLUDE:IncDirs.i

IlScuroMinLen	equ	$1000		;Just a guess!

		SECTION	SWITCH,CODE
		INCLUDE	"libraries/xfdmaster.i"

; xfdForeman structure MUST be first thing in all external decrunchers

Forman		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_IlScuro	;first slave

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

;---------------------------------------------------------
; Files packed by Il Scuro/Defjam.
;
; Decruncher is the same, and "PROG" is located just
; before the crunched data. This is sometimes moved
; around or encrypted over itself. Then it is often
; RLE data so a further decrunch is required!
;---------------------------------------------------------
; xfdSlave structure

S_IlScuro
	dc.l	0		;next slave
	dc.w	2		;version
	dc.w	36		;master version
	dc.l	N_IlScuro	;name
	dc.w	XFDPFF_ADDR	;flags
	dc.w	0
	dc.l	RB_IlScuro	;recog buffer
	dc.l	DB_IlScuro	;decrunch buffer
	dc.l	0		;recog segment
	dc.l	0		;decrunch segment
	dc.w	0,0		;slave/replace id
	dc.l	IlScuroMinLen	;min. file length for header and data

N_IlScuro
	dc.b	'Il Scuro/Defjam Compacted',0
	even

;---------------------------------------------------------
; Recog buffer function: receives buffer + length in a0/d0
;
; Returns:
; d0 = 1 if Il Scuro file, 0 if not!
; d2 = Offset into file for crunched data
; d3 = RLE destination address
; d4 = Jump address
; d5 = Destination address
; d6 = Crunched RLE length
;---------------------------------------------------------

RB_IlScuro	MOVE.L	D7,-(A7)
		MOVE.L	D0,D7
		BEQ.B	.SkipSave1
		MOVEM.L	D2-D6,-(A7)
.SkipSave1
	move.l	a0,a1		;a1 = Start of file
.1	move.l	a0,d1
	sub.l	a1,d1
	cmp.l	#IlScuroMinLen,d1
	bgt	.NoIlScuro	;Too far into file for a match so quit!
	cmp.w	#$41fa,(a0)+	;lea PackedData(pc),a0
	bne.b	.1
	move.l	a0,d1
	sub.l	a1,d1
	moveq	#0,d2
	move.w	(a0)+,d2	;d2 = Offset into file for crunched data
	add.l	d1,d2
	cmp.w	#$d1fc,(a0)+	;add.l	#$CrunchedLength,a0
	bne.b	.1
	move.l	(a0)+,d1
	add.l	d1,d2		;This cruncher expects data at the end!
	cmp.w	#$43f9,(a0)+	;lea	#$DestinationAddress,a1
	bne.b	.1
	move.l	(a0)+,d3	;d3 = RLE destination address
	cmp.w	#$2460,(a0)+	;move.l	-(a0),a2
	bne.b	.1
	cmp.w	#$d5c9,(a0)+	;add.l	a1,a2
	bne.b	.1
	cmp.w	#$4aa0,(a0)+	;tst.l	-(a0)
	bne.b	.1
	cmp.w	#$2020,(a0)+	;move.l	-(a0),d0
	bne.b	.1

; Check for the second part of the decruncher, which has some
; optional screen flashing before it.

.2	move.l	a0,d1
	sub.l	a1,d1
	cmp.l	#IlScuroMinLen,d1
	bgt	.NoIlScuro	;Too far into file for a match so quit!

	cmp.w	#$7203,(a0)+	;moveq	#3,d1
	bne.b	.2
	cmp.w	#$6100,(a0)+	;bsr	IlDec20
	bne.b	.2

; Now check for the RLE decoder.

.3	move.l	a0,d1
	sub.l	a1,d1
	cmp.l	#IlScuroMinLen,d1
	bgt.b	.NoIlScuro	;Too far into file for a match so quit!
	cmp.w	#$4ef9,(a0)+	;jmp StartAddress
	bne.b	.3
	move.l	(a0)+,d4	;d4 = Jump address
	cmp.w	#$45f9,(a0)+	;lea $RLECrunchedAddress,a2
	bne.b	.3
	addq	#4,a0
	cmp.w	#$47f9,(a0)+	;lea $DestinationAddress,a3
	bne.b	.3
	move.l	(a0)+,d5	;d5 = Destination address
	cmp.l	#$c1200b2,(a0)+	;cmp.b	#$B2,(a2)
	bne.b	.3
	cmp.l	#$67000008,(a0)+	;beq	B2Found
	bne.b	.3
	cmp.w	#$16da,(a0)+	;move.b	(a2)+,(a3)+
	bne.b	.3
	cmp.l	#$6000fff4,(a0)+	;bra	CheckRLE
	bne.b	.3
	cmp.w	#$528a,(a0)+	;addq.l	#1,a2
	bne.b	.3
	cmp.l	#$c120001,(a0)+	;cmp.b	#1,(a2)
	bne.b	.3
	cmp.l	#$66000004,(a0)+	;bne	CheckJustB2
	bne.b	.3
	cmp.w	#$4e75,(a0)+	;rts
	bne.b	.3
	cmp.l	#$c120000,(a0)+	;cmp.b	#0,(a2)
	bne.b	.3

; Now for the final check, locate "PROG" in the data.

.4	move.l	a0,d1
	sub.l	a1,d1
	cmp.l	#IlScuroMinLen,d1
	bgt.b	.NoIlScuro	;Too far into file for a match so quit!
	cmp.w	#'PR',(a0)+	;Search for 'PROG'
	bne.b	.4
	cmp.w	#'OG',(a0)+
	bne.b	.4

	moveq	#1,d0		;We'll quit here, it matches!
	bra.b	.end

.NoIlScuro
	moveq	#0,d0		;No match for this data.
.end		TST.L	D7
		BEQ.B	.SkipSave2
		MOVEM.L	(A7)+,D2-D6
.SkipSave2	MOVE.L	(A7)+,D7
		RTS

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

; It's impossible to calculate the correct decrunched 
; length without actually passing through the file
; twice. We'll just allocate the full 512k of his old
; cracks. In about 20 games I've never seen one which
; was more than 512k so this should be OK.

	move.l	#$80000,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.b	.Exit

; Let's fill the buffer!

	move.l	xfdbi_SourceBuffer(a5),a0
	CLR.L	D0	* indicate to ignore register saves!
	BSR	RB_IlScuro	; d2 = Offset into file for crunched data
				; d3 = RLE destination address
				; d4 = Jump address
				; d5 = Destination address
				; d6 = Crunched RLE length
	tst.l	d0
	beq.b	.Exit

	move.l	d5,xfdbi_DecrAddress(a5)
	move.l	d4,xfdbi_JmpAddress(a5)

	move.l	xfdbi_SourceBuffer(a5),a0
	add.l	d2,a0

	move.l	xfdbi_TargetBuffer(a5),a1
	add.l	d3,a1

; Unpack the data (from a0 to a1)

	bsr.b	D_IlScuro

; Unpack the $B2 RLE data (from a2 to a3)

	move.l	xfdbi_TargetBuffer(a5),a3
	move.l	a1,a2
	bsr	B2RLEDecode
	move.l	d0,xfdbi_TargetBufSaveLen(a5)

; Successful exit

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

;---------------------------------------------------------
; Actual IlScuro decruncher
;
; Inputs:
; a0 = END of packed data
; a1 = Destination address
;
; Outputs:
; d0 = Uncrunched length. All other registers preserved.
;---------------------------------------------------------
D_IlScuro
	movem.l	a0-a6,-(a7)
;	lea	PackedData(pc),a0	; Original source
;	add.l	#$2A0F4,a0		; a0 = End of source
;	lea	$3DE24,a1		; a1 = Destination address
	move.l	-(a0),a2
	add.l	a1,a2
	tst.l	-(a0)
	move.l	-(a0),d0
IlDec1	;move.w	a2,$DFF180
	moveq	#3,d1
	bsr	IlDec20
	tst.w	d2
	beq.s	IlDec8
	cmp.w	#7,d2
	bne.s	IlDec4
	lsr.l	#1,d0
	bne.s	IlDec2
	bsr	IlDec19
IlDec2	bcc.s	IlDec3
	moveq	#10,d1
	bsr	IlDec20
	tst.w	d2
	bne.s	IlDec4
	moveq	#$12,d1
	bsr	IlDec20
	bra.s	IlDec4

IlDec3	moveq	#4,d1
	bsr	IlDec20
	addq.w	#7,d2
IlDec4	subq.w	#1,d2
IlDec5	moveq	#7,d1
IlDec6	lsr.l	#1,d0
	beq.s	IlDec7
	roxl.l	#1,d3
	dbra	d1,IlDec6

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

	bra.s	IlDec8

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

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

IlDec8	cmp.l	a2,a1
	bge.s	IlDec18
	moveq	#2,d1
	bsr	IlDec20
	moveq	#2,d3
	moveq	#8,d1
	tst.w	d2
	beq.s	IlDec16
	moveq	#4,d3
	cmp.w	#2,d2
	beq.s	IlDec13
	moveq	#3,d3
	cmp.w	#1,d2
	beq.s	IlDec11
	moveq	#2,d1
	bsr.s	IlDec20
	cmp.w	#3,d2
	beq.s	IlDec10
	cmp.w	#2,d2
	beq.s	IlDec9
	addq.w	#5,d2
	move.w	d2,d3
	bra.s	IlDec13

IlDec9	moveq	#2,d1
	bsr.s	IlDec20
	addq.w	#7,d2
	move.w	d2,d3
	bra.s	IlDec13

IlDec10	moveq	#8,d1
	bsr.s	IlDec20
	move.w	d2,d3
	bra.s	IlDec13

IlDec11	moveq	#8,d1
	lsr.l	#1,d0
	bne.s	IlDec12
	bsr.s	IlDec19
IlDec12	bcs.s	IlDec16
	moveq	#14,d1
	bra.s	IlDec16

IlDec13	moveq	#$10,d1
	lsr.l	#1,d0
	bne.s	IlDec14
	bsr.s	IlDec19
IlDec14	bcc.s	IlDec16
	moveq	#8,d1
	lsr.l	#1,d0
	bne.s	IlDec15
	bsr.s	IlDec19
IlDec15	bcs.s	IlDec16
	moveq	#12,d1
IlDec16	bsr.s	IlDec20
	subq.w	#1,d3
IlDec17	move.b	-1(a2,d2.l),-(a2)
	dbra	d3,IlDec17

	cmp.l	a2,a1
	blt	IlDec1
IlDec18	movem.l	(a7)+,a0-a6
	rts

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

IlDec20	subq.w	#1,d1
	clr.l	d2
IlDec21	lsr.l	#1,d0
	beq.s	IlDec22
	roxl.l	#1,d2
	dbra	d1,IlDec21

	rts

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

	rts

;---------------------------------------------------------
; $B2 RLE Decoder as used by Il Scuro/Defjam
;
; Inputs:
; a2 = Source address
; a3 = Destination address
;
; Outputs:
; d0 = Uncrunched length. All other registers preserved.
;---------------------------------------------------------

B2RLEDecode
	movem.l	d7/a2-a3,-(a7)
CheckRLE
	cmp.b	#$b2,(a2)
	beq.b	B2Found
	move.b	(a2)+,(a3)+
	bra.b	CheckRLE

B2Found	addq.l	#1,a2
	cmp.b	#1,(a2)
	bne.b	CheckJustB2

	move.l	a3,d0		;a3 = End of unpacked data
	movem.l	(a7)+,d7/a2-a3
	sub.l	a3,d0
;	subq	#1,d0		;d0 = Uncrunched length
	rts

CheckJustB2	tst.b	(a2)
	bne.b	CopyXBytes
	move.b	#$b2,(a3)+
	addq.l	#1,a2
	bra.b	CheckRLE

CopyXBytes	move.b	(a2)+,d7
CopyLoop	move.b	(a2),(a3)+
	subq.b	#1,d7
	bne.b	CopyLoop
	addq.l	#1,a2
	bra.b	CheckRLE

	END
