********************************************************
**        XFD external decruncher for TUC 1.16        **
**               © 1998 by Georg Hörmann              **
********************************************************
**
** 1.0	- Initial release.
** 1.1	- Added support for data files.
**	- Added support for address files.
**

		OUTPUT	"LIBS:xfd/TUC"

		SECTION	TUC,CODE

		INCDIR	"dh0:Include_Asm"
		INCLUDE	"dh0:xfd/xfdmaster.i"

F_TUC		moveq	#-1,d0
		rts
		dc.l	XFDF_ID
		dc.w	1
		dc.w	0
		dc.l	0,0
		dc.l	S_TUC

		dc.b	"$VER: xfd_TUC_1.16 1.1 (13.12.98) © 1998 Georg Hörmann",0
		cnop	0,4

********************************************************
*
* Reloc files will always be restored to their original
* appearance.
*
* Address files will be treated as follows:
* a. If more than 1 hunk, a reloc file will be created.
*    The first hunk gets the MEM_TYPE of the decrunch
*    address.
* b. If 1 hunk with reloc information, same as a.
* c. If 1 hunk without reloc information, it could be
*    a relocated image and therefore gets a small
*    header in front that copies it to the decrunch
*    address. Only such files support the "Rückwärts"
*    option.
*

S_TUC		dc.l	S_TUCData
		dc.w	2
		dc.w	36
		dc.l	N_TUC
		dc.w	XFDPFF_RELOC
		dc.w	0
		dc.l	RB_TUC
		dc.l	DB_TUC
		dc.l	0
		dc.l	0
		dc.w	0
		dc.w	0
		dc.l	$1c8+4+12

N_TUC		dc.b	'TUC 1.16',0
		even

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

RB_TUC		cmp.l	#$3f3,(a0)
		bne.s	.Exit
		move.l	8(a0),d1
		lsl.w	#2,d1
		lea	20+4(a0,d1.w),a0
		cmp.l	#$55,(a0)+		;header length
		bne.s	.Exit
		cmp.l	#$7e001e1d,$36-$2c(a0)
		bne.s	.Exit
		cmp.l	#$48471e1d,$3a-$2c(a0)
		bne.s	.Exit
		cmp.l	#$49f50000,$4c-$2c(a0)
		bne.s	.Exit
		cmp.l	#$bd834846,$5a-$2c(a0)
		bne.s	.Exit
		moveq	#1,d0
		rts
.Exit		moveq	#0,d0
		rts

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

TUC_BSS		SET	xfdBufferInfo_SIZE
TUC_CrunchedData SET	xfdBufferInfo_SIZE+4
TUC_CountSize	SET	xfdBufferInfo_SIZE+8
TUC_CountStruct	SET	xfdBufferInfo_SIZE+12
TUC_EorValue	SET	xfdBufferInfo_SIZE+16
TUC_Mode	SET	xfdBufferInfo_SIZE+20	;1=reloc, 0=addr, -1=image
TUC_Back	SET	xfdBufferInfo_SIZE+21
TUC_JmpAddr	SET	xfdBufferInfo_SIZE+22
TUC_DecAddr	SET	xfdBufferInfo_SIZE+26
TUC_SIZE	SET	xfdBufferInfo_SIZE+30

DB_TUC		movem.l	d2-d7/a2-a6,-(a7)
		sub.w	#TUC_SIZE,a7
		move.l	a7,a5
		move.l	a0,-(a7)	;bufferinfo
		move.l	a5,a1
		moveq	#xfdBufferInfo_SIZE-1,d1
.CopyBI1	move.b	(a0)+,(a1)+
		dbf	d1,.CopyBI1

* get some addresses and sizes

		move.l	xfdbi_SourceBuffer(a5),a0
		move.l	8(a0),d1

		move.l	d1,d0
		lsl.l	#2,d0
		lea	20(a0,d0.w),a0		;start of code hunk

		move.l	$40-$24(a0),d0
		eor.l	#"rich",d0
		move.l	d0,TUC_EorValue(a5)
		move.l	$160-$24(a0),TUC_JmpAddr(a5)

		sf	TUC_Mode(a5)
		cmp.w	#$2094,$158-$24(a0)	;only used by reloc mode
		bne.s	.Mode_Ok
		move.b	#1,TUC_Mode(a5)		;reloc

.Mode_Ok	sf	TUC_Back(a5)
		cmp.w	#$4480,$110-$24(a0)	;forward mode
		beq.s	.Back_Ok
		st	TUC_Back(a5)

.Back_Ok	move.l	4(a0),d0
		lsl.l	#2,d0
		lea	8+24(a0,d0.l),a0	;end of code+reloc hunk
		move.l	a0,TUC_BSS(a5)

		move.l	d1,d0
		subq.w	#2,d0		;amount of bss hunks
		mulu	#12,d0
		lea	8(a0,d0.l),a0		;start of crunched data
		move.l	a0,TUC_CrunchedData(a5)

		moveq	#0,d0
		move.b	1(a0),d0		;amount hunks
		move.l	d0,d7		;amount of hunks

		moveq	#1,d2
		add.w	d0,d2
		lsl.l	#2,d2
		move.l	d2,TUC_CountSize(a5)
		mulu	d0,d2		;length of CountStructs

		addq.l	#4,d2		;for length
		move.l	d2,d0
		move.l	#$10001,d1
		move.l	4.w,a6
		jsr	-198(a6)
		move.w	#XFDERR_NOMEMORY,xfdbi_Error(a5)
		tst.l	d0
		beq	.Exit
		move.l	d0,a0
		move.l	d2,(a0)+
		move.l	a0,TUC_CountStruct(a5)

		move.l	d7,-(a7)
		bsr	TUC_Count
		move.l	(a7)+,d7
		move.w	#XFDERR_CORRUPTEDDATA,xfdbi_Error(a5)
		tst.w	d0
		beq	.ExitFree

* calculate length of final file

		move.l	TUC_CountStruct(a5),a3
		moveq	#20,d0		;3f3,0,x,0,x-1
		move.l	d7,d1
		lsl.l	#4,d1
		add.l	d1,d0		;header,3e9/a/b,len,3f2

		move.w	d7,d3
.CalcNext	move.l	(a3),d1		;is BSS ??
		beq.s	.SkipReloc
		add.l	d1,d0		;hunklen

		move.w	d7,d2
		moveq	#0,d4
		moveq	#0,d5		;3ec flag
.TestNextReloc	move.l	4(a3,d4.w),d1
		beq.s	.NoReloc
		tst.w	d5
		bne.s	.Skip3ec
		addq.l	#8,d0		;3ec, 0 am ende
		moveq	#1,d5
.Skip3ec	addq.l	#8,d0		;x,hunk #
		lsl.l	#2,d1
		add.l	d1,d0		;offsets
.NoReloc	addq.w	#4,d4
		subq.w	#1,d2
		bne.s	.TestNextReloc

.SkipReloc	add.l	TUC_CountSize(a5),a3
		subq.w	#1,d3
		bne.s	.CalcNext

		tst.b	TUC_Mode(a5)	;reloc, mode=1
		beq.s	.Test_Addr
		move.l	TUC_DecAddr(a5),d1	;really reloc or just no JmpAddr?
		beq.s	.Mode_Ok2
		move.l	d1,TUC_JmpAddr(a5)
		sf	TUC_Mode(a5)
.Test_Addr	cmp.w	#1,d7		;more than 1 hunk, mode=0
		bne.s	.Mode_Ok2
		move.l	TUC_CountStruct(a5),a0
		tst.l	4(a0)		;one hunk, but with relocs, mode=0
		bne.s	.Mode_Ok2
		st	TUC_Mode(a5)	;image, mode=-1
		add.l	#TUCAddr_End-TUCAddr_Start,d0

.Mode_Ok2	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	.ExitFree

* prepare allocated buffer

		move.l	d0,a1
		move.l	#$3f3,(a1)+
		clr.l	(a1)+
		move.l	d7,(a1)+
		clr.l	(a1)+
		move.l	d7,d0
		subq.l	#1,d0
		move.l	d0,(a1)+

		move.l	TUC_CountStruct(a5),a3

		move.l	xfdbi_SourceBuffer(a5),a0
		add.w	#20+4,a0
		move.w	d7,d0
		cmp.b	#1,TUC_Mode(a5)		;if reloc, just copy header
		beq.s	.CopyHunkHeader
		move.l	(a3),d1			;else, use coded hunklen
		tst.b	TUC_Mode(a5)
		beq.s	.NoImage
		add.l	#TUCAddr_End-TUCAddr_Start,d1
.NoImage	lsr.l	#2,d1
		tst.b	TUC_Mode(a5)		;get MEM_TYPE
		bmi.s	.NoMemType
		movem.l	d0/d1/a0/a1,-(a7)
		move.l	TUC_DecAddr(a5),a1
		jsr	-534(a6)	;typeofmem
		move.l	d0,d2
		movem.l	(a7)+,d0/d1/a0/a1
		beq.s	.NoMemType
		and.w	#$0002,d2
		beq.s	.NoMemType
		or.l	#$40000000,d1
.NoMemType	move.l	d1,(a1)+
		bra.s	.SkipHunkHeader
.CopyHunkHeader	move.l	(a0)+,(a1)+
.SkipHunkHeader	subq.w	#1,d0
		bne.s	.CopyHunkHeader

		move.l	TUC_BSS(a5),a2
		addq.w	#4,a2
		moveq	#0,d6		;flag for bss

		move.w	d7,d0
.PrepareHunks	tst.l	(a3)
		beq	.BSS
		move.l	#$3e9,(a1)+

		cmp.b	#1,TUC_Mode(a5)
		beq.s	.UseBSS
		tst.w	d6
		bne.s	.UseBSS
		move.l	(a3),d1
		tst.b	TUC_Mode(a5)
		beq.s	.NoImage2
		add.l	#TUCAddr_End-TUCAddr_Start,d1
.NoImage2	lsr.l	#2,d1
		subq.w	#8,a2		;correct add at end
		moveq	#1,d6
		bra.s	.SkipBSS
.UseBSS		move.l	(a2)+,d1
.SkipBSS	move.l	d1,(a1)+

		tst.b	TUC_Mode(a5)	;copy address header
		bge.s	.NoImage3
		moveq	#(TUCAddr_End-TUCAddr_Start)/4,d2
		sub.l	d2,d1
		lea	TUCAddr_Start(pc),a0
.CopyAddr	move.l	(a0)+,(a1)+
		subq.l	#1,d2
		bne.s	.CopyAddr
		move.l	TUC_DecAddr(a5),TUCAddr_DecAddr+2-TUCAddr_End(a1)
		move.l	TUC_JmpAddr(a5),TUCAddr_JmpAddr+2-TUCAddr_End(a1)
		move.l	(a3),TUCAddr_DataLen+2-TUCAddr_End(a1)

.NoImage3	move.l	a1,(a3)		;save pointer to hunk
		lsl.l	#2,d1
		add.l	d1,a1		;skip code/data

		move.w	d7,d1
		moveq	#0,d2
		moveq	#0,d3		;flag
.PrepareReloc	move.l	4(a3,d2.w),d4
		beq.s	.NoReloc_1
		tst.w	d3
		bne.s	.Skip3ec_1
		move.l	#$3ec,(a1)+
		moveq	#1,d3
.Skip3ec_1	move.l	d4,(a1)+	;x hunks
		lsr.w	#2,d2
		move.l	d2,(a1)+	;hunk #
		lsl.w	#2,d2
		move.l	a1,4(a3,d2.w)	;save pointer for decrunching
		lsl.l	#2,d4
		add.l	d4,a1		;skip offsets
.NoReloc_1	addq.w	#4,d2
		subq.w	#1,d1
		bne.s	.PrepareReloc
		tst.w	d3
		beq.s	.NextHunk
		clr.l	(a1)+
		bra.s	.NextHunk

.BSS		move.l	#$3eb,(a1)+
		move.l	(a2)+,(a1)+
		clr.l	(a3)		;no pointer needed
.NextHunk	move.l	#$3f2,(a1)+
		addq.w	#8,a2
		add.l	TUC_CountSize(a5),a3
		subq.w	#1,d0
		bne	.PrepareHunks

		bsr	TUC_Decrunch

		tst.b	TUC_Mode(a5)
		bge.s	.Ok
		tst.b	TUC_Back(a5)
		beq.s	.Ok

		move.l	xfdbi_TargetBuffer(a5),a0
		add.w	#20+4+8+(TUCAddr_End-TUCAddr_Start),a0
		move.l	TUCAddr_DataLen+2-TUCAddr_End(a0),d0
		lea	(a0,d0.l),a1
		lsr.l	#1,d0
.Switch		move.b	(a0),d1
		move.b	-(a1),(a0)+
		move.b	d1,(a1)
		subq.l	#1,d0
		bne.s	.Switch

.Ok		moveq	#1,d0

.ExitFree	move.l	d0,-(a7)
		move.l	TUC_CountStruct(a5),a1
		move.l	-(a1),d0
		move.l	4.w,a6
		jsr	-210(a6)
		move.l	(a7)+,d0

.Exit		move.l	(a7)+,a1	;bufferinfo
		moveq	#xfdBufferInfo_SIZE-1,d1
.CopyBI2	move.b	(a5)+,(a1)+
		dbf	d1,.CopyBI2
		add.w	#TUC_SIZE,a7
		movem.l	(a7)+,d2-d7/a2-a6
		rts

		cnop	0,4

TUCAddr_Start	movem.l	d0/d1/a0/a1/a6,-(a7)
TUCAddr_DecAddr	lea	$12345678,a1
TUCAddr_DataLen	move.l	#$12345678,d0
		move.l	4.w,a6
		jsr	-204(a6)
		tst.l	d0
		bne.s	.Ok
		add.w	#20,a7
		rts
.Ok		lea	TUCAddr_End(pc),a0
		move.l	TUCAddr_DecAddr+2(pc),a1
		move.l	TUCAddr_DataLen+2(pc),d0
		jsr	-624(a6)
		movem.l	(a7)+,d0/d1/a0/a1/a6
TUCAddr_JmpAddr	jmp	$12345678

		cnop	0,4
TUCAddr_End

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

*
*	CountStruct:
*
*	ULONG	HunkLen              ]
*	ULONG	Relocs to Hunk 0     ] (n+1)*4
*	...                          ]
*	ULONG	Relocs to Hunk n-1   ]
*
* This structure is needed for every crunched hunk !
*

TUC_Count	move.l	TUC_CrunchedData(a5),a0
		moveq	#0,d7
		move.b	(a0)+,d7		;bits needed for highest hunk #
		swap	d7
		move.b	(a0)+,d7		;amount hunks
						;a0: table of hunk len bits
		move.w	d7,d0
		addq.w	#1,d0
		and.w	#$fe,d0
		lea	(a0,d0.w),a2		;hunk table
		move.l	(a2),TUC_DecAddr(a5)
		move.w	d7,d0
		asl.w	#2,d0
		lea	20(a2,d0.w),a2		;data begin first hunk
		move.l	TUC_EorValue(a5),d3
		move.l	TUC_CountStruct(a5),a3
		moveq	#0,d6			;hunk count

.lbC00003A	moveq	#0,d5
		move.w	(a2)+,d0		;info table length
		beq	.lbC0000FE
		move.l	a2,a6			;info table
		lea	(a2,d0.w),a2
		move.w	d6,d0
		moveq	#0,d1
		move.b	(a0,d0.w),d1		;bit width of hunk length
		bsr	TUC_GetBits
		move.l	d0,d4			;hunk length
		move.l	d0,(a3)

.lbC000062	moveq	#0,d0
.lbC000064	asl.l	#1,d5			;get value from info table
		bne.s	.lbC000072
		move.l	(a2)+,d5
		eor.l	d3,d5
		move.b	#$10,ccr
		roxl.l	#1,d5
.lbC000072	bcc.s	.lbC000076
		addq.w	#2,d0
.lbC000076	move.w	(a6,d0.w),d0		;loop until negative
		bpl.s	.lbC000064
		not.w	d0

		cmp.w	#$100,d0		;less than $100 -> data byte
		bcs.s	.lbC0000F0
		bne.s	.lbC0000A6		;more than $100 -> crunched

* reloc info

		move.l	d7,d1
		swap	d1			;bits needed for hunk #
		bsr.s	TUC_GetBits		;d0: hunk number
		move.w	d0,d1
		lsl.w	#2,d1
		addq.l	#1,4(a3,d1.w)		;count reloc to hunk x
		moveq	#0,d1
		move.b	(a0,d0.w),d1		;bits of hunk length
		bsr.s	TUC_GetBits
		subq.l	#4,d4
		bra.s	.lbC0000F2

* crunched

.lbC0000A6	cmp.w	#$110,d0		;$101-$110
		bhi.s	.lbC0000C6
		sub.w	#$101,d0
		move.w	d0,d1			;value 0-$f
		bsr.s	TUC_GetBits
		sub.l	d0,d4
		moveq	#7,d1
		bsr.s	TUC_GetBits
		subq.l	#2,d4
		bra.s	.lbC0000F2

.lbC0000C6	move.w	d0,d2			;$111-$1ff
		move.w	d0,d1
		and.w	#15,d1
		bsr.s	TUC_GetBits
		addq.w	#3,d0			;length of string
		sub.l	d0,d4

		move.w	d2,d1
		lsr.w	#4,d1
		and.w	#15,d1
		addq.w	#2,d1
		bsr.s	TUC_GetBits

* copy uncrunched byte

.lbC0000F0	subq.l	#1,d4
.lbC0000F2	bmi.s	.Error
		bne.s	.lbC000062

.lbC0000FE	add.l	TUC_CountSize(a5),a3
		addq.w	#1,d6
		cmp.w	d7,d6			;last hunk ??
		bcs	.lbC00003A
		moveq	#1,d0
		rts

.Error		moveq	#0,d0
		rts

TUC_GetBits	moveq	#0,d0
.lbC00013A	asl.l	#1,d5
		bne.s	.lbC000148
		move.l	(a2)+,d5
		eor.l	d3,d5
		move.b	#$10,ccr
		roxl.l	#1,d5
.lbC000148	roxl.l	#1,d0
		dbra	d1,.lbC00013A
		rts

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

TUC_Decrunch	move.l	TUC_CrunchedData(a5),a0
		move.l	TUC_CountStruct(a5),a3

		moveq	#0,d7
		move.b	(a0)+,d7		;bits needed for highest hunk #
		swap	d7
		move.b	(a0)+,d7		;amount hunks

* a0: table of hunk lengths (bits to calculate hunk length)

		move.w	d7,d0
		addq.w	#1,d0
		and.w	#$fe,d0
		lea	(a0,d0.w),a2		;hunk table
		move.w	d7,d0
		asl.w	#2,d0
		lea	20(a2,d0.w),a2		;data begin first hunk
		move.l	TUC_EorValue(a5),d3

		moveq	#0,d6			;hunk count

.lbC00003A	moveq	#0,d5
		move.l	(a3),a1			;pointer to hunk
		move.w	(a2)+,d0		;info table length
		beq	.lbC0000FE
		move.l	a2,a6			;info table
		lea	(a2,d0.w),a2
		move.w	d6,d0
		moveq	#0,d1
		move.b	(a0,d0.w),d1		;bit width of hunk length
		bsr.s	TUC_GetBits
		move.l	d0,d4			;hunk length
		add.l	a1,d4			;end of hunk

.lbC000062	moveq	#0,d0
.lbC000064	asl.l	#1,d5			;get value from info table
		bne.s	.lbC000072
		move.l	(a2)+,d5
		eor.l	d3,d5
		move.b	#$10,ccr
		roxl.l	#1,d5
.lbC000072	bcc.s	.lbC000076
		addq.w	#2,d0
.lbC000076	move.w	(a6,d0.w),d0		;loop until negative
		bpl.s	.lbC000064
		not.w	d0

		cmp.w	#$100,d0		;less than $100 -> data byte
		bcs.s	.lbC0000F0
		bne.s	.lbC0000A6		;more than $100 -> crunched

* reloc info

		move.l	d7,d1
		swap	d1			;bits needed for hunk #
		bsr	TUC_GetBits
		moveq	#0,d1
		move.b	(a0,d0.w),d1		;bits of hunk length
		move.w	d0,d2			;d2: hunk number
		bsr	TUC_GetBits
		move.l	d5,-(a7)
		lsl.w	#2,d2
		move.l	4(a3,d2.w),a4		;current reloc pointer
		move.l	(a3),d5
		neg.l	d5
		add.l	a1,d5			;offset
		move.l	d5,(a4)+
		move.l	a4,4(a3,d2.w)		;save back pointer
		move.l	d0,(a1)+		;save longword
		move.l	(a7)+,d5
		bra.s	.lbC0000F2

* crunched

.lbC0000A6	cmp.w	#$110,d0		;$101-$110
		bhi.s	.lbC0000C6
		sub.w	#$101,d0
		move.w	d0,d1			;value 0-$f
		bsr	TUC_GetBits
		move.w	d0,d2			;amount of same bytes
		moveq	#7,d1
		bsr	TUC_GetBits
.lbC0000BE	move.b	d0,(a1)+		;copy same bytes
		dbra	d2,.lbC0000BE
		bra.s	.lbC0000F0

.lbC0000C6	move.w	d0,d2			;$111-$1ff
		move.w	d0,d1
		and.w	#15,d1
		bsr	TUC_GetBits
		addq.w	#3,d0			;length of string
		move.w	d2,d1
		move.w	d0,d2
		lsr.w	#4,d1
		and.w	#15,d1
		addq.w	#2,d1
		bsr	TUC_GetBits
		neg.l	d0			;offset
.lbC0000E6	move.b	(a1,d0.l),(a1)+
		dbra	d2,.lbC0000E6
		bra.s	.lbC0000F2

* copy uncrunched byte

.lbC0000F0	move.b	d0,(a1)+
.lbC0000F2	cmp.l	d4,a1			;end of hunk ??
		bne	.lbC000062
.lbC0000FE	add.l	TUC_CountSize(a5),a3
		addq.w	#1,d6
		cmp.w	d7,d6			;last hunk ??
		bcs	.lbC00003A
		rts

**********************************************************
*
* Data files must have the following format:
*
* - Only one "hunk" (starting with $0001)
* - Address of the "hunk" must be "TUC!" (that's the ID)
* - No reloc information (bitcode $100)
*
* The "Rückwärts" option cannot be recognized in any way,
* you have to switch bytes by hand if such a file appears.
*

S_TUCData	dc.l	0
		dc.w	2
		dc.w	38
		dc.l	N_TUCData
		dc.w	XFDPFF_DATA!XFDPFF_RECOGLEN!XFDPFF_USERTARGET
		dc.w	0
		dc.l	RB_TUCData
		dc.l	DB_TUCData
		dc.l	SD_TUCData
		dc.l	VD_TUCData
		dc.w	0
		dc.w	0
		dc.l	$1c+2+2+4

N_TUCData	dc.b	'TUC 1.16 Data',0
		even

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

RB_TUCData	bsr.s	RB_TUCDataID
		beq.s	.Out
		cmp.w	#$0001,(a0)		;only data with 1 "hunk"
		bne.s	.Exit
		move.w	$1c(a0),d0		;info table length
		beq.s	.Out
		movem.l	d3/d5/a2,-(a7)
		lea	$1e(a0,d0.w),a2
		moveq	#0,d1
		move.b	2(a0),d1		;bit width of hunk length
		moveq	#0,d5
		move.l	8(a0),d3		;calculate EOR value
		eor.l	#"M.F.",d3
		neg.l	d3
		swap	d3
		ror.l	#8,d3
		bsr	TUC_GetBits
		movem.l	(a7)+,d3/d5/a2
		move.l	d0,xfdrr_MinTargetLen(a1)
		move.l	d0,xfdrr_FinalTargetLen(a1)
		moveq	#1,d0
		rts
.Exit		moveq	#0,d0
.Out		rts


RB_TUCDataID	cmp.l	#"TUC!",4(a0)
		bne.s	.Exit
		cmp.l	#"TUC ",$c(a0)
		bne.s	.Exit
		cmp.l	#" M.F",$10(a0)
		bne.s	.Exit
		cmp.l	#"ried",$14(a0)
		bne.s	.Exit
		cmp.l	#"rich",$18(a0)
		bne.s	.Exit
		moveq	#1,d0
		rts
.Exit		moveq	#0,d0
		rts

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

SD_TUCData	cmp.w	#$0001,(a0)		;only data with 1 "hunk"
		bne.s	.Exit
		cmp.l	#$1e,d0			;length to scan
		blt.s	.Exit
		bsr.s	RB_TUCDataID
		beq.s	.Out
		tst.w	$1c(a0)			;info table length
		beq.s	.Exit
		rts
.Exit		moveq	#0,d0
.Out		rts

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

VD_TUCData	moveq	#0,d1
		move.w	$1c(a0),d1
		add.w	#$1e,d1			;start of packed data
		sub.l	d1,d0
		cmp.l	#4,d0			;at least one longword
		blt.s	.Exit

		movem.l	d2-d7/a2/a6,-(a7)
		move.l	d0,d6			;bytes still there
		move.l	8(a0),d3		;calculate EOR value
		eor.l	#"M.F.",d3
		neg.l	d3
		swap	d3
		ror.l	#8,d3
		bsr.s	TUCData_GetLen
		move.l	a2,d0
		sub.l	a0,d0
		movem.l	(a7)+,d2-d7/a2/a6
		tst.w	d1
		beq.s	.Exit
		rts

.Exit		moveq	#0,d0
		rts

TUCData_GetLen	moveq	#0,d7
		move.b	2(a0),d7		;bit width of data
		lea	$1c(a0),a2		;data table

		moveq	#0,d5
		move.w	(a2)+,d0		;info table length
		move.l	a2,a6			;info table
		lea	(a2,d0.w),a2
		move.w	d7,d1			;bit width of hunk length
		bsr.s	.GetBitsD6
		move.l	d0,d4			;hunk length

.lbC000062	moveq	#0,d0
.lbC000064	asl.l	#1,d5			;get value from info table
		bne.s	.lbC000072
		move.l	(a2)+,d5
		subq.l	#4,d6
		bmi.s	.Error
		eor.l	d3,d5
		move.b	#$10,ccr
		roxl.l	#1,d5
.lbC000072	bcc.s	.lbC000076
		addq.w	#2,d0
.lbC000076	move.w	(a6,d0.w),d0		;loop until negative
		bpl.s	.lbC000064
		not.w	d0

		cmp.w	#$100,d0		;less than $100 -> data byte
		bcs.s	.lbC0000F0
		bne.s	.lbC0000A6		;more than $100 -> crunched

* reloc info

.Error		moveq	#0,d1			;error
		rts

* crunched

.lbC0000A6	cmp.w	#$110,d0		;$101-$110
		bhi.s	.lbC0000C6
		sub.w	#$101,d0
		move.w	d0,d1			;value 0-$f
		bsr.s	.GetBitsD6
		sub.l	d0,d4
		moveq	#7,d1
		bsr.s	.GetBitsD6
		subq.l	#2,d4
		bra.s	.lbC0000F2

.lbC0000C6	move.w	d0,d2			;$111-$1ff
		move.w	d0,d1
		and.w	#15,d1
		bsr.s	.GetBitsD6
		addq.w	#3,d0			;length of string
		sub.l	d0,d4
		move.w	d2,d1
		lsr.w	#4,d1
		and.w	#15,d1
		addq.w	#2,d1
		bsr.s	.GetBitsD6

* copy uncrunched byte

.lbC0000F0	subq.l	#1,d4
.lbC0000F2	bgt.s	.lbC000062
		bmi.s	.Error
		moveq	#1,d1
		rts

.GetBitsD6	moveq	#0,d0
.lbC00013A	asl.l	#1,d5
		bne.s	.lbC000148
		move.l	(a2)+,d5
		subq.l	#4,d6
		bge.s	.Ok
		addq.w	#4,a7
		bra.s	.Error
.Ok		eor.l	d3,d5
		move.b	#$10,ccr
		roxl.l	#1,d5
.lbC000148	roxl.l	#1,d0
		dbra	d1,.lbC00013A
		rts

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

DB_TUCData	movem.l	d2-d7/a2-a6,-(a7)
		move.l	a0,a5
		move.l	xfdbi_MinTargetLen(a5),d0
		move.l	d0,xfdbi_TargetBufSaveLen(a5)
		move.l	d0,xfdbi_TargetBufLen(a5)

		move.w	xfdbi_Flags(a5),d1
		and.w	#XFDFF_USERTARGET,d1
		beq.s	.Alloc
		move.l	xfdbi_UserTargetBuf(a5),d0
		bra.s	.UserTarget
.Alloc		move.l	xfdbi_TargetBufMemType(a5),d1
		move.l	4.w,a6
		jsr	-198(a6)
.UserTarget	move.w	#XFDERR_NOMEMORY,xfdbi_Error(a5)
		move.l	d0,xfdbi_TargetBuffer(a5)
		beq.s	.Exit
		
		move.l	d0,a1
		move.l	xfdbi_SourceBuffer(a5),a0
		move.l	8(a0),d3		;calculate EOR value
		eor.l	#"M.F.",d3
		neg.l	d3
		swap	d3
		ror.l	#8,d3

		bsr.s	TUCData_Decr
		tst.w	d0
		bne.s	.Exit

.Free		move.w	xfdbi_Flags(a5),d1
		and.w	#XFDFF_USERTARGET,d1
		bne.s	.UserTarget2
		move.l	xfdbi_TargetBuffer(a5),a1
		move.l	xfdbi_TargetBufLen(a5),d0
		move.l	4.w,a6
		jsr	-210(a6)
.UserTarget2	move.w	#XFDERR_CORRUPTEDDATA,xfdbi_Error(a5)
		moveq	#0,d0
.Exit		movem.l	(a7)+,d2-d7/a2-a6
		rts

TUCData_Decr	moveq	#0,d7
		move.b	2(a0),d7		;bit width of data
		lea	$1c(a0),a2		;data table

		moveq	#0,d5
		move.w	(a2)+,d0		;info table length
		move.l	a2,a6			;info table
		lea	(a2,d0.w),a2
		move.w	d7,d1			;bit width of hunk length
		bsr	TUC_GetBits
		move.l	d0,d4			;hunk length
		add.l	a1,d4			;end of hunk

.lbC000062	moveq	#0,d0
.lbC000064	asl.l	#1,d5			;get value from info table
		bne.s	.lbC000072
		move.l	(a2)+,d5
		eor.l	d3,d5
		move.b	#$10,ccr
		roxl.l	#1,d5
.lbC000072	bcc.s	.lbC000076
		addq.w	#2,d0
.lbC000076	move.w	(a6,d0.w),d0		;loop until negative
		bpl.s	.lbC000064
		not.w	d0

		cmp.w	#$100,d0		;less than $100 -> data byte
		bcs.s	.lbC0000F0
		bne.s	.lbC0000A6		;more than $100 -> crunched

* reloc info

.Error		moveq	#0,d0			;error
		rts

* crunched

.lbC0000A6	cmp.w	#$110,d0		;$101-$110
		bhi.s	.lbC0000C6
		sub.w	#$101,d0
		move.w	d0,d1			;value 0-$f
		bsr	TUC_GetBits
		move.w	d0,d2			;amount of same bytes
		moveq	#7,d1
		bsr	TUC_GetBits
.lbC0000BE	move.b	d0,(a1)+		;copy same bytes
		cmp.l	d4,a1
		beq.s	.Error
		dbra	d2,.lbC0000BE
		bra.s	.lbC0000F0

.lbC0000C6	move.w	d0,d2			;$111-$1ff
		move.w	d0,d1
		and.w	#15,d1
		bsr	TUC_GetBits
		addq.w	#3,d0			;length of string
		move.w	d2,d1
		move.w	d0,d2
		lsr.w	#4,d1
		and.w	#15,d1
		addq.w	#2,d1
		bsr	TUC_GetBits
		neg.l	d0			;offset
.lbC0000E6	move.b	(a1,d0.l),(a1)+
		cmp.l	d4,a1
		dbeq	d2,.lbC0000E6
		tst.w	d2
		ble.s	.lbC0000F2
		bra.s	.Error

* copy uncrunched byte

.lbC0000F0	move.b	d0,(a1)+
.lbC0000F2	cmp.l	d4,a1			;end of hunk ??
		bne	.lbC000062
		moveq	#1,d0
		rts


		END