summaryrefslogtreecommitdiff
path: root/Source/CompressBlock.S
blob: 52dab5b92ec7627e32f5b050434e395ed3e11609 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
**
**	$Id: CompressBlock.S,v 21.3 92/05/18 02:20:39 chris Exp $
**	$Revision: 21.3 $
**
**	$Filename: CompressBlock.S $
**	$Author: chris $
**	$Date: 92/05/18 02:20:39 $
**
**	iff.library/IFFL_CompressBlock
**
**	COPYRIGHT (C) 1987-1992 BY CHRISTIAN A. WEBER, BRUGGERWEG 2,
**	CH-8037 ZUERICH, SWITZERLAND.  ALL RIGHTS RESERVED.  NO PART
**	OF THIS SOFTWARE MAY BE COPIED, REPRODUCED,  OR  TRANSMITTED
**	IN ANY FORM OR BY ANY MEANS,  WITHOUT THE PRIOR WRITTEN PER-
**	MISSION OF THE AUTHOR. USE AT YOUR OWN RISK.
**


		IDNT	IFFL_CompressBlock
		SECTION	text,CODE

		INCLUDE	"IffLib.i"

		XREF	SetError
		XDEF	CompressBlockFunc

		XDEF	Compress_NONE,Compress_BYTERUN1 ;,Compress_FIBDELTA

******* iff.library/IFFL_CompressBlock **************************************
*
*    NAME
*	IFFL_CompressBlock -- Compress a memory block
*
*    SYNOPSIS
*	result = IFFL_CompressBlock( source, destination, size, mode )
*	                               A0      A1           D0    D1
*
*	ULONG IFFL_CompressBlock( APTR, APTR, ULONG, ULONG )
*
*    FUNCTION
*	Compress the memory block using the appropriate compression mode.
*	If the compressed data would become longer than the uncompressed,
*	an error is returned.
*
*    INPUTS
*	source      - Pointer to data to compress
*	destination - Target address for compression
*	size        - Number of data bytes to compress
*	mode        - Compression mode. Currently, the following modes
*	              are supported:
*
*	              IFFL_COMPR_NONE     - Vanilla copy
*	              IFFL_COMPR_BYTERUN1 - CmpByteRun1 (ILBM BODY data)
*	              IFFL_COMPR_FIBDELTA - Fibonacci Delta (8SVX BODY data)
*
*    RESULTS
*	Length of compressed data or 0 if an error occurred.
*	IFFL_IFFError() returns IFFL_ERROR_BADCOMPRESSION if you ask for
*	an unsupported compression mode.
*
*   BUGS
*	In IFFL_COMPR_BYTERUN1, if the compressed data would become longer,
*	the buffer will be overwritten, and no error is returned. So be
*	sure to supply a destination buffer which is big enough!
*
*    SEE ALSO
*	IFFL_DecompressBlock()
*
*****************************************************************************

CompressBlockFunc:
		subq.l	#1,d1
		beq.b	Compress_BYTERUN1	; Modus == 1
		bmi.b	Compress_NONE		; Modus == 0

	*** Unbekannter Modus --> Error setzen

		movem.l	a5-a6,-(SP)
		movea.l	a6,a5			; A5 :  IFFBase für SetError()
		moveq.l	#IFFL_ERROR_BADCOMPRESSION,d0
		bsr	SetError		; Setzt auch D0 auf 0
		movem.l	(SP)+,a5-a6
		rts

*****************************************************************************
**	Kopiermodus (für CompressBlock() UND DecompressBlock() benutzt)

Compress_NONE:	movem.l	d0/a6,-(SP)
		movea.l	iffb_SysBase(a6),a6
		JSRLIB	CopyMem
		movem.l	(SP)+,d0/a6
		rts

*****************************************************************************
**	CmpByteRun1 komprimieren

Compress_BYTERUN1:
		movem.l	d2-d3/a2-a3,-(SP)
		lea	0(a0,d0.l),a2	; A2 : Source-Endadresse
		moveq	#0,d3		; Byte-Zähler

crunchloop:	bsr.b	CountEq		; wieviele gleiche Bytes folgen ?
		cmp.w	#3,d0		; genug gleiche Bytes zum runnen ?
		blt.b	countdump	; nee, lohnt sich nicht -> Dumpen

		addq.l	#2,d3		; Markierbyte & Anzahl
		move.b	(a0),d1		; Wert
		adda.w	d0,a0		; Source anpassen
		subq.w	#1,d0		; muss .w sein und nicht .b !!!!!!!
		neg.b	d0		; negieren (= "Run"-Code)
		move.b	d0,(a1)+	; und eintragen
		move.b	d1,(a1)+	; Wert eintragen
		bra.b	crunchcont	; weitermachen

countdump:	movea.l	a0,a3		; Source-Pointer retten
		moveq	#0,d2		; D2 : Länge des Dump-Blocks
1$:		addq.b	#1,d2
		bmi.b	2$		; höchstens 127 Bytes pro Block
		addq.l	#1,a0
		cmpa.l	a2,a0		; Ende der Daten erreicht ?
		bhs.b	3$		; ja -> abbrechen
		bsr.b	CountEq
		cmp.w	#3,d0		; Ende des Dump-Blocks ?
		blt.b	1$		; noch nicht
		bra.b	3$		; Ende
2$:		moveq	#127,d2
3$:		movea.l	a3,a0		; Source-Pointer restaurieren

		add.l	d2,d3		; zur Gesamtanzahl dazuzählen
		addq.l	#1,d3		; Markierbyte nicht vergessen
		subq.w	#1,d2		; aus 1..128 mach 0..127
		move.b	d2,(a1)+	; Markierbyte eintragen
4$:		move.b	(a0)+,(a1)+	; Datenbytes eintragen
		dbf	d2,4$


crunchcont:	cmpa.l	a2,a0		; Ende der Linie erreicht ?
		blo.b	crunchloop	; noch nicht!

		move.l	d3,d0		; Return: Anzahl Destination-Bytes
		movem.l	(SP)+,d2-d3/a2-a3
		rts

	*** Anzahl gleicher Zeichen ab (a0) zählen und nach D0

CountEq:	move.l	a0,-(SP)
		moveq	#1,d0		; D0 : Anzahl gleiche Bytes
1$:		move.b	(a0)+,d1	; erstes Byte
2$:		cmp.b	(a0)+,d1	; Byte gleich wie letztes Byte ?
		bne.b	3$		; nein -> abbrechen
		cmp.w	#128,d0
		bge.b	3$		; höchstens 128 gleiche
		addq.w	#1,d0		; Anzahl erhöhen
		cmpa.l	a2,a0		; Ende des Buffers erreicht ?
		blo.b	2$		; noch nicht -> weiterzählen
3$:		move.l	(SP)+,a0
		rts


		END