LZCompression.cs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. public static class LZCompression
  5. {
  6. public const int QLZ_VERSION_MAJOR = 1;
  7. public const int QLZ_VERSION_MINOR = 5;
  8. public const int QLZ_VERSION_REVISION = 0;
  9. // Streaming mode not supported
  10. public const int QLZ_STREAMING_BUFFER = 0;
  11. // Bounds checking not supported Use try...catch instead
  12. public const int QLZ_MEMORY_SAFE = 0;
  13. // Decrease QLZ_POINTERS_3 to increase level 3 compression speed. Do not edit any other values!
  14. private const int HASH_VALUES = 4096;
  15. private const int MINOFFSET = 2;
  16. private const int UNCONDITIONAL_MATCHLEN = 6;
  17. private const int UNCOMPRESSED_END = 4;
  18. private const int CWORD_LEN = 4;
  19. private const int DEFAULT_HEADERLEN = 9;
  20. private const int QLZ_POINTERS_1 = 1;
  21. private const int QLZ_POINTERS_3 = 16;
  22. private static int headerLen(byte[] source)
  23. {
  24. return ((source[0] & 2) == 2) ? 9 : 3;
  25. }
  26. public static int sizeDecompressed(byte[] source)
  27. {
  28. if (headerLen(source) == 9)
  29. return source[5] | (source[6] << 8) | (source[7] << 16) | (source[8] << 24);
  30. else
  31. return source[2];
  32. }
  33. public static int sizeCompressed(byte[] source)
  34. {
  35. if (headerLen(source) == 9)
  36. return source[1] | (source[2] << 8) | (source[3] << 16) | (source[4] << 24);
  37. else
  38. return source[1];
  39. }
  40. private static void write_header(byte[] dst, int level, bool compressible, int size_compressed, int size_decompressed)
  41. {
  42. dst[0] = (byte)(2 | (compressible ? 1 : 0));
  43. dst[0] |= (byte)(level << 2);
  44. dst[0] |= (1 << 6);
  45. dst[0] |= (0 << 4);
  46. fast_write(dst, 1, size_decompressed, 4);
  47. fast_write(dst, 5, size_compressed, 4);
  48. }
  49. public static byte[] compress(byte[] source, int level)
  50. {
  51. int src = 0;
  52. int dst = DEFAULT_HEADERLEN + CWORD_LEN;
  53. uint cword_val = 0x80000000;
  54. int cword_ptr = DEFAULT_HEADERLEN;
  55. byte[] destination = new byte[source.Length + 400];
  56. int[,] hashtable;
  57. int[] cachetable = new int[HASH_VALUES];
  58. byte[] hash_counter = new byte[HASH_VALUES];
  59. byte[] d2;
  60. int fetch = 0;
  61. int last_matchstart = (source.Length - UNCONDITIONAL_MATCHLEN - UNCOMPRESSED_END - 1);
  62. int lits = 0;
  63. if (level != 1 && level != 3)
  64. throw new ArgumentException("C# version only supports level 1 and 3");
  65. if (level == 1)
  66. hashtable = new int[HASH_VALUES, QLZ_POINTERS_1];
  67. else
  68. hashtable = new int[HASH_VALUES, QLZ_POINTERS_3];
  69. if (source.Length == 0)
  70. return new byte[0];
  71. if (src <= last_matchstart)
  72. fetch = source[src] | (source[src + 1] << 8) | (source[src + 2] << 16);
  73. while (src <= last_matchstart)
  74. {
  75. if ((cword_val & 1) == 1)
  76. {
  77. if (src > source.Length >> 1 && dst > src - (src >> 5))
  78. {
  79. d2 = new byte[source.Length + DEFAULT_HEADERLEN];
  80. write_header(d2, level, false, source.Length, source.Length + DEFAULT_HEADERLEN);
  81. System.Array.Copy(source, 0, d2, DEFAULT_HEADERLEN, source.Length);
  82. return d2;
  83. }
  84. fast_write(destination, cword_ptr, (int)((cword_val >> 1) | 0x80000000), 4);
  85. cword_ptr = dst;
  86. dst += CWORD_LEN;
  87. cword_val = 0x80000000;
  88. }
  89. if (level == 1)
  90. {
  91. int hash = ((fetch >> 12) ^ fetch) & (HASH_VALUES - 1);
  92. int o = hashtable[hash, 0];
  93. int cache = cachetable[hash] ^ fetch;
  94. cachetable[hash] = fetch;
  95. hashtable[hash, 0] = src;
  96. if (cache == 0 && hash_counter[hash] != 0 && (src - o > MINOFFSET || (src == o + 1 && lits >= 3 && src > 3 && source[src] == source[src - 3] && source[src] == source[src - 2] && source[src] == source[src - 1] && source[src] == source[src + 1] && source[src] == source[src + 2])))
  97. {
  98. cword_val = ((cword_val >> 1) | 0x80000000);
  99. if (source[o + 3] != source[src + 3])
  100. {
  101. int f = 3 - 2 | (hash << 4);
  102. destination[dst + 0] = (byte)(f >> 0 * 8);
  103. destination[dst + 1] = (byte)(f >> 1 * 8);
  104. src += 3;
  105. dst += 2;
  106. }
  107. else
  108. {
  109. int old_src = src;
  110. int remaining = ((source.Length - UNCOMPRESSED_END - src + 1 - 1) > 255 ? 255 : (source.Length - UNCOMPRESSED_END - src + 1 - 1));
  111. src += 4;
  112. if (source[o + src - old_src] == source[src])
  113. {
  114. src++;
  115. if (source[o + src - old_src] == source[src])
  116. {
  117. src++;
  118. while (source[o + (src - old_src)] == source[src] && (src - old_src) < remaining)
  119. src++;
  120. }
  121. }
  122. int matchlen = src - old_src;
  123. hash <<= 4;
  124. if (matchlen < 18)
  125. {
  126. int f = (hash | (matchlen - 2));
  127. destination[dst + 0] = (byte)(f >> 0 * 8);
  128. destination[dst + 1] = (byte)(f >> 1 * 8);
  129. dst += 2;
  130. }
  131. else
  132. {
  133. fast_write(destination, dst, hash | (matchlen << 16), 3);
  134. dst += 3;
  135. }
  136. }
  137. fetch = source[src] | (source[src + 1] << 8) | (source[src + 2] << 16);
  138. lits = 0;
  139. }
  140. else
  141. {
  142. lits++;
  143. hash_counter[hash] = 1;
  144. destination[dst] = source[src];
  145. cword_val = (cword_val >> 1);
  146. src++;
  147. dst++;
  148. fetch = ((fetch >> 8) & 0xffff) | (source[src + 2] << 16);
  149. }
  150. }
  151. else
  152. {
  153. fetch = source[src] | (source[src + 1] << 8) | (source[src + 2] << 16);
  154. int o, offset2;
  155. int matchlen, k, m;
  156. byte c;
  157. int remaining = ((source.Length - UNCOMPRESSED_END - src + 1 - 1) > 255 ? 255 : (source.Length - UNCOMPRESSED_END - src + 1 - 1));
  158. int hash = ((fetch >> 12) ^ fetch) & (HASH_VALUES - 1);
  159. c = hash_counter[hash];
  160. matchlen = 0;
  161. offset2 = 0;
  162. for (k = 0; k < QLZ_POINTERS_3 && c > k; k++)
  163. {
  164. o = hashtable[hash, k];
  165. if ((byte)fetch == source[o] && (byte)(fetch >> 8) == source[o + 1] && (byte)(fetch >> 16) == source[o + 2] && o < src - MINOFFSET)
  166. {
  167. m = 3;
  168. while (source[o + m] == source[src + m] && m < remaining)
  169. m++;
  170. if ((m > matchlen) || (m == matchlen && o > offset2))
  171. {
  172. offset2 = o;
  173. matchlen = m;
  174. }
  175. }
  176. }
  177. o = offset2;
  178. hashtable[hash, c & (QLZ_POINTERS_3 - 1)] = src;
  179. c++;
  180. hash_counter[hash] = c;
  181. if (matchlen >= 3 && src - o < 131071)
  182. {
  183. int offset = src - o;
  184. for (int u = 1; u < matchlen; u++)
  185. {
  186. fetch = source[src + u] | (source[src + u + 1] << 8) | (source[src + u + 2] << 16);
  187. hash = ((fetch >> 12) ^ fetch) & (HASH_VALUES - 1);
  188. c = hash_counter[hash]++;
  189. hashtable[hash, c & (QLZ_POINTERS_3 - 1)] = src + u;
  190. }
  191. src += matchlen;
  192. cword_val = ((cword_val >> 1) | 0x80000000);
  193. if (matchlen == 3 && offset <= 63)
  194. {
  195. fast_write(destination, dst, offset << 2, 1);
  196. dst++;
  197. }
  198. else if (matchlen == 3 && offset <= 16383)
  199. {
  200. fast_write(destination, dst, (offset << 2) | 1, 2);
  201. dst += 2;
  202. }
  203. else if (matchlen <= 18 && offset <= 1023)
  204. {
  205. fast_write(destination, dst, ((matchlen - 3) << 2) | (offset << 6) | 2, 2);
  206. dst += 2;
  207. }
  208. else if (matchlen <= 33)
  209. {
  210. fast_write(destination, dst, ((matchlen - 2) << 2) | (offset << 7) | 3, 3);
  211. dst += 3;
  212. }
  213. else
  214. {
  215. fast_write(destination, dst, ((matchlen - 3) << 7) | (offset << 15) | 3, 4);
  216. dst += 4;
  217. }
  218. lits = 0;
  219. }
  220. else
  221. {
  222. destination[dst] = source[src];
  223. cword_val = (cword_val >> 1);
  224. src++;
  225. dst++;
  226. }
  227. }
  228. }
  229. while (src <= source.Length - 1)
  230. {
  231. if ((cword_val & 1) == 1)
  232. {
  233. fast_write(destination, cword_ptr, (int)((cword_val >> 1) | 0x80000000), 4);
  234. cword_ptr = dst;
  235. dst += CWORD_LEN;
  236. cword_val = 0x80000000;
  237. }
  238. destination[dst] = source[src];
  239. src++;
  240. dst++;
  241. cword_val = (cword_val >> 1);
  242. }
  243. while ((cword_val & 1) != 1)
  244. {
  245. cword_val = (cword_val >> 1);
  246. }
  247. fast_write(destination, cword_ptr, (int)((cword_val >> 1) | 0x80000000), CWORD_LEN);
  248. write_header(destination, level, true, source.Length, dst);
  249. d2 = new byte[dst];
  250. System.Array.Copy(destination, d2, dst);
  251. return d2;
  252. }
  253. private static void fast_write(byte[] a, int i, int value, int numbytes)
  254. {
  255. for (int j = 0; j < numbytes; j++)
  256. a[i + j] = (byte)(value >> (j * 8));
  257. }
  258. public static byte[] decompress(byte[] source)
  259. {
  260. int level;
  261. int size = sizeDecompressed(source);
  262. int src = headerLen(source);
  263. int dst = 0;
  264. uint cword_val = 1;
  265. byte[] destination = new byte[size];
  266. int[] hashtable = new int[4096];
  267. byte[] hash_counter = new byte[4096];
  268. int last_matchstart = size - UNCONDITIONAL_MATCHLEN - UNCOMPRESSED_END - 1;
  269. int last_hashed = -1;
  270. int hash;
  271. uint fetch = 0;
  272. level = (source[0] >> 2) & 0x3;
  273. if (level != 1 && level != 3)
  274. throw new ArgumentException("C# version only supports level 1 and 3");
  275. if ((source[0] & 1) != 1)
  276. {
  277. byte[] d2 = new byte[size];
  278. System.Array.Copy(source, headerLen(source), d2, 0, size);
  279. return d2;
  280. }
  281. for (; ; )
  282. {
  283. if (cword_val == 1)
  284. {
  285. cword_val = (uint)(source[src] | (source[src + 1] << 8) | (source[src + 2] << 16) | (source[src + 3] << 24));
  286. src += 4;
  287. if (dst <= last_matchstart)
  288. {
  289. if (level == 1)
  290. fetch = (uint)(source[src] | (source[src + 1] << 8) | (source[src + 2] << 16));
  291. else
  292. fetch = (uint)(source[src] | (source[src + 1] << 8) | (source[src + 2] << 16) | (source[src + 3] << 24));
  293. }
  294. }
  295. if ((cword_val & 1) == 1)
  296. {
  297. uint matchlen;
  298. uint offset2;
  299. cword_val = cword_val >> 1;
  300. if (level == 1)
  301. {
  302. hash = ((int)fetch >> 4) & 0xfff;
  303. offset2 = (uint)hashtable[hash];
  304. if ((fetch & 0xf) != 0)
  305. {
  306. matchlen = (fetch & 0xf) + 2;
  307. src += 2;
  308. }
  309. else
  310. {
  311. matchlen = source[src + 2];
  312. src += 3;
  313. }
  314. }
  315. else
  316. {
  317. uint offset;
  318. if ((fetch & 3) == 0)
  319. {
  320. offset = (fetch & 0xff) >> 2;
  321. matchlen = 3;
  322. src++;
  323. }
  324. else if ((fetch & 2) == 0)
  325. {
  326. offset = (fetch & 0xffff) >> 2;
  327. matchlen = 3;
  328. src += 2;
  329. }
  330. else if ((fetch & 1) == 0)
  331. {
  332. offset = (fetch & 0xffff) >> 6;
  333. matchlen = ((fetch >> 2) & 15) + 3;
  334. src += 2;
  335. }
  336. else if ((fetch & 127) != 3)
  337. {
  338. offset = (fetch >> 7) & 0x1ffff;
  339. matchlen = ((fetch >> 2) & 0x1f) + 2;
  340. src += 3;
  341. }
  342. else
  343. {
  344. offset = (fetch >> 15);
  345. matchlen = ((fetch >> 7) & 255) + 3;
  346. src += 4;
  347. }
  348. offset2 = (uint)(dst - offset);
  349. }
  350. destination[dst + 0] = destination[offset2 + 0];
  351. destination[dst + 1] = destination[offset2 + 1];
  352. destination[dst + 2] = destination[offset2 + 2];
  353. for (int i = 3; i < matchlen; i += 1)
  354. {
  355. destination[dst + i] = destination[offset2 + i];
  356. }
  357. dst += (int)matchlen;
  358. if (level == 1)
  359. {
  360. fetch = (uint)(destination[last_hashed + 1] | (destination[last_hashed + 2] << 8) | (destination[last_hashed + 3] << 16));
  361. while (last_hashed < dst - matchlen)
  362. {
  363. last_hashed++;
  364. hash = (int)(((fetch >> 12) ^ fetch) & (HASH_VALUES - 1));
  365. hashtable[hash] = last_hashed;
  366. hash_counter[hash] = 1;
  367. fetch = (uint)(fetch >> 8 & 0xffff | (uint)(destination[last_hashed + 3] << 16));
  368. }
  369. fetch = (uint)(source[src] | (source[src + 1] << 8) | (source[src + 2] << 16));
  370. }
  371. else
  372. {
  373. fetch = (uint)(source[src] | (source[src + 1] << 8) | (source[src + 2] << 16) | (source[src + 3] << 24));
  374. }
  375. last_hashed = dst - 1;
  376. }
  377. else
  378. {
  379. if (dst <= last_matchstart)
  380. {
  381. destination[dst] = source[src];
  382. dst += 1;
  383. src += 1;
  384. cword_val = cword_val >> 1;
  385. if (level == 1)
  386. {
  387. while (last_hashed < dst - 3)
  388. {
  389. last_hashed++;
  390. int fetch2 = destination[last_hashed] | (destination[last_hashed + 1] << 8) | (destination[last_hashed + 2] << 16);
  391. hash = ((fetch2 >> 12) ^ fetch2) & (HASH_VALUES - 1);
  392. hashtable[hash] = last_hashed;
  393. hash_counter[hash] = 1;
  394. }
  395. fetch = (uint)(fetch >> 8 & 0xffff | (uint)(source[src + 2] << 16));
  396. }
  397. else
  398. {
  399. fetch = (uint)(fetch >> 8 & 0xffff | (uint)(source[src + 2] << 16) | (uint)(source[src + 3] << 24));
  400. }
  401. }
  402. else
  403. {
  404. while (dst <= size - 1)
  405. {
  406. if (cword_val == 1)
  407. {
  408. src += CWORD_LEN;
  409. cword_val = 0x80000000;
  410. }
  411. destination[dst] = source[src];
  412. dst++;
  413. src++;
  414. cword_val = cword_val >> 1;
  415. }
  416. return destination;
  417. }
  418. }
  419. }
  420. }
  421. }