2 * original code: WDOSX-Pack v1.07, (c) 1999-2001 by Joergen Ibsen / Jibz
3 * for data and executable compression software: http://www.ibsensoftware.com/
15 #ifndef WDX_EXCLUDE_CRC
16 uint32_t wdxCRC32 (const void *src
, int len
) {
17 static const unsigned int crctab
[16] = {
18 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190,
19 0x6b6b51f4, 0x4db26158, 0x5005713c, 0xedb88320, 0xf00f9344,
20 0xd6d6a3e8, 0xcb61b38c, 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278,
23 const uint8_t *buf
= (const uint8_t *)src
;
24 uint32_t crc
= 0xffffffffUL
;
26 if (src
== NULL
|| len
< 1) return 0;
29 crc
= crctab
[crc
&0x0f]^(crc
>>4);
30 crc
= crctab
[crc
&0x0f]^(crc
>>4);
32 return crc
^0xffffffffUL
;
37 #define WDXUNPACK_LEN2_LIMIT 1920
39 #define WDXFatalError() longjmp(errJP, 666)
42 #ifndef WDX_EXCLUDE_PACKER
43 int wdxPackBufferSize (int inSize
) {
44 if (inSize
< 1) return 0;
45 return inSize
+((inSize
+7)/8)+2;
49 int wdxPack (void *dest
, int destSize
, const void *source
, int length
) {
54 /* global variables */
55 const uint8_t *inBuffer
= (const uint8_t *)source
, *sourceOfs
, *backPtr
;
56 uint8_t *outBuffer
= (uint8_t *)dest
;
57 uint32_t nextBackEntry
;
60 uint32_t *backTable
; /* back-table, array */
61 //uint32_t lookup[256][256]; /* lookup-table */ /*FIXME: made dynamic*/
62 uint32_t *lookup
= NULL
; /* lookup-table */ /*FIXME: made dynamic*/
63 uint32_t lastMatchPos
= 0;
66 uint32_t bytesOut
= 0;
68 void advanceTagByte (int bit
) {
69 /* check bitcount and then decrement */
71 if (--destSize
< 0) WDXFatalError();
73 tagByte
= outBuffer
++;
78 *tagByte
= ((*tagByte
)<<1)|(bit
?1:0);
82 /* output Gamma2-code for val in range [2..?] ... */
83 void outputGamma (uint32_t val
) {
84 uint32_t invertlen
= 0, invert
= 0;
86 /* rotate bits into invert (except last) */
88 invert
= (invert
<<1)|(val
&0x01);
90 val
= (val
>>1)&0x7FFFFFFF;
92 /* output Gamma2-encoded bits */
93 for (--invertlen
; invertlen
> 0; --invertlen
) {
94 advanceTagByte(invert
&0x01);
98 advanceTagByte(invert
&0x01);
102 void outputLiteral (uint8_t lit
) {
104 advanceTagByte(0); /* 0 indicates a literal */
105 if (--destSize
< 0) WDXFatalError();
106 *outBuffer
++ = lit
; /* output the literal */
110 void outputCodePair (uint32_t pos
, uint32_t len
, const uint8_t *buffer
) {
111 /* if we just had a match, don't use lastMatchPos */
113 /* if a short match is too far away, encode it as two literals instead */
114 if (pos
> WDXUNPACK_LEN2_LIMIT
&& len
== 2) {
115 outputLiteral(buffer
[0]);
116 outputLiteral(buffer
[1]);
118 advanceTagByte(1); /* 1 indicates a match */
119 /* a match more than WDXUNPACK_LEN2_LIMIT bytes back will be longer than 2 */
120 if (pos
> WDXUNPACK_LEN2_LIMIT
) --len
;
121 outputGamma(len
); /* output length */
122 lastMatchPos
= pos
--;
123 /*assert(pos >= 0);*/
124 outputGamma(((pos
>>6)&0x3FFFFFFF)+2); /* output high part of position */
125 /* output low 6 bits of position */
126 advanceTagByte(pos
&0x20);
127 advanceTagByte(pos
&0x10);
128 advanceTagByte(pos
&0x08);
129 advanceTagByte(pos
&0x04);
130 advanceTagByte(pos
&0x02);
131 advanceTagByte(pos
&0x01);
135 /* if a short match is too far away, encode it as two literals instead */
136 if (pos
> WDXUNPACK_LEN2_LIMIT
&& len
== 2 && pos
!= lastMatchPos
) {
137 outputLiteral(buffer
[0]);
138 outputLiteral(buffer
[1]);
140 advanceTagByte(1); /* 1 indicates a match */
141 /* a match more than WDXUNPACK_LEN2_LIMIT bytes back will be longer than 2 */
142 if (pos
> WDXUNPACK_LEN2_LIMIT
&& pos
!= lastMatchPos
) --len
;
143 outputGamma(len
); /* output length */
144 /* output position */
145 if (pos
== lastMatchPos
) {
146 /* a match with position 0 means use last position */
150 lastMatchPos
= pos
--;
151 /*assert(pos >= 0);*/
152 outputGamma(((pos
>>6)&0x3FFFFFFF)+3); /* output high part of position */
153 /* output low 6 bits of position */
154 advanceTagByte(pos
&0x20);
155 advanceTagByte(pos
&0x10);
156 advanceTagByte(pos
&0x08);
157 advanceTagByte(pos
&0x04);
158 advanceTagByte(pos
&0x02);
159 advanceTagByte(pos
&0x01);
165 void findMatch (TheMatch
*thematch
, const uint8_t *buffer
, uint32_t lookback
, uint32_t lookforward
) {
166 uint32_t backPos
, matchLen
, bestMatchLen
, bestMatchPos
;
171 /* temporary variables to avoid indirect addressing into the match */
172 bestMatchLen
= 0; bestMatchPos
= 0;
173 /* update lookup- and backtable up to current position */
174 while (backPtr
< buffer
) {
177 backTable
[nextBackEntry
] = lookup
[idx0
*256+idx1
];
178 lookup
[idx0
*256+idx1
] = nextBackEntry
;
182 /* get position by looking up next two bytes */
183 backPos
= lookup
[buffer
[0]*256+buffer
[1]];
184 if (backPos
!= 0 && lookforward
> 1) {
185 ptr
= backPos
+sourceOfs
;
186 /* go backwards until before buffer */
187 while (ptr
>= buffer
&& backPos
!= 0) {
188 /*backPos := PInt(Integer(backTable)+backPos*4)^;*/
189 backPos
= backTable
[backPos
];
190 ptr
= backPos
+sourceOfs
;
192 /* search through table entries */
193 while (backPos
!= 0 && buffer
-ptr
<= lookback
) {
195 /* if this position has a chance to be better */
196 if (*(ptr
+bestMatchLen
) == *(buffer
+bestMatchLen
)) {
198 while (matchLen
< lookforward
&& *(ptr
+matchLen
) == *(buffer
+matchLen
)) ++matchLen
;
200 i0
= buffer
-ptr
==lastMatchPos
? 1 : 0;
201 i1
= bestMatchPos
==lastMatchPos
? 1 : 0;
202 if (matchLen
+i0
> bestMatchLen
+i1
) {
203 bestMatchLen
= matchLen
;
204 if (bestMatchLen
== lookforward
) backPos
= 0;
205 bestMatchPos
= buffer
-ptr
;
208 /* move backwards to next position */
209 /*backPos := PInt(Integer(backTable)+backPos*4)^;*/
210 backPos
= backTable
[backPos
];
211 ptr
= backPos
+sourceOfs
;
214 /* forget match if too far away */
215 if (bestMatchPos
> WDXUNPACK_LEN2_LIMIT
&& bestMatchLen
== 2 && bestMatchPos
!= lastMatchPos
) {
219 /* update the match with best match */
220 thematch
->len
= bestMatchLen
;
221 thematch
->pos
= bestMatchPos
;
225 TheMatch match
, nextmatch
, literalmatch
, testmatch
;
226 uint32_t pos
, lastpos
, literalCount
;
230 if (length
< 1) return 0;
231 if (destSize
< 2) return -1;
232 if (!(backTable
= malloc((length
+4)*4))) return -2; /* out of memory */
233 if (!(lookup
= malloc(256*256*4))) { free(backTable
); return -2; } /* out of memory */
236 /* compressing error */
242 memset(&match
, 0, sizeof(match
));
243 memset(&nextmatch
, 0, sizeof(nextmatch
));
244 memset(&literalmatch
, 0, sizeof(literalmatch
));
245 memset(&testmatch
, 0, sizeof(testmatch
));
246 literalmatch
.pos
= literalmatch
.len
= 0;
247 sourceOfs
= inBuffer
-1;
248 /* init lookup- and backtable */
249 /*for (i = 0; i <= 255; ++i) for (j = 0; j <= 255; ++j) lookup[i*256+j] = 0;*/
250 memset(lookup
, 0, 256*256*4);
251 memset(backTable
, 0, (length
+4)*4);
259 /* the first byte is sent verbatim */
260 *outBuffer
++ = *inBuffer
++;
265 *(tagByte
= outBuffer
++) = 0;
270 while (pos
< length
) {
271 /* find best match at current position (if not already found) */
272 if (pos
== lastpos
) {
273 match
.len
= nextmatch
.len
;
274 match
.pos
= nextmatch
.pos
;
276 findMatch(&match
, inBuffer
, pos
, length
-pos
);
278 /* if we found a match, find the best match at the next position */
279 if (match
.len
!= 0) {
280 findMatch(&nextmatch
, inBuffer
+1, pos
+1, length
-(pos
+1));
285 /* decide if we should output a match or a literal */
286 i0
= (match
.pos
==lastMatchPos
? 1 : 0);
287 i1
= (nextmatch
.pos
==lastMatchPos
? 1 : 0);
288 if (match
.len
!= 0 && match
.len
+i0
>= nextmatch
.len
+i1
) {
289 /* output any pending literals */
290 if (literalCount
!= 0) {
291 if (literalCount
== 1) {
292 outputLiteral(inBuffer
[-1]);
294 /* check if there is a closer match with the required length */
295 findMatch(&testmatch
, inBuffer
-literalCount
, literalmatch
.pos
, literalCount
);
296 if (testmatch
.len
>= literalCount
) outputCodePair(testmatch
.pos
, literalCount
, inBuffer
-literalCount
);
297 else outputCodePair(literalmatch
.pos
, literalCount
, inBuffer
-literalCount
);
302 outputCodePair(match
.pos
, match
.len
, inBuffer
);
303 inBuffer
+= match
.len
;
306 /* check if we are allready collecting literals */
307 if (literalCount
!= 0) {
308 /* if so, continue.. */
310 /* have we collected as many as possible? */
311 if (literalCount
== literalmatch
.len
) {
312 outputCodePair(literalmatch
.pos
, literalCount
, inBuffer
-literalCount
+1);
316 /* if we had a match which was not good enough, then save it.. */
317 if (match
.len
!= 0) {
318 literalmatch
.len
= match
.len
;
319 literalmatch
.pos
= match
.pos
;
322 /* if not, we have to output the literal now */
323 outputLiteral(inBuffer
[0]);
330 /* output any remaining literal bytes */
331 if (literalCount
!= 0) {
332 if (literalCount
== 1) outputLiteral(inBuffer
[-1]);
333 else outputCodePair(literalmatch
.pos
, literalCount
, inBuffer
-literalCount
);
335 /* switch last tagByte into position */
336 if (bitCount
!= 8) *tagByte
<<= bitCount
;
345 #ifndef WDX_EXCLUDE_UNPACKER
346 int wdxUnpack (void *bufOut
, int outSize
, const void *bufIn
, int inSize
) {
347 const uint8_t *src
= (const uint8_t *)bufIn
;
348 uint8_t *dest
= (uint8_t *)bufOut
, *pp
;
350 int lastMatchPos
= 0, lastWasMatch
= 0, len
, pos
, b
, bCount
= 0, origOutSz
= outSize
;
358 if (inSize
< 1) WDXFatalError();
363 res
= (fbyte
&0x80)!=0 ? 1 : 0;
364 fbyte
= (fbyte
&0x7f)<<1;
369 int getGamma (void) {
373 res
= (res
<<1)|getBit();
374 } while (getBit() == 1);
378 /* get 6 low bits of position */
379 int getLoPos (int pos
) {
380 for (int f
= 0; f
< 6; ++f
) pos
= (pos
<<1)|getBit();
385 if (outSize
< 1) return 0;
386 if (inSize
< 1) return -1; /* out of input data */
389 /* decompressing error */
390 if (!itsOk
) return -1;
391 return origOutSz
-outSize
;
394 /* the first byte was sent verbatim */
398 while (outSize
> 0) {
404 if (inSize
< 1) break;
414 pos
= getLoPos(pos
)+1;
416 if (pos
> WDXUNPACK_LEN2_LIMIT
) ++len
;
420 /* same position as last match? */
421 if (pos
== 0) pos
= lastMatchPos
;
423 pos
= getLoPos(pos
-1)+1;
425 if (pos
> WDXUNPACK_LEN2_LIMIT
) ++len
;
430 if ((void *)pp
< (void *)bufOut
) return -1; /* shit! */
431 for (; len
> 0 && outSize
> 0; --outSize
, --len
) *dest
++ = *pp
++;
434 return origOutSz
-outSize
;