Richard Boegli's CnC_Generals_Zero_Hour Fork WIP
This is documentation of Richard Boegil's Zero Hour Fork
 
Loading...
Searching...
No Matches
huffdecode.cpp
Go to the documentation of this file.
1/*
2** Command & Conquer Generals Zero Hour(tm)
3** Copyright 2025 Electronic Arts Inc.
4**
5** This program is free software: you can redistribute it and/or modify
6** it under the terms of the GNU General Public License as published by
7** the Free Software Foundation, either version 3 of the License, or
8** (at your option) any later version.
9**
10** This program is distributed in the hope that it will be useful,
11** but WITHOUT ANY WARRANTY; without even the implied warranty of
12** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13** GNU General Public License for more details.
14**
15** You should have received a copy of the GNU General Public License
16** along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19// Copyright (C) Electronic Arts Canada Inc. 1995-2002. All rights reserved.
20
21#ifndef __HUFREAD
22#define __HUFREAD 1
23
24#include <string.h>
25#include "codex.h"
26#include "huffcodex.h"
27
28#if defined(_MSC_VER)
29#pragma warning(push,1)
30#endif
31
32/****************************************************************/
33/* Internal Functions */
34/****************************************************************/
35
37{
38 unsigned char *s;
40 unsigned int bits;
41};
42
43/****************************************************************/
44/* Huffman Unpacker */
45/****************************************************************/
46
47static int ZERO=0;
48
49#define GET16BITS() \
50 bitsunshifted = qs[0] | (bitsunshifted << 8);\
51 bitsunshifted = qs[1] | (bitsunshifted << 8);\
52 qs += 2;
53
54
55#define SQgetbits(v,n)\
56 if (n) \
57 { \
58 v = bits >> (32-(n));\
59 bits <<= (n);\
60 bitsleft -= (n);\
61 } \
62\
63 if (bitsleft<0)\
64 {\
65 GET16BITS() \
66\
67 bits = bitsunshifted<<(-bitsleft);\
68 bitsleft += 16;\
69 }
70
71
72#define SQgetnum(v) \
73 if ((int)bits<0)\
74 {\
75 SQgetbits(v,3);\
76 v -= 4;\
77 }\
78 else\
79 {\
80 int n;\
81 unsigned int v1;\
82\
83 if (bits>>16)\
84 {\
85 n=2;\
86 do\
87 {\
88 bits <<= 1; \
89 ++n;\
90 }\
91 while ((int)bits>=0);\
92 bits <<= 1;\
93 bitsleft -= (n-1);\
94 SQgetbits(v,ZERO);\
95 }\
96 else\
97 {\
98 n=2;\
99 do\
100 {\
101 ++n;\
102 SQgetbits(v,1);\
103 }\
104 while (!v);\
105 }\
106 if (n>16)\
107 {\
108 SQgetbits(v,n-16);\
109 SQgetbits(v1,16);\
110 v = (v1|(v<<16))+(1<<n)-4;\
111 }\
112 else\
113 {\
114 SQgetbits(v,n);\
115 v = (v+(1<<n)-4);\
116 }\
117 }
118
119/* note: requires 'amt' be a multiple of 16 */
120#define SQmemset(ptr, val, amt) \
121{\
122 int i = amt/16;\
123 int intval = (val<<24)|(val<<16)|(val<<8)|val;\
124 int* lptr = (int*)ptr;\
125\
126 while (i)\
127 {\
128 lptr[0] = intval;\
129 lptr[1] = intval;\
130 lptr[2] = intval;\
131 lptr[3] = intval;\
132 lptr += 4;\
133 --i;\
134 }\
135}\
136
137static int HUFF_decompress(unsigned char *packbuf, unsigned char *unpackbuf)
138{
139 unsigned int type;
140 unsigned char clue;
141 int ulen;
142 unsigned int cmp;
143 int bitnum=0;
144 int cluelen=0;
145 unsigned char *qs;
146 unsigned char *qd;
147 unsigned int bits;
148 unsigned int bitsunshifted=0;
149 int numbits;
150 int bitsleft;
151 unsigned int v;
152
153 qs = packbuf;
154 qd = unpackbuf;
155 ulen = 0L;
156
157 if (qs)
158 {
159 {
160 int mostbits;
161 int i;
162 int bitnumtbl[16];
163 unsigned int deltatbl[16];
164 unsigned int cmptbl[16];
165 unsigned char codetbl[256];
166 unsigned char quickcodetbl[256];
167 unsigned char quicklentbl[256];
168
169 bitsleft = -16; /* init bit stream */
170 bits = 0;
171 SQgetbits(v,ZERO);
172
173 SQgetbits(type,16);
174
175 if (type&0x8000) /* 4 byte size field */
176 {
177 /* (skip nothing for 0x30fb) */
178 if (type&0x100) /* skip ulen */
179 {
180 SQgetbits(v,16);
181 SQgetbits(v,16);
182 }
183 type &= ~0x100;
184
185 SQgetbits(v,16); /* unpack len */
186 SQgetbits(ulen,16);
187 ulen |= (v<<16);
188 }
189 else
190 {
191 /* (skip nothing for 0x30fb) */
192 if (type&0x100) /* skip ulen */
193 {
194 SQgetbits(v,8);
195 SQgetbits(v,16);
196 }
197 type &= ~0x100;
198
199 SQgetbits(v,8); /* unpack len */
200 SQgetbits(ulen,16);
201 ulen |= (v<<16);
202 }
203
204 {
205 {
206 int numchars;
207
208 {
209 unsigned int basecmp;
210
211 {
212 unsigned int t;
213 SQgetbits(t,8); /* clue byte */
214 clue = (unsigned char)t;
215 }
216
217 numchars = 0;
218 numbits = 1;
219 basecmp = (unsigned int) 0;
220
221 /* decode bitnums */
222
223 do
224 {
225 basecmp <<= 1;
226 deltatbl[numbits] = basecmp-numchars;
227
228 SQgetnum(bitnum); /* # of codes of n bits */
229 bitnumtbl[numbits] = bitnum;
230
231 numchars += bitnum;
232 basecmp += bitnum;
233
234 cmp = 0;
235 if (bitnum) /* left justify cmp */
236 cmp = (basecmp << (16-numbits) & 0xffff);
237
238 cmptbl[numbits++] = cmp;
239
240 }
241 while (!bitnum || cmp); /* n+1 bits in cmp? */
242 }
243 cmptbl[numbits-1] = 0xffffffff; /* force match on most bits */
244
245 mostbits = numbits-1;
246
247 /* decode leapfrog code table */
248
249 {
250 signed char leap[256];
251 unsigned char nextchar;
252
253 SQmemset(leap,0,256);
254 nextchar = (unsigned char) -1;
255
256 for (i=0;i<numchars;++i)
257 {
258 int leapdelta=0;
259
260 SQgetnum(leapdelta);
261 ++leapdelta;
262
263 do
264 {
265 ++nextchar;
266 if (!leap[nextchar])
267 --leapdelta;
268 } while (leapdelta);
269
270 leap[nextchar] = 1;
271 codetbl[i] = nextchar;
272 }
273 }
274 }
275
276/****************************************************************/
277/* Make fast 8 tables */
278/****************************************************************/
279
280 SQmemset(quicklentbl,64,256);
281
282 {
283 int bits;
284 int bitnum;
285 int numbitentries;
286 int nextcode;
287 int nextlen;
288 int i;
289 unsigned char *codeptr;
290 unsigned char *quickcodeptr;
291 unsigned char *quicklenptr;
292
293 codeptr = codetbl;
294 quickcodeptr = quickcodetbl;
295 quicklenptr = quicklentbl;
296
297 for (bits=1; bits<=mostbits; ++bits)
298 {
299 bitnum = bitnumtbl[bits];
300 if (bits>=9)
301 break;
302 numbitentries = 1<<(8-bits);
303
304 while (bitnum--)
305 {
306 nextcode = *codeptr++;
307 nextlen = bits;
308 if (nextcode==clue)
309 {
310 cluelen = bits;
311 nextlen = 96; /* will force out of main loop */
312 }
313 for (i=0; i<numbitentries; ++i)
314 {
315 *quickcodeptr++ = (unsigned char) nextcode;
316 *quicklenptr++ = (unsigned char) nextlen;
317 }
318 }
319 }
320 }
321 }
322
323/****************************************************************/
324/* Main decoder */
325/****************************************************************/
326
327 for (;;)
328 {
329 unsigned char *quickcodeptr = quickcodetbl;
330 unsigned char *quicklenptr = quicklentbl;
331
332 goto nextloop;
333
334/* quick 8 fetch */
335
336 do
337 {
338
339 *qd++ = quickcodeptr[bits>>24];
340 GET16BITS();
341 bits = bitsunshifted<<(16-bitsleft);
342
343/* quick 8 decode */
344
345nextloop:
346 numbits = quicklenptr[bits>>24];
347 bitsleft -= numbits;
348
349 if (bitsleft>=0)
350 {
351 do
352 {
353 *qd++ = quickcodeptr[bits>>24];
354 bits <<= numbits;
355
356 numbits = quicklenptr[bits>>24];
357 bitsleft -= numbits;
358 if (bitsleft<0) break;
359 *qd++ = quickcodeptr[bits>>24];
360 bits <<= numbits;
361
362 numbits = quicklenptr[bits>>24];
363 bitsleft -= numbits;
364 if (bitsleft<0) break;
365 *qd++ = quickcodeptr[bits>>24];
366 bits <<= numbits;
367
368 numbits = quicklenptr[bits>>24];
369 bitsleft -= numbits;
370 if (bitsleft<0) break;
371 *qd++ = quickcodeptr[bits>>24];
372 bits <<= numbits;
373
374 numbits = quicklenptr[bits>>24];
375 bitsleft -= numbits;
376
377 } while (bitsleft>=0);
378 }
379 bitsleft += 16;
380
381 } while (bitsleft>=0); /* would fetching 16 bits do it? */
382
383 bitsleft = bitsleft-16+numbits; /* back to normal */
384
385/****************************************************************/
386/* 16 bit decoder */
387/****************************************************************/
388
389 {
390 unsigned char code;
391
392
393 if (numbits!=96)
394 {
395 cmp = (unsigned int) (bits>>16); /* 16 bit left justified compare */
396
397 numbits = 8;
398 do
399 {
400 ++numbits;
401 }
402 while (cmp>=cmptbl[numbits]);
403 }
404 else
405 numbits = cluelen;
406
407
408 cmp = bits >> (32-(numbits));
409 bits <<= (numbits);
410 bitsleft -= (numbits);
411
412 code = codetbl[cmp-deltatbl[numbits]]; /* the code */
413
414 if (code!=clue && bitsleft>=0)
415 {
416 *qd++ = code;
417 goto nextloop;
418 }
419
420 if (bitsleft<0)
421 {
422 GET16BITS();
423 bits = bitsunshifted<<-bitsleft;
424 bitsleft += 16;
425 }
426
427 if (code!=clue)
428 {
429 *qd++ = code;
430 goto nextloop;
431 }
432
433 /* handle clue */
434
435 {
436 int runlen=0;
437 unsigned char *d=qd;
438 unsigned char *dest;
439
440 SQgetnum(runlen);
441 if (runlen) /* runlength sequence */
442 {
443 dest = d+runlen;
444 code = *(d-1);
445 do
446 {
447 *d++ = code;
448 } while (d<dest);
449
450 qd = d;
451 goto nextloop;
452 }
453 }
454
455 SQgetbits(v,1); /* End Of File */
456 if (v)
457 break;
458
459 {
460 unsigned int t;
461 SQgetbits(t,8); /* explicite byte */
462 code = (unsigned char)t;
463 }
464 *qd++ = code;
465 goto nextloop;
466 }
467
468 }
469
470
471/****************************************************************/
472/* Undelta */
473/****************************************************************/
474
475 {
476 int i;
477 int nextchar;
478
479 if (type==0x32fb || type==0xb2fb) /* deltaed? */
480 {
481 i = 0;
482 qd = unpackbuf;
483 while (qd<unpackbuf+ulen)
484 {
485 i += (int) *qd;
486 *qd++ = (unsigned char) i;
487 }
488 }
489 else if (type==0x34fb || type==0xb4fb) /* accelerated? */
490 {
491
492 i = 0;
493 nextchar = 0;
494 qd = unpackbuf;
495 while (qd<unpackbuf+ulen)
496 {
497 i += (int) *qd;
498 nextchar += i;
499 *qd++ = (unsigned char) nextchar;
500 }
501 }
502 }
503 }
504 }
505 return(ulen);
506}
507
508#if defined(_MSC_VER)
509#pragma warning(pop)
510#endif
511
512/****************************************************************/
513/* Information Functions */
514/****************************************************************/
515
516/* check for reasonable header: */
517/* 30fb..35fb header */
518
519bool GCALL HUFF_is(const void *compresseddata)
520{
521 bool ok=false;
522 int packtype=ggetm(compresseddata,2);
523
524 if (packtype==0x30fb
525 || packtype==0x31fb
526 || packtype==0x32fb
527 || packtype==0x33fb
528 || packtype==0x34fb
529 || packtype==0x35fb
530 || packtype==0xb0fb
531 || packtype==0xb1fb
532 || packtype==0xb2fb
533 || packtype==0xb3fb
534 || packtype==0xb4fb
535 || packtype==0xb5fb)
536 ok = true;
537
538 return(ok);
539}
540
541
542/****************************************************************/
543/* Decode Functions */
544/****************************************************************/
545
546int GCALL HUFF_size(const void *compresseddata)
547{
548 int len=0;
549 int packtype=ggetm(compresseddata,2);
550 int ssize=(packtype&0x8000)?4:3;
551
552 if (packtype&0x100) /* 31fb 33fb 35fb */
553 {
554 len = ggetm((char *)compresseddata+2+ssize,ssize);
555 }
556 else /* 30fb 32fb 34fb */
557 {
558 len = ggetm((char *)compresseddata+2,ssize);
559 }
560
561 return(len);
562}
563
564int GCALL HUFF_decode(void *dest, const void *compresseddata, int *compressedsize)
565{
566 return(HUFF_decompress((unsigned char *)compresseddata, (unsigned char *)dest));
567}
568
569#endif
570
#define ZERO
#define GCALL
Definition codex.h:81
#define GET16BITS()
bool GCALL HUFF_is(const void *compresseddata)
int GCALL HUFF_decode(void *dest, const void *compresseddata, int *compressedsize)
#define SQmemset(ptr, val, amt)
int GCALL HUFF_size(const void *compresseddata)
#define SQgetbits(v, n)
#define SQgetnum(v)
unsigned char * s
unsigned int bits