/* ** Command & Conquer Generals Zero Hour(tm) ** Copyright 2025 Electronic Arts Inc. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . */ // Copyright (C) Electronic Arts Canada Inc. 1995-2002. All rights reserved. #ifndef __BTRWRITE #define __BTRWRITE 1 #include #include "codex.h" #include "btreecodex.h" /****************************************************************/ /* Internal Functions */ /****************************************************************/ #define BTREEWORD short #define BTREECODES 256 #define BTREEBIGNUM 32000 #define BTREESLOPAGE 16384 struct BTREEMemStruct { char *ptr; int len; }; struct BTreeEncodeContext { unsigned int packbits; unsigned int workpattern; unsigned char *bufptr; unsigned int ulen; unsigned int masks[17]; unsigned char clueq[BTREECODES]; unsigned char right[BTREECODES]; unsigned char join[BTREECODES]; unsigned int plen; unsigned char *bufbase; unsigned char *bufend; unsigned char *buffer; unsigned char *buf1; unsigned char *buf2; }; static void BTREE_writebits(struct BTreeEncodeContext *EC, struct BTREEMemStruct *dest, unsigned int bitpattern, unsigned int len) { if (len > 16) { BTREE_writebits(EC,dest,(unsigned int) (bitpattern>>16), len-16); BTREE_writebits(EC,dest,(unsigned int) bitpattern, 16); } else { EC->packbits += len; EC->workpattern += (bitpattern & EC->masks[len]) << (24-EC->packbits); while (EC->packbits > 7) { *(dest->ptr+dest->len) = (unsigned char) (EC->workpattern >> 16); ++dest->len; EC->workpattern = EC->workpattern << 8; EC->packbits -= 8; ++EC->plen; } } } static void BTREE_adjcount(unsigned char *s, unsigned char *bend, BTREEWORD *count) { #ifdef __WATCOMC__ union { unsigned char b[4]; int w; } i; #define COUNTADJ(j) i.b[1] = i.b[0]; i.b[0] = *(s+j); ++count[i.w]; i.w = 0; i.b[0] = (unsigned BTREEWORD) *s++; #else unsigned BTREEWORD i; #define COUNTADJ(j) i = (BTREEWORD)(((i<<8) | *(s+j))); ++*(count+(int)i); i = (unsigned BTREEWORD) *s++; #endif bend -= 16; if (sbufbase; if (s==EC->buf1) { d = EC->buf2; } else { d = EC->buf1; } EC->bufbase = d; bend = EC->bufend; *bend = (unsigned char) clue; while (s<=bend) { while (!cluep[(unsigned int) (*d++ = *s++)]) ; i = (unsigned int) *(s-1); if (cluep[i]==1) { if (*s==rightp[i]) { *(d-1) = joinp[i]; ++s; } } else { if (cluep[i]==3) { *(d-1) = (unsigned char) clue; *d++ = *(s-1); } else *d++ = *s++; } } EC->bufend = d-2; } /* find 48 most common nodes */ static unsigned int BTREE_findbest(BTREEWORD *countptr, unsigned char *tryq, unsigned int *bestn, unsigned int *bestval, int ratio) { unsigned int i; unsigned int i1; unsigned int i2; unsigned int bestsize; unsigned int i3; unsigned int l; bestsize = 1; i = 3; l = 0; for (i2=0;i2<256;++i2) { if (tryq[i2]) { for (i1=0;i1<256;++i1) { if (*countptr++>(BTREEWORD)i) { if (tryq[i1]) { i = *(countptr-1); i3=bestsize; while (bestval[i3-1]ulen*3/2+(int)BTREESLOPAGE; buf2size = EC->ulen*3/2+(int)BTREESLOPAGE; treebuf = (unsigned char *) galloc(treebufsize); if (!treebuf) return; /* failure Insufficient memory for work buffer */ EC->buf1 = (unsigned char *) galloc(buf1size); if (!EC->buf1) return; /* failure Insufficient memory for work buffer */ EC->buf2 = (unsigned char *) galloc(buf2size); if (!EC->buf2) return; /* failure Insufficient memory for work buffer */ memcpy(EC->buf1, EC->buffer, EC->ulen); /* copy to scratch buffer */ EC->buffer = EC->buf1; EC->bufptr = EC->buf1+EC->ulen; EC->bufbase = EC->buffer; EC->bufend = EC->bufptr; count = (BTREEWORD *) treebuf; if (quick) ratio = quick; else ratio = 2; /*** count file ***/ for (i=0; ibufptr; ptr1 = EC->buffer; while (ptr1clueq[i] = 0; /* get a clue byte (forced) */ for(i=0; i3) tryq[i] = 1; else tryq[i] = 0; } /* don't use 0 for clue or node (so that [clue][0] is reserved for EOF) */ count2[0] = BTREEBIGNUM; /* don't use for clue or node */ /* asciiz btree suppress packing of 0..31 */ if (zerosuppress) { for (i=0; i<32; ++i) { count2[i] = BTREEBIGNUM; /* don't use for nodes */ tryq[i] = 0; /* don't try to pack */ freeq[i] = 0; /* don't try to pack */ } } /* sort codes with least used codes first */ /* primary key is count, secondary key is higher code */ /* registers vars usage i - code i1 - done flag/swap temp */ for (i=0;isortptr[i-1]))) { i1 = sortptr[i]; sortptr[i] = sortptr[i-1]; sortptr[i-1] = i1; i1 = 1; } } } freeptr = 0; i = sortptr[freeptr++]; clue = (unsigned char) i; freeq[i] = 0; tryq[i] = 0; EC->clueq[i] = 3; if (count2[i]) BTREE_joinnodes(EC,EC->clueq, EC->right, EC->join, clue); EC->clueq[i] = 2; /* init best array */ bestval[0] = (unsigned int) -1; /* count file (pass 2) */ bt_size = 0; domore = passes; while (domore) { /* clear count array */ BTREE_clearcount(tryq,count); /* do an adjacency count */ ptr1 = EC->bufbase; bend = EC->bufend; BTREE_adjcount(ptr1, bend, count); /* find most common nodes */ bestsize = BTREE_findbest(count,tryq,bestn,bestval,ratio); /* decide which nodes should be joined to what */ domore = 0; if (bestsize>1) { tcost = tsave = 0; i = i1 = domore = 1; while (domore) { leftnode = (bestn[i]>>8)&255; rightnode = bestn[i]&255; if ((tryq[leftnode]==1) && (tryq[rightnode]==1)) { domore = 0; while ((freeptrclueq[joinnode] = 3; freeq[leftnode] = 0; tryq[leftnode] = 2; EC->clueq[leftnode] = 1; EC->right[leftnode] = (unsigned char) rightnode; EC->join[leftnode] = (unsigned char) joinnode; freeq[rightnode] = 0; tryq[rightnode] = 2; bt_node[bt_size] = joinnode; bt_left[bt_size] = leftnode; bt_right[bt_size] = rightnode; ++bt_size; if (i1<=multimax) domore = 1; } } } ++i; if (i>=bestsize) domore = 0; } bestsize = i1; if (bestsize>1) { /* multijoin nodes */ BTREE_joinnodes(EC,EC->clueq, EC->right, EC->join, clue); /* restore clue table */ for(i=1;i>8)&255; joinnode = bestjoin[i]; EC->clueq[leftnode] = EC->clueq[joinnode] = 0; } domore = --passes; } } } EC->bufptr = EC->bufend; /* write header */ BTREE_writebits(EC,dest,(unsigned int) clue, 8); /* clue byte */ BTREE_writebits(EC,dest,(unsigned int) bt_size, 8); /* tree size */ for (i=0; iplen; /*** write packed file ***/ ptr1 = EC->bufbase; bend = EC->bufend; while (ptr1buf2); gfree(EC->buf1); gfree(treebuf); } static int BTREE_compressfile(struct BTreeEncodeContext *EC, struct BTREEMemStruct *infile, struct BTREEMemStruct *outfile, int ulen, int zerosuppress) { unsigned int i; unsigned int passes; unsigned int multimax; int flen; /* set defaults */ EC->packbits = 0; EC->workpattern = 0L; passes = 256; multimax = 32; EC->masks[0] = 0; for (i=1;i<17;++i) EC->masks[i] = (EC->masks[i-1] << 1) + 1; /* read in a source file */ EC->buffer = (unsigned char *) (infile->ptr); flen = infile->len; EC->ulen = flen; EC->bufptr = EC->buffer + flen; /* pack a file */ outfile->ptr = outfile->ptr; outfile->len = 0L; EC->packbits = 0; EC->workpattern = 0L; EC->plen = 0L; /* write standard header stuff (type/signature/ulen/adjust) */ /* simple fb6 header */ if (ulen==infile->len) { BTREE_writebits(EC,outfile,(unsigned int) 0x46fb, 16); BTREE_writebits(EC,outfile,(unsigned int) infile->len, 24); } /* composite fb6 header */ else { BTREE_writebits(EC,outfile,(unsigned int) 0x47fb, 16); BTREE_writebits(EC,outfile,(unsigned int) ulen, 24); BTREE_writebits(EC,outfile,(unsigned int) infile->len, 24); } BTREE_treepack(EC,outfile,passes, multimax, 0, zerosuppress); return(outfile->len); } /****************************************************************/ /* Encode Function */ /****************************************************************/ int GCALL BTREE_encode(void *compresseddata, const void *source, int sourcesize, int *opts) { int plen; struct BTREEMemStruct infile; struct BTREEMemStruct outfile; struct BTreeEncodeContext EC; int opt=0; if (opts) opt = opts[0]; infile.ptr = (char *)source; infile.len = sourcesize; outfile.ptr = (char *)compresseddata; outfile.len = sourcesize; plen = BTREE_compressfile(&EC,&infile, &outfile, sourcesize, opt); return(plen); } #endif