PageRenderTime 52ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/nall/decode/inflate.hpp

https://gitlab.com/TeoTwawki/higan
C++ Header | 346 lines | 287 code | 59 blank | 0 comment | 86 complexity | 872f81eacb03e9a49e991a0dd393788d MD5 | raw file
  1. #pragma once
  2. #include <setjmp.h>
  3. namespace nall { namespace Decode {
  4. namespace puff {
  5. inline auto puff(
  6. unsigned char* dest, unsigned long* destlen,
  7. unsigned char* source, unsigned long* sourcelen
  8. ) -> int;
  9. }
  10. inline auto inflate(
  11. uint8_t* target, uint targetLength,
  12. const uint8_t* source, uint sourceLength
  13. ) -> bool {
  14. unsigned long tl = targetLength, sl = sourceLength;
  15. int result = puff::puff((unsigned char*)target, &tl, (unsigned char*)source, &sl);
  16. return result == 0;
  17. }
  18. namespace puff {
  19. enum : uint {
  20. MAXBITS = 15,
  21. MAXLCODES = 286,
  22. MAXDCODES = 30,
  23. FIXLCODES = 288,
  24. MAXCODES = MAXLCODES + MAXDCODES,
  25. };
  26. struct state {
  27. unsigned char* out;
  28. unsigned long outlen;
  29. unsigned long outcnt;
  30. unsigned char* in;
  31. unsigned long inlen;
  32. unsigned long incnt;
  33. int bitbuf;
  34. int bitcnt;
  35. jmp_buf env;
  36. };
  37. struct huffman {
  38. short* count;
  39. short* symbol;
  40. };
  41. inline auto bits(state* s, int need) -> int {
  42. long val;
  43. val = s->bitbuf;
  44. while(s->bitcnt < need) {
  45. if(s->incnt == s->inlen) longjmp(s->env, 1);
  46. val |= (long)(s->in[s->incnt++]) << s->bitcnt;
  47. s->bitcnt += 8;
  48. }
  49. s->bitbuf = (int)(val >> need);
  50. s->bitcnt -= need;
  51. return (int)(val & ((1L << need) - 1));
  52. }
  53. inline auto stored(state* s) -> int {
  54. uint len;
  55. s->bitbuf = 0;
  56. s->bitcnt = 0;
  57. if(s->incnt + 4 > s->inlen) return 2;
  58. len = s->in[s->incnt++];
  59. len |= s->in[s->incnt++] << 8;
  60. if(s->in[s->incnt++] != (~len & 0xff) ||
  61. s->in[s->incnt++] != ((~len >> 8) & 0xff)
  62. ) return 2;
  63. if(s->incnt + len > s->inlen) return 2;
  64. if(s->out != nullptr) {
  65. if(s->outcnt + len > s->outlen) return 1;
  66. while(len--) s->out[s->outcnt++] = s->in[s->incnt++];
  67. } else {
  68. s->outcnt += len;
  69. s->incnt += len;
  70. }
  71. return 0;
  72. }
  73. inline auto decode(state* s, huffman* h) -> int {
  74. int len, code, first, count, index, bitbuf, left;
  75. short* next;
  76. bitbuf = s->bitbuf;
  77. left = s->bitcnt;
  78. code = first = index = 0;
  79. len = 1;
  80. next = h->count + 1;
  81. while(true) {
  82. while(left--) {
  83. code |= bitbuf & 1;
  84. bitbuf >>= 1;
  85. count = *next++;
  86. if(code - count < first) {
  87. s->bitbuf = bitbuf;
  88. s->bitcnt = (s->bitcnt - len) & 7;
  89. return h->symbol[index + (code - first)];
  90. }
  91. index += count;
  92. first += count;
  93. first <<= 1;
  94. code <<= 1;
  95. len++;
  96. }
  97. left = (MAXBITS + 1) - len;
  98. if(left == 0) break;
  99. if(s->incnt == s->inlen) longjmp(s->env, 1);
  100. bitbuf = s->in[s->incnt++];
  101. if(left > 8) left = 8;
  102. }
  103. return -10;
  104. }
  105. inline auto construct(huffman* h, short* length, int n) -> int {
  106. int symbol, len, left;
  107. short offs[MAXBITS + 1];
  108. for(len = 0; len <= MAXBITS; len++) h->count[len] = 0;
  109. for(symbol = 0; symbol < n; symbol++) h->count[length[symbol]]++;
  110. if(h->count[0] == n) return 0;
  111. left = 1;
  112. for(len = 1; len <= MAXBITS; len++) {
  113. left <<= 1;
  114. left -= h->count[len];
  115. if(left < 0) return left;
  116. }
  117. offs[1] = 0;
  118. for(len = 1; len < MAXBITS; len++) offs[len + 1] = offs[len] + h->count[len];
  119. for(symbol = 0; symbol < n; symbol++) {
  120. if(length[symbol] != 0) h->symbol[offs[length[symbol]]++] = symbol;
  121. }
  122. return left;
  123. }
  124. inline auto codes(state* s, huffman* lencode, huffman* distcode) -> int {
  125. int symbol, len;
  126. uint dist;
  127. static const short lens[29] = {
  128. 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
  129. 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258
  130. };
  131. static const short lext[29] = {
  132. 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
  133. 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0
  134. };
  135. static const short dists[30] = {
  136. 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
  137. 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
  138. 8193, 12289, 16385, 24577
  139. };
  140. static const short dext[30] = {
  141. 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
  142. 7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
  143. 12, 12, 13, 13
  144. };
  145. do {
  146. symbol = decode(s, lencode);
  147. if(symbol < 0) return symbol;
  148. if(symbol < 256) {
  149. if(s->out != nullptr) {
  150. if(s->outcnt == s->outlen) return 1;
  151. s->out[s->outcnt] = symbol;
  152. }
  153. s->outcnt++;
  154. } else if(symbol > 256) {
  155. symbol -= 257;
  156. if(symbol >= 29) return -10;
  157. len = lens[symbol] + bits(s, lext[symbol]);
  158. symbol = decode(s, distcode);
  159. if(symbol < 0) return symbol;
  160. dist = dists[symbol] + bits(s, dext[symbol]);
  161. #ifndef INFLATE_ALLOW_INVALID_DISTANCE_TOO_FAR
  162. if(dist > s->outcnt) return -11;
  163. #endif
  164. if(s->out != nullptr) {
  165. if(s->outcnt + len > s->outlen) return 1;
  166. while(len--) {
  167. s->out[s->outcnt] =
  168. #ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOO_FAR
  169. dist > s->outcnt ? 0 :
  170. #endif
  171. s->out[s->outcnt - dist];
  172. s->outcnt++;
  173. }
  174. } else {
  175. s->outcnt += len;
  176. }
  177. }
  178. } while(symbol != 256);
  179. return 0;
  180. }
  181. inline auto fixed(state* s) -> int {
  182. static int virgin = 1;
  183. static short lencnt[MAXBITS + 1], lensym[FIXLCODES];
  184. static short distcnt[MAXBITS + 1], distsym[MAXDCODES];
  185. static huffman lencode, distcode;
  186. if(virgin) {
  187. int symbol = 0;
  188. short lengths[FIXLCODES];
  189. lencode.count = lencnt;
  190. lencode.symbol = lensym;
  191. distcode.count = distcnt;
  192. distcode.symbol = distsym;
  193. for(; symbol < 144; symbol++) lengths[symbol] = 8;
  194. for(; symbol < 256; symbol++) lengths[symbol] = 9;
  195. for(; symbol < 280; symbol++) lengths[symbol] = 7;
  196. for(; symbol < FIXLCODES; symbol++) lengths[symbol] = 8;
  197. construct(&lencode, lengths, FIXLCODES);
  198. for(symbol = 0; symbol < MAXDCODES; symbol++) lengths[symbol] = 5;
  199. construct(&distcode, lengths, MAXDCODES);
  200. virgin = 0;
  201. }
  202. return codes(s, &lencode, &distcode);
  203. }
  204. inline auto dynamic(state* s) -> int {
  205. int nlen, ndist, ncode, index, err;
  206. short lengths[MAXCODES];
  207. short lencnt[MAXBITS + 1], lensym[MAXLCODES];
  208. short distcnt[MAXBITS + 1], distsym[MAXDCODES];
  209. huffman lencode, distcode;
  210. static const short order[19] = {
  211. 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15
  212. };
  213. lencode.count = lencnt;
  214. lencode.symbol = lensym;
  215. distcode.count = distcnt;
  216. distcode.symbol = distsym;
  217. nlen = bits(s, 5) + 257;
  218. ndist = bits(s, 5) + 1;
  219. ncode = bits(s, 4) + 4;
  220. if(nlen > MAXLCODES || ndist > MAXDCODES) return -3;
  221. for(index = 0; index < ncode; index++) lengths[order[index]] = bits(s, 3);
  222. for(; index < 19; index++) lengths[order[index]] = 0;
  223. err = construct(&lencode, lengths, 19);
  224. if(err != 0) return -4;
  225. index = 0;
  226. while(index < nlen + ndist) {
  227. int symbol, len;
  228. symbol = decode(s, &lencode);
  229. if(symbol < 16) {
  230. lengths[index++] = symbol;
  231. } else {
  232. len = 0;
  233. if(symbol == 16) {
  234. if(index == 0) return -5;
  235. len = lengths[index - 1];
  236. symbol = 3 + bits(s, 2);
  237. } else if(symbol == 17) {
  238. symbol = 3 + bits(s, 3);
  239. } else {
  240. symbol = 11 + bits(s, 7);
  241. }
  242. if(index + symbol > nlen + ndist) return -6;
  243. while(symbol--) lengths[index++] = len;
  244. }
  245. }
  246. if(lengths[256] == 0) return -9;
  247. err = construct(&lencode, lengths, nlen);
  248. if(err < 0 || (err > 0 && nlen - lencode.count[0] != 1)) return -7;
  249. err = construct(&distcode, lengths + nlen, ndist);
  250. if(err < 0 || (err > 0 && ndist - distcode.count[0] != 1)) return -8;
  251. return codes(s, &lencode, &distcode);
  252. }
  253. inline auto puff(
  254. unsigned char* dest, unsigned long* destlen,
  255. unsigned char* source, unsigned long* sourcelen
  256. ) -> int {
  257. state s;
  258. int last, type, err;
  259. s.out = dest;
  260. s.outlen = *destlen;
  261. s.outcnt = 0;
  262. s.in = source;
  263. s.inlen = *sourcelen;
  264. s.incnt = 0;
  265. s.bitbuf = 0;
  266. s.bitcnt = 0;
  267. if(setjmp(s.env) != 0) {
  268. err = 2;
  269. } else {
  270. do {
  271. last = bits(&s, 1);
  272. type = bits(&s, 2);
  273. err = type == 0 ? stored(&s)
  274. : type == 1 ? fixed(&s)
  275. : type == 2 ? dynamic(&s)
  276. : -1;
  277. if(err != 0) break;
  278. } while(!last);
  279. }
  280. if(err <= 0) {
  281. *destlen = s.outcnt;
  282. *sourcelen = s.incnt;
  283. }
  284. return err;
  285. }
  286. }
  287. }}