Richard Boegli's CnC_Generals_Zero_Hour Fork WIP
This is documentation of Richard Boegil's Zero Hour Fork
 
Loading...
Searching...
No Matches
btreeencode.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 __BTRWRITE
22#define __BTRWRITE 1
23
24#include <string.h>
25#include "codex.h"
26#include "btreecodex.h"
27
28/****************************************************************/
29/* Internal Functions */
30/****************************************************************/
31
32#define BTREEWORD short
33#define BTREECODES 256
34#define BTREEBIGNUM 32000
35#define BTREESLOPAGE 16384
36
38{
39 char *ptr;
40 int len;
41};
42
44{
45 unsigned int packbits;
46 unsigned int workpattern;
47 unsigned char *bufptr;
48 unsigned int ulen;
49 unsigned int masks[17];
50 unsigned char clueq[BTREECODES];
51 unsigned char right[BTREECODES];
52 unsigned char join[BTREECODES];
53 unsigned int plen;
54 unsigned char *bufbase;
55 unsigned char *bufend;
56 unsigned char *buffer;
57 unsigned char *buf1;
58 unsigned char *buf2;
59};
60
61static void BTREE_writebits(struct BTreeEncodeContext *EC,
62 struct BTREEMemStruct *dest,
63 unsigned int bitpattern,
64 unsigned int len)
65{
66 if (len > 16)
67 {
68 BTREE_writebits(EC,dest,(unsigned int) (bitpattern>>16), len-16);
69 BTREE_writebits(EC,dest,(unsigned int) bitpattern, 16);
70 }
71 else
72 {
73 EC->packbits += len;
74 EC->workpattern += (bitpattern & EC->masks[len]) << (24-EC->packbits);
75 while (EC->packbits > 7)
76 {
77 *(dest->ptr+dest->len) = (unsigned char) (EC->workpattern >> 16);
78 ++dest->len;
79
80 EC->workpattern = EC->workpattern << 8;
81 EC->packbits -= 8;
82 ++EC->plen;
83 }
84 }
85}
86
87
88static void BTREE_adjcount(unsigned char *s, unsigned char *bend, BTREEWORD *count)
89{
90
91#ifdef __WATCOMC__
92
93 union
94 {
95 unsigned char b[4];
96 int w;
97 } i;
98
99 #define COUNTADJ(j) i.b[1] = i.b[0]; i.b[0] = *(s+j); ++count[i.w];
100
101 i.w = 0;
102 i.b[0] = (unsigned BTREEWORD) *s++;
103
104#else
105
106 unsigned BTREEWORD i;
107
108 #define COUNTADJ(j) i = (BTREEWORD)(((i<<8) | *(s+j))); ++*(count+(int)i);
109
110 i = (unsigned BTREEWORD) *s++;
111
112#endif
113
114 bend -= 16;
115
116 if (s<bend)
117 {
118 do
119 {
120 COUNTADJ(0);
121 COUNTADJ(1);
122 COUNTADJ(2);
123 COUNTADJ(3);
124
125 COUNTADJ(4);
126 COUNTADJ(5);
127 COUNTADJ(6);
128 COUNTADJ(7);
129
130 COUNTADJ(8);
131 COUNTADJ(9);
132 COUNTADJ(10);
133 COUNTADJ(11);
134
135 COUNTADJ(12);
136 COUNTADJ(13);
137 COUNTADJ(14);
138 COUNTADJ(15);
139 s += 16;
140
141 } while (s<bend);
142 }
143
144 bend += 16;
145
146 if (s<bend)
147 {
148 do
149 {
150 COUNTADJ(0);
151 ++s;
152
153 } while (s<bend);
154 }
155}
156
157/* Clear 128 ints (256 words). Done as ints for speed. */
158
159static void BTREE_clearcount(unsigned char *tryq,BTREEWORD *countbuf)
160{
161 int zero=0;
162 int i;
163 int j;
164 int *intptr;
165
166 intptr = (int *) countbuf;
167 j = 256;
168 do
169 {
170 if (*tryq)
171 {
172 *tryq++ = 1;
173
174 i = 8;
175 do
176 {
177 *(intptr+0) = zero;
178 *(intptr+1) = zero;
179 *(intptr+2) = zero;
180 *(intptr+3) = zero;
181
182 *(intptr+4) = zero;
183 *(intptr+5) = zero;
184 *(intptr+6) = zero;
185 *(intptr+7) = zero;
186
187 *(intptr+8) = zero;
188 *(intptr+9) = zero;
189 *(intptr+10) = zero;
190 *(intptr+11) = zero;
191
192 *(intptr+12) = zero;
193 *(intptr+13) = zero;
194 *(intptr+14) = zero;
195 *(intptr+15) = zero;
196 intptr += 16;
197
198 } while (--i);
199 }
200 else
201 {
202 ++tryq;
203 intptr += 128;
204 }
205 } while (--j);
206}
207
208static void BTREE_joinnodes(struct BTreeEncodeContext *EC,
209 unsigned char *cluep,
210 unsigned char *rightp,
211 unsigned char *joinp,
212 unsigned int clue)
213{
214 unsigned char *s;
215 unsigned char *d;
216 unsigned char *bend;
217 unsigned int i;
218
219 /* pack file */
220
221 s = EC->bufbase;
222 if (s==EC->buf1)
223 {
224 d = EC->buf2;
225 }
226 else
227 {
228 d = EC->buf1;
229 }
230 EC->bufbase = d;
231 bend = EC->bufend;
232
233 *bend = (unsigned char) clue;
234 while (s<=bend)
235 {
236 while (!cluep[(unsigned int) (*d++ = *s++)])
237 ;
238
239 i = (unsigned int) *(s-1);
240
241 if (cluep[i]==1)
242 { if (*s==rightp[i])
243 { *(d-1) = joinp[i];
244 ++s;
245 }
246 }
247 else
248 { if (cluep[i]==3)
249 { *(d-1) = (unsigned char) clue;
250 *d++ = *(s-1);
251 }
252 else
253 *d++ = *s++;
254 }
255 }
256 EC->bufend = d-2;
257}
258
259
260/* find 48 most common nodes */
261
262static unsigned int BTREE_findbest(BTREEWORD *countptr,
263 unsigned char *tryq,
264 unsigned int *bestn,
265 unsigned int *bestval,
266 int ratio)
267{
268 unsigned int i;
269 unsigned int i1;
270 unsigned int i2;
271 unsigned int bestsize;
272
273 unsigned int i3;
274 unsigned int l;
275
276 bestsize = 1;
277 i = 3;
278 l = 0;
279 for (i2=0;i2<256;++i2)
280 {
281 if (tryq[i2])
282 { for (i1=0;i1<256;++i1)
283 {
284 if (*countptr++>(BTREEWORD)i)
285 {
286 if (tryq[i1])
287 { i = *(countptr-1);
288 i3=bestsize;
289 while (bestval[i3-1]<i)
290 {
291 bestn[i3] = bestn[i3-1];
292 bestval[i3] = bestval[i3-1];
293 --i3;
294 }
295 bestn[i3] = l+i1;
296 bestval[i3] = i;
297 if (bestsize<48)
298 ++bestsize;
299 while (bestval[bestsize-1]<(bestval[1]/ratio))
300 --bestsize;
301 if (bestsize<48)
302 i = bestval[1]/ratio;
303 else
304 i = bestval[bestsize-1];
305 }
306 }
307 }
308 }
309 else
310 countptr += 256;
311 l += 256;
312 }
313 return(bestsize);
314}
315
316static void BTREE_treepack(struct BTreeEncodeContext *EC,
317 struct BTREEMemStruct *dest,
318 unsigned int passes,
319 unsigned int multimax,
320 unsigned int quick,
321 int zerosuppress)
322{
323
324 unsigned char *bend;
325 unsigned char *ptr1;
326 unsigned char *treebuf;
327 BTREEWORD *count;
328 unsigned int i;
329 unsigned int i1;
330
331 int joinnode, leftnode, rightnode;
332 int ratio;
333 unsigned int hlen;
334 unsigned int domore;
335 unsigned int cost, save;
336 unsigned int tcost, tsave;
337 unsigned int clue;
338
339 unsigned int freeptr;
340 unsigned int count2[BTREECODES];
341 unsigned char tryq[BTREECODES];
342 unsigned char freeq[BTREECODES];
343
344 unsigned int bestsize;
345 unsigned char bestjoin[BTREECODES];
346 unsigned int bestn[BTREECODES];
347 unsigned int bestval[BTREECODES];
348
349 unsigned int bt_size;
350 unsigned int bt_node[BTREECODES];
351 unsigned int bt_left[BTREECODES];
352 unsigned int bt_right[BTREECODES];
353 unsigned int sortptr[BTREECODES];
354
355 int treebufsize;
356 int buf1size;
357 int buf2size;
358
359 // 3/2 allows for worst case, where 2nd most popular
360 treebufsize = 65536L*sizeof(BTREEWORD); /* 131K */
361 buf1size = EC->ulen*3/2+(int)BTREESLOPAGE;
362 buf2size = EC->ulen*3/2+(int)BTREESLOPAGE;
363
364 treebuf = (unsigned char *) galloc(treebufsize);
365 if (!treebuf)
366 return; /* failure Insufficient memory for work buffer */
367
368 EC->buf1 = (unsigned char *) galloc(buf1size);
369 if (!EC->buf1)
370 return; /* failure Insufficient memory for work buffer */
371
372 EC->buf2 = (unsigned char *) galloc(buf2size);
373 if (!EC->buf2)
374 return; /* failure Insufficient memory for work buffer */
375
376 memcpy(EC->buf1, EC->buffer, EC->ulen); /* copy to scratch buffer */
377
378 EC->buffer = EC->buf1;
379 EC->bufptr = EC->buf1+EC->ulen;
380
381 EC->bufbase = EC->buffer;
382 EC->bufend = EC->bufptr;
383
384 count = (BTREEWORD *) treebuf;
385
386 if (quick) ratio = quick;
387 else ratio = 2;
388
389/*** count file ***/
390
391 for (i=0; i<BTREECODES; ++i)
392 count2[i] = 0;
393
394 i1 = 0;
395 bend = EC->bufptr;
396 ptr1 = EC->buffer;
397 while (ptr1<bend)
398 { i = (unsigned int) *ptr1++;
399 i1 = i1 + i;
400 ++count2[i];
401 }
402
403/* init clue array */
404
405 for (i=0;i<BTREECODES;++i)
406 EC->clueq[i] = 0;
407
408/* get a clue byte (forced) */
409
410 for(i=0; i<BTREECODES; ++i)
411 { freeq[i] = 1;
412 if (count2[i]>3)
413 tryq[i] = 1;
414 else
415 tryq[i] = 0;
416 }
417
418/* don't use 0 for clue or node (so that [clue][0] is reserved for EOF) */
419
420 count2[0] = BTREEBIGNUM; /* don't use for clue or node */
421
422/* asciiz btree suppress packing of 0..31 */
423
424 if (zerosuppress)
425 {
426 for (i=0; i<32; ++i)
427 {
428 count2[i] = BTREEBIGNUM; /* don't use for nodes */
429 tryq[i] = 0; /* don't try to pack */
430 freeq[i] = 0; /* don't try to pack */
431 }
432 }
433
434
435/* sort codes with least used codes first */
436/* primary key is count, secondary key is higher code */
437
438/* registers vars usage
439 i - code
440 i1 - done flag/swap temp
441*/
442
443 for (i=0;i<BTREECODES;++i)
444 sortptr[i] = i;
445
446 i1=1;
447 while (i1)
448 {
449 i1 = 0;
450 for (i=1; i<BTREECODES; ++i)
451 {
452 if (count2[sortptr[i]]<count2[sortptr[i-1]] || ((count2[sortptr[i]]==count2[sortptr[i-1]]) && (sortptr[i]>sortptr[i-1])))
453 {
454 i1 = sortptr[i];
455 sortptr[i] = sortptr[i-1];
456 sortptr[i-1] = i1;
457 i1 = 1;
458 }
459 }
460 }
461
462 freeptr = 0;
463 i = sortptr[freeptr++];
464 clue = (unsigned char) i;
465 freeq[i] = 0;
466 tryq[i] = 0;
467 EC->clueq[i] = 3;
468
469 if (count2[i])
470 BTREE_joinnodes(EC,EC->clueq, EC->right, EC->join, clue);
471
472 EC->clueq[i] = 2;
473
474/* init best array */
475
476 bestval[0] = (unsigned int) -1;
477
478
479/* count file (pass 2) */
480
481 bt_size = 0;
482 domore = passes;
483 while (domore)
484 {
485
486/* clear count array */
487
488 BTREE_clearcount(tryq,count);
489
490/* do an adjacency count */
491
492 ptr1 = EC->bufbase;
493 bend = EC->bufend;
494
495 BTREE_adjcount(ptr1, bend, count);
496
497/* find most common nodes */
498
499 bestsize = BTREE_findbest(count,tryq,bestn,bestval,ratio);
500
501/* decide which nodes should be joined to what */
502
503 domore = 0;
504 if (bestsize>1)
505 {
506 tcost = tsave = 0;
507 i = i1 = domore = 1;
508 while (domore)
509 {
510 leftnode = (bestn[i]>>8)&255;
511 rightnode = bestn[i]&255;
512
513 if ((tryq[leftnode]==1) && (tryq[rightnode]==1))
514 {
515 domore = 0;
516 while ((freeptr<BTREECODES) && (!freeq[sortptr[freeptr]]))
517 ++freeptr;
518
519 if (freeptr<BTREECODES)
520 {
521 joinnode = sortptr[freeptr];
522
523 cost = 3+count2[joinnode];
524 save = bestval[i];
525
526 if (cost<save)
527 {
528 tcost += cost;
529 tsave += save;
530
531 bestjoin[i1] = (unsigned char) joinnode;
532 bestn[i1] = bestn[i];
533 ++i1;
534
535 freeq[joinnode] = 0;
536 tryq[joinnode] = 2;
537 EC->clueq[joinnode] = 3;
538
539 freeq[leftnode] = 0;
540 tryq[leftnode] = 2;
541 EC->clueq[leftnode] = 1;
542 EC->right[leftnode] = (unsigned char) rightnode;
543 EC->join[leftnode] = (unsigned char) joinnode;
544
545 freeq[rightnode] = 0;
546 tryq[rightnode] = 2;
547
548 bt_node[bt_size] = joinnode;
549 bt_left[bt_size] = leftnode;
550 bt_right[bt_size] = rightnode;
551 ++bt_size;
552
553 if (i1<=multimax)
554 domore = 1;
555 }
556 }
557 }
558
559 ++i;
560 if (i>=bestsize)
561 domore = 0;
562 }
563
564 bestsize = i1;
565
566 if (bestsize>1)
567 {
568 /* multijoin nodes */
569
570 BTREE_joinnodes(EC,EC->clueq, EC->right, EC->join, clue);
571
572 /* restore clue table */
573
574 for(i=1;i<bestsize;++i)
575 { leftnode = (bestn[i]>>8)&255;
576 joinnode = bestjoin[i];
577 EC->clueq[leftnode] = EC->clueq[joinnode] = 0;
578 }
579
580 domore = --passes;
581 }
582
583 }
584
585 }
586 EC->bufptr = EC->bufend;
587
588/* write header */
589
590 BTREE_writebits(EC,dest,(unsigned int) clue, 8); /* clue byte */
591 BTREE_writebits(EC,dest,(unsigned int) bt_size, 8); /* tree size */
592
593 for (i=0; i<bt_size;++i)
594 { BTREE_writebits(EC,dest,(unsigned int) bt_node[i], 8);
595 BTREE_writebits(EC,dest,(unsigned int) bt_left[i], 8);
596 BTREE_writebits(EC,dest,(unsigned int) bt_right[i], 8);
597 }
598
599 hlen = EC->plen;
600
601/*** write packed file ***/
602
603 ptr1 = EC->bufbase;
604 bend = EC->bufend;
605
606 while (ptr1<bend)
607 BTREE_writebits(EC,dest,(unsigned int) *ptr1++, 8);
608
609 BTREE_writebits(EC,dest,(unsigned int) clue, 8);
610 BTREE_writebits(EC,dest,(unsigned int) 0, 8);
611
612 BTREE_writebits(EC,dest,0L,7); /* flush bits */
613
614 gfree(EC->buf2);
615 gfree(EC->buf1);
616 gfree(treebuf);
617}
618
619static int BTREE_compressfile(struct BTreeEncodeContext *EC,
620 struct BTREEMemStruct *infile,
621 struct BTREEMemStruct *outfile,
622 int ulen,
623 int zerosuppress)
624{
625 unsigned int i;
626
627 unsigned int passes;
628 unsigned int multimax;
629 int flen;
630
631/* set defaults */
632
633 EC->packbits = 0;
634
635 EC->workpattern = 0L;
636 passes = 256;
637 multimax = 32;
638 EC->masks[0] = 0;
639 for (i=1;i<17;++i)
640 EC->masks[i] = (EC->masks[i-1] << 1) + 1;
641
642/* read in a source file */
643
644 EC->buffer = (unsigned char *) (infile->ptr);
645 flen = infile->len;
646
647 EC->ulen = flen;
648 EC->bufptr = EC->buffer + flen;
649
650/* pack a file */
651
652 outfile->ptr = outfile->ptr;
653 outfile->len = 0L;
654
655 EC->packbits = 0;
656 EC->workpattern = 0L;
657 EC->plen = 0L;
658
659/* write standard header stuff (type/signature/ulen/adjust) */
660
661 /* simple fb6 header */
662
663 if (ulen==infile->len)
664 {
665 BTREE_writebits(EC,outfile,(unsigned int) 0x46fb, 16);
666 BTREE_writebits(EC,outfile,(unsigned int) infile->len, 24);
667 }
668
669 /* composite fb6 header */
670
671 else
672 {
673 BTREE_writebits(EC,outfile,(unsigned int) 0x47fb, 16);
674 BTREE_writebits(EC,outfile,(unsigned int) ulen, 24);
675 BTREE_writebits(EC,outfile,(unsigned int) infile->len, 24);
676 }
677
678 BTREE_treepack(EC,outfile,passes, multimax, 0, zerosuppress);
679
680 return(outfile->len);
681}
682
683
684
685/****************************************************************/
686/* Encode Function */
687/****************************************************************/
688
689int GCALL BTREE_encode(void *compresseddata, const void *source, int sourcesize, int *opts)
690{
691 int plen;
692 struct BTREEMemStruct infile;
693 struct BTREEMemStruct outfile;
694 struct BTreeEncodeContext EC;
695 int opt=0;
696 if (opts)
697 opt = opts[0];
698
699 infile.ptr = (char *)source;
700 infile.len = sourcesize;
701 outfile.ptr = (char *)compresseddata;
702 outfile.len = sourcesize;
703
704 plen = BTREE_compressfile(&EC,&infile, &outfile, sourcesize, opt);
705
706 return(plen);
707}
708
709#endif
710
#define gfree
Definition gimex.h:360
#define galloc
Definition gimex.h:356
#define BTREESLOPAGE
#define BTREEBIGNUM
#define BTREEWORD
#define COUNTADJ(j)
#define BTREECODES
int GCALL BTREE_encode(void *compresseddata, const void *source, int sourcesize, int *opts)
#define GCALL
Definition codex.h:81
unsigned int packbits
unsigned char join[BTREECODES]
unsigned int masks[17]
unsigned char * buf2
unsigned char * bufend
unsigned int ulen
unsigned int plen
unsigned int workpattern
unsigned char * buf1
unsigned char right[BTREECODES]
unsigned char * bufbase
unsigned char * buffer
unsigned char clueq[BTREECODES]
unsigned char * bufptr