LZO1X_C.CPP 8.1 KB

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