/libpsn00b/lzp/compress.c

https://github.com/Lameguy64/PSn00bSDK · C · 489 lines · 323 code · 158 blank · 8 comment · 102 complexity · 34a0b3be5e34a58e50ae954501bc1ff5 MD5 · raw file

  1. // Based on ilia muraviev's CRUSH compressor program which falls under public domain
  2. #include <string.h>
  3. #if LZP_USE_MALLOC == TRUE
  4. #include <stdlib.h>
  5. #include <malloc.h>
  6. #endif
  7. #include "lzconfig.h"
  8. #include "bit.h"
  9. #include "lzp.h"
  10. // Internal structure for hash table allocation sizes
  11. #if LZP_NO_COMPRESS == FALSE
  12. struct {
  13. short WindowSize; // Window size (17 - 23)
  14. short Hash1Size; // Hash 1 table size (10 - 21)
  15. short Hash2Size; // Hash 2 table size (12 - 24)
  16. } lzHashParam = {
  17. LZP_WINDOW_SIZE,
  18. LZP_HASH1_SIZE,
  19. LZP_HASH2_SIZE
  20. };
  21. #endif
  22. // Defines and macros for lz77 compression/decompression (don't touch)
  23. #define W_BITS lzHashParam.WindowSize
  24. #define HASH1_BITS lzHashParam.Hash1Size
  25. #define HASH2_BITS lzHashParam.Hash2Size
  26. #define W_SIZE (1<<W_BITS)
  27. #define W_MASK (W_SIZE-1)
  28. #define SLOT_BITS 4
  29. #define NUM_SLOTS (1<<SLOT_BITS)
  30. #define A_BITS 2 // 1 xx
  31. #define B_BITS 2 // 01 xx
  32. #define C_BITS 2 // 001 xx
  33. #define D_BITS 3 // 0001 xxx
  34. #define E_BITS 5 // 00001 xxxxx
  35. #define F_BITS 9 // 00000 xxxxxxxxx
  36. #define A (1<<A_BITS)
  37. #define B ((1<<B_BITS)+A)
  38. #define C ((1<<C_BITS)+B)
  39. #define D ((1<<D_BITS)+C)
  40. #define E ((1<<E_BITS)+D)
  41. #define F ((1<<F_BITS)+E)
  42. #define MIN_MATCH 3
  43. #define MAX_MATCH ((F-1)+MIN_MATCH)
  44. #define BUF_SIZE (1<<26)
  45. #define TOO_FAR (1<<16)
  46. #define HASH1_LEN MIN_MATCH
  47. #define HASH2_LEN (MIN_MATCH+1)
  48. #define HASH1_SIZE (1<<HASH1_BITS)
  49. #define HASH2_SIZE (1<<HASH2_BITS)
  50. #define HASH1_MASK (HASH1_SIZE-1)
  51. #define HASH2_MASK (HASH2_SIZE-1)
  52. #define HASH1_SHIFT ((HASH1_BITS+(HASH1_LEN-1))/HASH1_LEN)
  53. #define HASH2_SHIFT ((HASH2_BITS+(HASH2_LEN-1))/HASH2_LEN)
  54. // LZ77
  55. //
  56. #if LZP_NO_COMPRESS == FALSE
  57. int update_hash1(int h, int c) {
  58. return(((h<<HASH1_SHIFT)+c)&HASH1_MASK);
  59. }
  60. int update_hash2(int h, int c) {
  61. return(((h<<HASH2_SHIFT)+c)&HASH2_MASK);
  62. }
  63. int get_min(int a, int b) {
  64. return(a<b?a:b);
  65. }
  66. int get_max(int a, int b) {
  67. return(a>b?a:b);
  68. }
  69. int get_penalty(int a, int b) {
  70. int p=0;
  71. while(a > b) {
  72. a >>= 3;
  73. ++p;
  74. }
  75. return(p);
  76. }
  77. int lzCompress(void* outBuff, void* inBuff, int inSize, int level) {
  78. #if LZP_USE_MALLOC == FALSE
  79. int head[HASH1_SIZE+HASH2_SIZE];
  80. int prev[W_SIZE];
  81. #else
  82. int* head = malloc(4*(HASH1_SIZE+HASH2_SIZE));
  83. int* prev = malloc(4*W_SIZE);
  84. #endif
  85. int max_chain[] = {4, 256, 1<<12};
  86. int i,s;
  87. int h1=0;
  88. int h2=0;
  89. int p=0;
  90. int len;
  91. int offset;
  92. int max_match;
  93. int limit;
  94. int chain_len;
  95. int next_p;
  96. int max_lazy;
  97. int log;
  98. inPtr = (unsigned char*)inBuff;
  99. outPtr = (unsigned char*)outBuff;
  100. outBytes = 0;
  101. for (i=0; i<HASH1_SIZE+HASH2_SIZE; ++i)
  102. head[i] = -1;
  103. for (i=0; i<HASH1_LEN; ++i)
  104. h1=update_hash1(h1, inPtr[i]);
  105. for (i=0; i<HASH2_LEN; ++i)
  106. h2=update_hash2(h2, inPtr[i]);
  107. init_bits();
  108. // Put window size value so that the compressed data will be independent of the compression settings
  109. put_bits(5, lzHashParam.WindowSize);
  110. while(p < inSize) {
  111. len = MIN_MATCH-1;
  112. offset = W_SIZE;
  113. max_match = get_min(MAX_MATCH, inSize-p);
  114. limit = get_max(p-W_SIZE, 0);
  115. if (head[h1] >= limit) {
  116. s = head[h1];
  117. if (inPtr[s] == inPtr[p]) {
  118. i = 0;
  119. while(++i < max_match) {
  120. if (inPtr[s+i] != inPtr[p+i])
  121. break;
  122. }
  123. if (i > len) {
  124. len = i;
  125. offset = p-s;
  126. }
  127. }
  128. }
  129. if (len < MAX_MATCH) {
  130. chain_len = max_chain[level];
  131. s = head[h2+HASH1_SIZE];
  132. while((chain_len-- != 0) && (s >= limit)) {
  133. if ((inPtr[s+len] == inPtr[p+len]) && (inPtr[s] == inPtr[p])) {
  134. i = 0;
  135. while(++i < max_match) {
  136. if (inPtr[s+i] != inPtr[p+i])
  137. break;
  138. }
  139. if (i > len+get_penalty((p-s)>>4, offset)) {
  140. len = i;
  141. offset = p-s;
  142. }
  143. if (i == max_match)
  144. break;
  145. }
  146. s=prev[s&W_MASK];
  147. }
  148. }
  149. if ((len == MIN_MATCH) && (offset > TOO_FAR))
  150. len=0;
  151. if ((level >= 2) && (len >= MIN_MATCH) && (len < max_match)) {
  152. next_p = p+1;
  153. max_lazy = get_min(len+4, max_match);
  154. chain_len = max_chain[level];
  155. s = head[update_hash2(h2, inPtr[next_p+(HASH2_LEN-1)])+HASH1_SIZE];
  156. while((chain_len-- != 0) && (s >= limit)) {
  157. if ((inPtr[s+len] == inPtr[next_p+len]) && (inPtr[s] == inPtr[next_p])) {
  158. i = 0;
  159. while(++i < max_lazy) {
  160. if (inPtr[s+i] != inPtr[next_p+i])
  161. break;
  162. }
  163. if (i > len+get_penalty(next_p-s, offset)) {
  164. len = 0;
  165. break;
  166. }
  167. if (i == max_lazy)
  168. break;
  169. }
  170. s = prev[s&W_MASK];
  171. }
  172. }
  173. if (len >= MIN_MATCH) { // Match
  174. put_bits(1, 1);
  175. i = len-MIN_MATCH;
  176. if (i < A) {
  177. put_bits(1, 1); // 1
  178. put_bits(A_BITS, i);
  179. } else if (i < B) {
  180. put_bits(2, 1<<1); // 01
  181. put_bits(B_BITS, i-A);
  182. } else if (i < C) {
  183. put_bits(3, 1<<2); // 001
  184. put_bits(C_BITS, i-B);
  185. } else if (i < D) {
  186. put_bits(4, 1<<3); // 0001
  187. put_bits(D_BITS, i-C);
  188. } else if (i < E) {
  189. put_bits(5, 1<<4); // 00001
  190. put_bits(E_BITS, i-D);
  191. } else {
  192. put_bits(5, 0); // 00000
  193. put_bits(F_BITS, i-E);
  194. }
  195. --offset;
  196. log = W_BITS-NUM_SLOTS;
  197. while(offset >= (2<<log))
  198. ++log;
  199. put_bits(SLOT_BITS, log-(W_BITS-NUM_SLOTS));
  200. if (log>(W_BITS-NUM_SLOTS))
  201. put_bits(log, offset-(1<<log));
  202. else
  203. put_bits(W_BITS-(NUM_SLOTS-1), offset);
  204. } else { // Literal
  205. len = 1;
  206. put_bits(9, inPtr[p]<<1); // 0 xxxxxxxx
  207. }
  208. while(len-- != 0) { // Insert new strings
  209. head[h1] = p;
  210. prev[p&W_MASK] = head[h2+HASH1_SIZE];
  211. head[h2+HASH1_SIZE] = p;
  212. ++p;
  213. h1 = update_hash1(h1, inPtr[p+(HASH1_LEN-1)]);
  214. h2 = update_hash2(h2, inPtr[p+(HASH2_LEN-1)]);
  215. }
  216. }
  217. flush_bits();
  218. #if LZP_USE_MALLOC == TRUE
  219. free(head);
  220. free(prev);
  221. #endif
  222. return(outBytes);
  223. }
  224. void lzSetHashSizes(int window, int hash1, int hash2) {
  225. lzHashParam.WindowSize = window;
  226. lzHashParam.Hash1Size = hash1;
  227. lzHashParam.Hash2Size = hash2;
  228. }
  229. void lzResetHashSizes() {
  230. lzHashParam.WindowSize = LZP_WINDOW_SIZE;
  231. lzHashParam.Hash1Size = LZP_HASH1_SIZE;
  232. lzHashParam.Hash2Size = LZP_HASH2_SIZE;
  233. }
  234. #endif // LZP_NO_COMPRESS
  235. int lzDecompress(void* outBuff, void* inBuff, int inSize) {
  236. int p=0;
  237. int len;
  238. int log;
  239. int s;
  240. int windowSize;
  241. inPtr = (unsigned char*)inBuff;
  242. outPtr = (unsigned char*)outBuff;
  243. inBytes = 0;
  244. outBytes = 0;
  245. init_bits();
  246. // Get window size value
  247. windowSize = get_bits(5);
  248. while(inBytes < inSize) {
  249. if (get_bits(1)) {
  250. if (get_bits(1))
  251. len = get_bits(A_BITS);
  252. else if (get_bits(1))
  253. len = get_bits(B_BITS)+A;
  254. else if (get_bits(1))
  255. len = get_bits(C_BITS)+B;
  256. else if (get_bits(1))
  257. len = get_bits(D_BITS)+C;
  258. else if (get_bits(1))
  259. len = get_bits(E_BITS)+D;
  260. else
  261. len = get_bits(F_BITS)+E;
  262. log = get_bits(SLOT_BITS)+(windowSize-NUM_SLOTS);
  263. s =~ (log>(windowSize-NUM_SLOTS) ? get_bits(log)+(1<<log) : get_bits(windowSize-(NUM_SLOTS-1)))+p;
  264. if (s < 0)
  265. return(LZP_ERR_DECOMPRESS);
  266. outPtr[p++] = outPtr[s++];
  267. outPtr[p++] = outPtr[s++];
  268. outPtr[p++] = outPtr[s++];
  269. while(len-- != 0)
  270. outPtr[p++] = outPtr[s++];
  271. } else {
  272. outPtr[p++] = get_bits(8);
  273. }
  274. }
  275. return(p);
  276. }
  277. int lzDecompressLen(void* outBuff, int outSize, void* inBuff, int inSize) {
  278. int p=0;
  279. int len;
  280. int log;
  281. int s;
  282. int windowSize;
  283. inPtr = (unsigned char*)inBuff;
  284. outPtr = (unsigned char*)outBuff;
  285. inBytes = 0;
  286. outBytes = 0;
  287. init_bits();
  288. // Get window size value
  289. windowSize = get_bits(5);
  290. while(inBytes < inSize) {
  291. if (get_bits(1)) {
  292. if (get_bits(1))
  293. len = get_bits(A_BITS);
  294. else if (get_bits(1))
  295. len = get_bits(B_BITS)+A;
  296. else if (get_bits(1))
  297. len = get_bits(C_BITS)+B;
  298. else if (get_bits(1))
  299. len = get_bits(D_BITS)+C;
  300. else if (get_bits(1))
  301. len = get_bits(E_BITS)+D;
  302. else
  303. len = get_bits(F_BITS)+E;
  304. log = get_bits(SLOT_BITS)+(windowSize-NUM_SLOTS);
  305. s =~ (log>(windowSize-NUM_SLOTS) ? get_bits(log)+(1<<log) : get_bits(windowSize-(NUM_SLOTS-1)))+p;
  306. if (s < 0)
  307. return(LZP_ERR_DECOMPRESS);
  308. outPtr[p++] = outPtr[s++];
  309. if (p >= outSize)
  310. break;
  311. outPtr[p++] = outPtr[s++];
  312. if (p >= outSize)
  313. break;
  314. outPtr[p++] = outPtr[s++];
  315. if (p >= outSize)
  316. break;
  317. while(len-- != 0) {
  318. outPtr[p++] = outPtr[s++];
  319. if (p >= outSize)
  320. break;
  321. }
  322. if (p >= outSize)
  323. break;
  324. } else {
  325. outPtr[p++] = get_bits(8);
  326. }
  327. if (p >= outSize)
  328. break;
  329. }
  330. return(p);
  331. }