LZO1X_C.CPP 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349
  1. /*
  2. ** Command & Conquer Red Alert(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. /* lzo1x_c.c -- standalone LZO1X-1 compressor
  19. This file is part of the LZO real-time data compression library.
  20. Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer
  21. The LZO library is free software; you can redistribute it and/or
  22. modify it under the terms of the GNU Library General Public
  23. License as published by the Free Software Foundation; either
  24. version 2 of the License, or (at your option) any later version.
  25. The LZO library is distributed in the hope that it will be useful,
  26. but WITHOUT ANY WARRANTY; without even the implied warranty of
  27. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  28. Library General Public License for more details.
  29. You should have received a copy of the GNU Library General Public
  30. License along with the LZO library; see the file COPYING.LIB.
  31. If not, write to the Free Software Foundation, Inc.,
  32. 675 Mass Ave, Cambridge, MA 02139, USA.
  33. Markus F.X.J. Oberhumer
  34. [email protected]
  35. */
  36. #include "lzo1x.h"
  37. #define NDEBUG
  38. #include <assert.h>
  39. #include "lzo_conf.h"
  40. #if !defined(LZO1X) && !defined(LZO1Y)
  41. # define LZO1X
  42. #endif
  43. /***********************************************************************
  44. //
  45. ************************************************************************/
  46. #define M1_MAX_OFFSET 0x0400
  47. #if defined(LZO1X)
  48. #define M2_MAX_OFFSET 0x0800
  49. #elif defined(LZO1Y)
  50. #define M2_MAX_OFFSET 0x0400
  51. #endif
  52. #define M3_MAX_OFFSET 0x4000
  53. #define M4_MAX_OFFSET 0xbfff
  54. #define MX_MAX_OFFSET (M1_MAX_OFFSET + M2_MAX_OFFSET)
  55. #define M1_MARKER 0
  56. #define M2_MARKER 64
  57. #define M3_MARKER 32
  58. #define M4_MARKER 16
  59. #define _DV2(p,shift1,shift2) \
  60. (((( (lzo_uint)(p[2]) << shift1) ^ p[1]) << shift2) ^ p[0])
  61. #define DVAL_NEXT(dv,p) \
  62. dv ^= p[-1]; dv = (((dv) >> 5) ^ ((lzo_uint)(p[2]) << (2*5)))
  63. #define _DV(p,shift) _DV2(p,shift,shift)
  64. #define DVAL_FIRST(dv,p) dv = _DV((p),5)
  65. #define _DINDEX(dv,p) ((40799u * (dv)) >> 5)
  66. #define DINDEX(dv,p) (((_DINDEX(dv,p)) & 0x3fff) << 0)
  67. #define UPDATE_D(dict,cycle,dv,p) dict[ DINDEX(dv,p) ] = (p)
  68. #define UPDATE_I(dict,cycle,index,p) dict[index] = (p)
  69. /***********************************************************************
  70. // compress a block of data.
  71. ************************************************************************/
  72. static int do_compress(const lzo_byte *in , lzo_uint in_len,
  73. lzo_byte *out, lzo_uint *out_len,
  74. lzo_voidp wrkmem )
  75. {
  76. register const lzo_byte *ip;
  77. lzo_uint dv;
  78. lzo_byte *op;
  79. const lzo_byte * const in_end = in + in_len;
  80. const lzo_byte * const ip_end = in + in_len - 9 - 4;
  81. const lzo_byte *ii;
  82. const lzo_bytepp const dict = (const lzo_bytepp) wrkmem;
  83. op = out;
  84. ip = in;
  85. ii = ip;
  86. DVAL_FIRST(dv,ip); UPDATE_D(dict,cycle,dv,ip); ip++;
  87. DVAL_NEXT(dv,ip); UPDATE_D(dict,cycle,dv,ip); ip++;
  88. DVAL_NEXT(dv,ip); UPDATE_D(dict,cycle,dv,ip); ip++;
  89. DVAL_NEXT(dv,ip); UPDATE_D(dict,cycle,dv,ip); ip++;
  90. while (1) {
  91. register const lzo_byte *m_pos;
  92. lzo_uint m_len;
  93. lzo_ptrdiff_t m_off;
  94. lzo_uint lit;
  95. lzo_uint dindex = DINDEX(dv,ip);
  96. m_pos = dict[dindex];
  97. UPDATE_I(dict,cycle,dindex,ip);
  98. if (LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,M4_MAX_OFFSET)) {
  99. }
  100. #if defined(LZO_UNALIGNED_OK_2)
  101. else
  102. if (* (unsigned short *) m_pos != * (unsigned short *) ip)
  103. #else
  104. else
  105. if (m_pos[0] != ip[0] || m_pos[1] != ip[1])
  106. #endif
  107. {
  108. } else {
  109. if (m_pos[2] == ip[2]) {
  110. lit = ip - ii;
  111. m_pos += 3;
  112. if (m_off <= M2_MAX_OFFSET)
  113. goto match;
  114. /* better compression, but slower */
  115. if (lit == 3) {
  116. assert(op - 2 > out); op[-2] |= LZO_BYTE(3);
  117. *op++ = *ii++; *op++ = *ii++; *op++ = *ii++;
  118. goto code_match;
  119. }
  120. if (*m_pos == ip[3]) {
  121. goto match;
  122. }
  123. } else {
  124. /* still need a better way for finding M1 matches */
  125. }
  126. }
  127. /* a literal */
  128. ++ip;
  129. if (ip >= ip_end) {
  130. break;
  131. }
  132. DVAL_NEXT(dv,ip);
  133. continue;
  134. /* a match */
  135. match:
  136. /* store current literal run */
  137. if (lit > 0) {
  138. register lzo_uint t = lit;
  139. if (t <= 3) {
  140. assert(op - 2 > out);
  141. op[-2] |= LZO_BYTE(t);
  142. } else {
  143. if (t <= 18) {
  144. *op++ = LZO_BYTE(t - 3);
  145. } else {
  146. register lzo_uint tt = t - 18;
  147. *op++ = 0;
  148. while (tt > 255) {
  149. tt -= 255;
  150. *op++ = 0;
  151. }
  152. assert(tt > 0);
  153. *op++ = LZO_BYTE(tt);
  154. }
  155. }
  156. do {
  157. *op++ = *ii++;
  158. } while (--t > 0);
  159. }
  160. /* code the match */
  161. code_match:
  162. assert(ii == ip);
  163. ip += 3;
  164. if (*m_pos++ != *ip++ || *m_pos++ != *ip++ || *m_pos++ != *ip++ ||
  165. *m_pos++ != *ip++ || *m_pos++ != *ip++ || *m_pos++ != *ip++)
  166. {
  167. --ip;
  168. m_len = ip - ii;
  169. assert(m_len >= 3); assert(m_len <= 8);
  170. if (m_off <= M2_MAX_OFFSET) {
  171. m_off -= 1;
  172. *op++ = LZO_BYTE(((m_len - 1) << 5) | ((m_off & 7) << 2));
  173. *op++ = LZO_BYTE(m_off >> 3);
  174. } else {
  175. if (m_off <= M3_MAX_OFFSET) {
  176. m_off -= 1;
  177. *op++ = LZO_BYTE(M3_MARKER | (m_len - 2));
  178. goto m3_m4_offset;
  179. } else {
  180. m_off -= 0x4000;
  181. assert(m_off > 0); assert(m_off <= 0x7fff);
  182. *op++ = LZO_BYTE(M4_MARKER |
  183. ((m_off & 0x4000) >> 11) | (m_len - 2));
  184. goto m3_m4_offset;
  185. }
  186. }
  187. } else {
  188. const lzo_byte *end;
  189. end = in_end;
  190. while (ip < end && *m_pos == *ip) {
  191. m_pos++;
  192. ip++;
  193. }
  194. m_len = (ip - ii);
  195. assert(m_len >= 3);
  196. if (m_off <= M3_MAX_OFFSET) {
  197. m_off -= 1;
  198. if (m_len <= 33) {
  199. *op++ = LZO_BYTE(M3_MARKER | (m_len - 2));
  200. } else {
  201. m_len -= 33;
  202. *op++ = M3_MARKER | 0;
  203. goto m3_m4_len;
  204. }
  205. } else {
  206. m_off -= 0x4000;
  207. assert(m_off > 0); assert(m_off <= 0x7fff);
  208. if (m_len <= 9) {
  209. *op++ = LZO_BYTE(M4_MARKER |
  210. ((m_off & 0x4000) >> 11) | (m_len - 2));
  211. } else {
  212. m_len -= 9;
  213. *op++ = LZO_BYTE(M4_MARKER | ((m_off & 0x4000) >> 11));
  214. m3_m4_len:
  215. while (m_len > 255) {
  216. m_len -= 255;
  217. *op++ = 0;
  218. }
  219. assert(m_len > 0);
  220. *op++ = LZO_BYTE(m_len);
  221. }
  222. }
  223. m3_m4_offset:
  224. *op++ = LZO_BYTE((m_off & 63) << 2);
  225. *op++ = LZO_BYTE(m_off >> 6);
  226. }
  227. ii = ip;
  228. if (ip >= ip_end) {
  229. break;
  230. }
  231. DVAL_FIRST(dv,ip);
  232. }
  233. /* store final literal run */
  234. if (in_end - ii > 0) {
  235. register lzo_uint t = in_end - ii;
  236. if (op == out && t <= 238) {
  237. *op++ = LZO_BYTE(17 + t);
  238. } else {
  239. if (t <= 3) {
  240. op[-2] |= LZO_BYTE(t);
  241. } else {
  242. if (t <= 18) {
  243. *op++ = LZO_BYTE(t - 3);
  244. } else {
  245. register lzo_uint tt = t - 18;
  246. *op++ = 0;
  247. while (tt > 255) {
  248. tt -= 255;
  249. *op++ = 0;
  250. }
  251. assert(tt > 0);
  252. *op++ = LZO_BYTE(tt);
  253. }
  254. }
  255. }
  256. do {
  257. *op++ = *ii++;
  258. } while (--t > 0);
  259. }
  260. *out_len = op - out;
  261. return LZO_E_OK;
  262. }
  263. /***********************************************************************
  264. // public entry point
  265. ************************************************************************/
  266. int lzo1x_1_compress ( const lzo_byte *in , lzo_uint in_len,
  267. lzo_byte *out, lzo_uint *out_len,
  268. lzo_voidp wrkmem )
  269. {
  270. lzo_byte *op = out;
  271. int r = LZO_E_OK;
  272. if (in_len <= 0)
  273. *out_len = 0;
  274. else if (in_len <= 9 + 4)
  275. {
  276. *op++ = LZO_BYTE(17 + in_len);
  277. do *op++ = *in++; while (--in_len > 0);
  278. *out_len = op - out;
  279. }
  280. else
  281. r = do_compress(in,in_len,out,out_len,wrkmem);
  282. if (r == LZO_E_OK)
  283. {
  284. op = out + *out_len;
  285. *op++ = M4_MARKER | 1;
  286. *op++ = 0;
  287. *op++ = 0;
  288. *out_len += 3;
  289. }
  290. return r;
  291. }
  292. /*
  293. vi:ts=4
  294. */