refencode.cpp 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  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. // Copyright (C) Electronic Arts Canada Inc. 1995-2002. All rights reserved.
  19. #ifndef __REFWRITE
  20. #define __REFWRITE 1
  21. #include <string.h>
  22. #include "codex.h"
  23. #include "refcodex.h"
  24. /****************************************************************/
  25. /* Internal Functions */
  26. /****************************************************************/
  27. static unsigned int matchlen(unsigned char *s,unsigned char *d, unsigned int maxmatch)
  28. {
  29. unsigned int current;
  30. for (current=0; current<maxmatch && *s++==*d++; ++current)
  31. ;
  32. return(current);
  33. }
  34. #define HASH(cptr) (int)((((unsigned int)(unsigned char)cptr[0]<<8) | ((unsigned int)(unsigned char)cptr[2])) ^ ((unsigned int)(unsigned char)cptr[1]<<4))
  35. static int refcompress(unsigned char *from, int len, unsigned char *dest, int maxback, int quick)
  36. {
  37. unsigned int tlen;
  38. unsigned int tcost;
  39. // unsigned int ccost; // context cost
  40. unsigned int run;
  41. unsigned int toffset;
  42. unsigned int boffset;
  43. unsigned int blen;
  44. unsigned int bcost;
  45. unsigned int mlen;
  46. unsigned char *tptr;
  47. unsigned char *cptr;
  48. unsigned char *to;
  49. unsigned char *rptr;
  50. int countliterals=0;
  51. int countshort=0;
  52. int countint=0;
  53. int countvint=0;
  54. int hash;
  55. int hoffset;
  56. int minhoffset;
  57. int i;
  58. int *link;
  59. int *hashtbl;
  60. to = dest;
  61. run = 0;
  62. cptr = rptr = from;
  63. if ((unsigned int)maxback > (unsigned int)131071)
  64. maxback = 131071;
  65. hashtbl = (int *) galloc(65536L*sizeof(int));
  66. if (!hashtbl)
  67. return(0);
  68. link = (int *) galloc(131072L*sizeof(int));
  69. if (!link)
  70. return(0);
  71. memset(hashtbl,-1,65536L*sizeof(int));
  72. len -= 4;
  73. while (len>=0)
  74. {
  75. boffset = 0;
  76. blen = 2;
  77. bcost = 2;
  78. // ccost = 0;
  79. mlen = qmin(len,1028);
  80. tptr=cptr-1;
  81. hash = HASH(cptr);
  82. hoffset = hashtbl[hash];
  83. minhoffset = qmax(cptr-from-131071,0);
  84. if (hoffset>=minhoffset)
  85. {
  86. do
  87. {
  88. tptr = from+hoffset;
  89. if (cptr[blen]==tptr[blen])
  90. {
  91. tlen = matchlen(cptr,tptr,mlen);
  92. if (tlen > blen)
  93. {
  94. toffset = (cptr-1)-tptr;
  95. if (toffset<1024 && tlen<=10) /* two byte int form */
  96. tcost = 2;
  97. else if (toffset<16384 && tlen<=67) /* three byte int form */
  98. tcost = 3;
  99. else /* four byte very int form */
  100. tcost = 4;
  101. if (tlen-tcost+4 > blen-bcost+4)
  102. {
  103. blen = tlen;
  104. bcost = tcost;
  105. boffset = toffset;
  106. if (blen>=1028) break;
  107. }
  108. }
  109. }
  110. } while ((hoffset = link[hoffset&131071]) >= minhoffset);
  111. }
  112. // ccost = 0;
  113. // if ((run<4) && ((run+blen)>=4))
  114. // ccost = 1; // extra packet cost to switch out of literal into reference
  115. // if (bcost>blen || (blen<=2 && bcost==blen && !ccost) || (len<4))
  116. if (bcost>=blen || len<4)
  117. {
  118. hoffset = (cptr-from);
  119. link[hoffset&131071] = hashtbl[hash];
  120. hashtbl[hash] = hoffset;
  121. ++run;
  122. ++cptr;
  123. --len;
  124. }
  125. else
  126. {
  127. while (run>3) /* literal block of data */
  128. {
  129. tlen = qmin(112,run&~3);
  130. run -= tlen;
  131. *to++ = (unsigned char) (0xe0+(tlen>>2)-1);
  132. memcpy(to,rptr,tlen);
  133. rptr += tlen;
  134. to += tlen;
  135. ++countliterals;
  136. }
  137. if (bcost==2) /* two byte int form */
  138. {
  139. *to++ = (unsigned char) (((boffset>>8)<<5) + ((blen-3)<<2) + run);
  140. *to++ = (unsigned char) boffset;
  141. ++countshort;
  142. }
  143. else if (bcost==3) /* three byte int form */
  144. {
  145. *to++ = (unsigned char) (0x80 + (blen-4));
  146. *to++ = (unsigned char) ((run<<6) + (boffset>>8));
  147. *to++ = (unsigned char) boffset;
  148. ++countint;
  149. }
  150. else /* four byte very int form */
  151. {
  152. *to++ = (unsigned char) (0xc0 + ((boffset>>16)<<4) + (((blen-5)>>8)<<2) + run);
  153. *to++ = (unsigned char) (boffset>>8);
  154. *to++ = (unsigned char) (boffset);
  155. *to++ = (unsigned char) (blen-5);
  156. ++countvint;
  157. }
  158. if (run)
  159. {
  160. memcpy(to, rptr, run);
  161. to += run;
  162. run = 0;
  163. }
  164. if (quick)
  165. {
  166. hoffset = (cptr-from);
  167. link[hoffset&131071] = hashtbl[hash];
  168. hashtbl[hash] = hoffset;
  169. cptr += blen;
  170. }
  171. else
  172. {
  173. for (i=0; i < (int)blen; ++i)
  174. {
  175. hash = HASH(cptr);
  176. hoffset = (cptr-from);
  177. link[hoffset&131071] = hashtbl[hash];
  178. hashtbl[hash] = hoffset;
  179. ++cptr;
  180. }
  181. }
  182. rptr = cptr;
  183. len -= blen;
  184. }
  185. }
  186. len += 4;
  187. run += len;
  188. while (run>3) /* no match at end, use literal */
  189. {
  190. tlen = qmin(112,run&~3);
  191. run -= tlen;
  192. *to++ = (unsigned char) (0xe0+(tlen>>2)-1);
  193. memcpy(to,rptr,tlen);
  194. rptr += tlen;
  195. to += tlen;
  196. }
  197. *to++ = (unsigned char) (0xfc+run); /* end of stream command + 0..3 literal */
  198. if (run)
  199. {
  200. memcpy(to,rptr,run);
  201. to += run;
  202. }
  203. gfree(link);
  204. gfree(hashtbl);
  205. return(to-dest);
  206. }
  207. /****************************************************************/
  208. /* Encode Function */
  209. /****************************************************************/
  210. int GCALL REF_encode(void *compresseddata, const void *source, int sourcesize, int *opts)
  211. {
  212. int maxback=131072;
  213. int quick=0;
  214. int plen;
  215. int hlen;
  216. /* simple fb6 header */
  217. if (sourcesize>0xffffff) // 32 bit header required
  218. {
  219. gputm(compresseddata, (unsigned int) 0x90fb, 2);
  220. gputm((char *)compresseddata+2, (unsigned int) sourcesize, 4);
  221. hlen = 6L;
  222. }
  223. else
  224. {
  225. gputm(compresseddata, (unsigned int) 0x10fb, 2);
  226. gputm((char *)compresseddata+2, (unsigned int) sourcesize, 3);
  227. hlen = 5L;
  228. }
  229. plen = hlen+refcompress((unsigned char *)source, sourcesize, (unsigned char *)compresseddata+hlen, maxback, quick);
  230. return(plen);
  231. }
  232. #endif