inflate.ts 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. /**
  2. * Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author Alexander Rose <alexander.rose@weirdbyte.de>
  5. *
  6. * ported from https://github.com/photopea/UZIP.js/blob/master/UZIP.js
  7. * MIT License, Copyright (c) 2018 Photopea
  8. */
  9. import { NumberArray } from '../type-helpers';
  10. import { U, makeCodes, codes2map } from './util';
  11. import { RuntimeContext } from '../../mol-task';
  12. function InflateContext(data: Uint8Array, buf?: Uint8Array) {
  13. const noBuf = buf === undefined;
  14. if(buf === undefined) buf = new Uint8Array((data.length >>> 2) << 3);
  15. return {
  16. data,
  17. buf,
  18. noBuf,
  19. BFINAL: 0,
  20. off: 0,
  21. pos: 0
  22. };
  23. }
  24. type InflateContext = ReturnType<typeof InflateContext>
  25. function inflateBlocks(ctx: InflateContext, count: number) {
  26. const { data, noBuf } = ctx;
  27. let { buf, BFINAL, off, pos } = ctx;
  28. let iBlock = 0;
  29. while(BFINAL === 0 && iBlock < count) {
  30. let lmap, dmap;
  31. let ML = 0, MD = 0;
  32. BFINAL = _bitsF(data, pos, 1);
  33. iBlock += 1;
  34. const BTYPE = _bitsF(data, pos + 1, 2);
  35. pos += 3;
  36. if(BTYPE === 0) {
  37. // uncompressed block
  38. if((pos & 7) !== 0) pos += 8 - (pos & 7);
  39. const p8 = (pos >>> 3) + 4;
  40. const len = data[p8 - 4] | (data[p8 - 3] << 8);
  41. if(noBuf) buf = _check(buf, off + len);
  42. buf.set(new Uint8Array(data.buffer, data.byteOffset + p8, len), off);
  43. pos = ((p8 + len) << 3);
  44. off += len;
  45. continue;
  46. }
  47. // grow output buffer if not provided
  48. if(noBuf) buf = _check(buf, off + (1 << 17));
  49. if(BTYPE === 1) {
  50. // block compressed with fixed Huffman codes
  51. lmap = U.flmap;
  52. dmap = U.fdmap;
  53. ML = (1 << 9) - 1;
  54. MD = (1 << 5) - 1;
  55. } else if(BTYPE === 2) {
  56. // block compressed with dynamic Huffman codes
  57. const HLIT = _bitsE(data, pos, 5) + 257;
  58. const HDIST = _bitsE(data, pos + 5, 5) + 1;
  59. const HCLEN = _bitsE(data, pos + 10, 4) + 4;
  60. pos += 14;
  61. for(let i = 0; i < 38; i += 2) {
  62. U.itree[i] = 0;
  63. U.itree[i + 1] = 0;
  64. }
  65. let tl = 1;
  66. for(let i = 0; i < HCLEN; i++) {
  67. const l = _bitsE(data, pos + i * 3, 3);
  68. U.itree[(U.ordr[i] << 1) + 1] = l;
  69. if(l > tl) tl = l;
  70. }
  71. pos += 3 * HCLEN;
  72. makeCodes(U.itree, tl);
  73. codes2map(U.itree, tl, U.imap);
  74. lmap = U.lmap; dmap = U.dmap;
  75. pos = _decodeTiny(U.imap, (1 << tl) - 1, HLIT + HDIST, data, pos, U.ttree);
  76. const mx0 = _copyOut(U.ttree, 0, HLIT, U.ltree);
  77. ML = (1 << mx0) - 1;
  78. const mx1 = _copyOut(U.ttree, HLIT, HDIST, U.dtree);
  79. MD = (1 << mx1) - 1;
  80. makeCodes(U.ltree, mx0);
  81. codes2map(U.ltree, mx0, lmap);
  82. makeCodes(U.dtree, mx1);
  83. codes2map(U.dtree, mx1, dmap);
  84. } else {
  85. throw new Error(`unknown BTYPE ${BTYPE}`);
  86. }
  87. while(true) {
  88. const code = lmap[_get17(data, pos) & ML];
  89. pos += code & 15;
  90. const lit = code >>> 4;
  91. if((lit >>> 8) === 0) {
  92. buf[off++] = lit;
  93. } else if(lit === 256) {
  94. break;
  95. } else {
  96. let end = off + lit - 254;
  97. if(lit > 264) {
  98. const ebs = U.ldef[lit - 257];
  99. end = off + (ebs >>> 3) + _bitsE(data, pos, ebs & 7);
  100. pos += ebs & 7;
  101. }
  102. const dcode = dmap[_get17(data, pos) & MD];
  103. pos += dcode & 15;
  104. const dlit = dcode >>> 4;
  105. const dbs = U.ddef[dlit];
  106. const dst = (dbs >>> 4) + _bitsF(data, pos, dbs & 15);
  107. pos += dbs & 15;
  108. if(noBuf) buf = _check(buf, off + (1 << 17));
  109. while(off < end) {
  110. buf[off] = buf[off++ - dst];
  111. buf[off] = buf[off++ - dst];
  112. buf[off] = buf[off++ - dst];
  113. buf[off] = buf[off++ - dst];
  114. }
  115. off = end;
  116. }
  117. }
  118. }
  119. ctx.buf = buf;
  120. ctx.BFINAL = BFINAL;
  121. ctx.off = off;
  122. ctx.pos = pos;
  123. }
  124. // https://tools.ietf.org/html/rfc1951
  125. export async function _inflate(runtime: RuntimeContext, data: Uint8Array, buf?: Uint8Array) {
  126. if(data[0] === 3 && data[1] === 0) return (buf ? buf : new Uint8Array(0));
  127. const ctx = InflateContext(data, buf);
  128. while(ctx.BFINAL === 0) {
  129. if (runtime.shouldUpdate) {
  130. await runtime.update({ message: 'Inflating blocks...', current: ctx.pos, max: data.length });
  131. }
  132. inflateBlocks(ctx, 100);
  133. }
  134. return ctx.buf.length === ctx.off ? ctx.buf : ctx.buf.slice(0, ctx.off);
  135. }
  136. function _check(buf: Uint8Array, len: number) {
  137. const bl = buf.length;
  138. if(len <= bl) return buf;
  139. const nbuf = new Uint8Array(Math.max(bl << 1, len));
  140. nbuf.set(buf, 0);
  141. return nbuf;
  142. }
  143. function _decodeTiny(lmap: NumberArray, LL: number, len: number, data: Uint8Array, pos: number, tree: number[]) {
  144. let i = 0;
  145. while(i < len) {
  146. const code = lmap[_get17(data, pos) & LL];
  147. pos += code & 15;
  148. const lit = code >>> 4;
  149. if(lit <= 15) {
  150. tree[i] = lit;
  151. i++;
  152. } else {
  153. let ll = 0, n = 0;
  154. if(lit === 16) {
  155. n = (3 + _bitsE(data, pos, 2));
  156. pos += 2;
  157. ll = tree[i - 1];
  158. } else if(lit === 17) {
  159. n = (3 + _bitsE(data, pos, 3));
  160. pos += 3;
  161. } else if(lit === 18) {
  162. n = (11 + _bitsE(data, pos, 7));
  163. pos += 7;
  164. }
  165. const ni = i + n;
  166. while(i < ni) {
  167. tree[i] = ll;
  168. i++;
  169. }
  170. }
  171. }
  172. return pos;
  173. }
  174. function _copyOut(src: number[], off: number, len: number, tree: number[]) {
  175. let mx = 0, i = 0;
  176. const tl = tree.length >>> 1;
  177. while(i < len) {
  178. let v = src[i + off];
  179. tree[(i << 1)] = 0;
  180. tree[(i << 1) + 1] = v;
  181. if(v > mx)mx = v;
  182. i++;
  183. }
  184. while(i < tl) {
  185. tree[(i << 1)] = 0;
  186. tree[(i << 1) + 1] = 0;
  187. i++;
  188. }
  189. return mx;
  190. }
  191. function _bitsE(dt: NumberArray, pos: number, length: number) {
  192. return ((dt[pos >>> 3] | (dt[(pos >>> 3) + 1] << 8)) >>> (pos & 7)) & ((1 << length) - 1);
  193. }
  194. function _bitsF(dt: NumberArray, pos: number, length: number) {
  195. return ((dt[pos >>> 3] | (dt[(pos >>> 3) + 1] << 8) | (dt[(pos >>> 3) + 2] << 16)) >>> (pos & 7)) & ((1 << length) - 1);
  196. }
  197. function _get17(dt: NumberArray, pos: number) { // return at least 17 meaningful bytes
  198. return (dt[pos >>> 3] | (dt[(pos >>> 3) + 1] << 8) | (dt[(pos >>> 3) + 2] << 16) ) >>> (pos & 7);
  199. }