workers.ts 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. import pako from 'pako';
  2. import * as UZIP from 'uzip';
  3. import JSZip from 'jszip';
  4. const wk = self as unknown as {
  5. postMessage(b: unknown, bufs: ArrayBuffer[]): void;
  6. };
  7. const dcmp = ['inflate', 'gunzip', 'unzlib'];
  8. const concat = (chunks: Uint8Array[]) => {
  9. const out = new Uint8Array(
  10. chunks.reduce((a, v) => v.length + a, 0)
  11. );
  12. let loc = 0;
  13. for (const chunk of chunks) {
  14. out.set(chunk, loc);
  15. loc += chunk.length;
  16. }
  17. return out;
  18. }
  19. // CRC32 table
  20. const crct = new Uint32Array(256);
  21. for (let i = 0; i < 256; ++i) {
  22. let c = i, k = 9;
  23. while (--k) c = ((c & 1) && 0xEDB88320) ^ (c >>> 1);
  24. crct[i] = c;
  25. }
  26. // CRC32
  27. const crc = (d: Uint8Array) => {
  28. let c = 0xFFFFFFFF;
  29. for (let i = 0; i < d.length; ++i) c = crct[(c & 255) ^ d[i]] ^ (c >>> 8);
  30. return c ^ 0xFFFFFFFF;
  31. }
  32. const uzGzip = (d: Uint8Array) => {
  33. const raw = UZIP.deflateRaw(d);
  34. const head = new Uint8Array([31, 139, 8, 0, 0, 0, 0, 0, 0, 0]);
  35. const c = crc(d);
  36. const l = raw.length;
  37. const tail = new Uint8Array([
  38. c & 255, (c >>> 8) & 255, (c >>> 16) & 255, (c >>> 32) & 255,
  39. l & 255, (l >>> 8) & 255, (l >>> 16) & 255, (l >>> 32) & 255,
  40. ]);
  41. return concat([head, raw, tail]);
  42. }
  43. onmessage = (ev: MessageEvent<[string, string]>) => {
  44. const [lib, type] = ev.data;
  45. if (lib == 'pako') {
  46. if (type == 'zip') {
  47. const zip = new JSZip();
  48. onmessage = (ev: MessageEvent<null | [string, Uint8Array]>) => {
  49. if (ev.data) {
  50. zip.file(ev.data[0], ev.data[1]);
  51. } else zip.generateAsync({
  52. type: 'uint8array',
  53. compressionOptions: { level: 6 }
  54. }).then(buf => {
  55. wk.postMessage([buf, true], [buf.buffer]);
  56. })
  57. };
  58. } else if (type == 'unzip') {
  59. onmessage = (ev: MessageEvent<Uint8Array>) => {
  60. JSZip.loadAsync(ev.data).then(zip => {
  61. const out: Record<string, Uint8Array> = {};
  62. const bufs: Promise<ArrayBuffer>[] = [];
  63. for (const k in zip.files) {
  64. const file = zip.files[k];
  65. bufs.push(file.async('uint8array').then(v => {
  66. out[file.name] = v;
  67. return v.buffer;
  68. }));
  69. }
  70. Promise.all(bufs).then(res => {
  71. wk.postMessage([out, true], res);
  72. });
  73. })
  74. }
  75. } else {
  76. const strm = dcmp.indexOf(type) == -1
  77. ? new pako.Deflate(type == 'gzip' ? {
  78. gzip: true
  79. } : {
  80. raw: type == 'inflate'
  81. }
  82. ) : new pako.Inflate({
  83. raw: type == 'deflate'
  84. });
  85. let chk: Uint8Array;
  86. strm.onData = (chunk: Uint8Array) => {
  87. if (chk) wk.postMessage([chk, false], [chk.buffer]);
  88. chk = chunk;
  89. };
  90. onmessage = (ev: MessageEvent<[Uint8Array, boolean]>) => {
  91. strm.push(ev.data[0], ev.data[1]);
  92. if (ev.data[1]) wk.postMessage([chk, true], [chk.buffer]);
  93. };
  94. }
  95. } else if (lib == 'uzip') {
  96. if (type == 'zip') {
  97. const zip: Record<string, Uint8Array> = {};
  98. onmessage = (ev: MessageEvent<null | [string, Uint8Array]>) => {
  99. if (ev.data) {
  100. zip[ev.data[0]] = ev.data[1];
  101. } else {
  102. const buf = UZIP.encode(zip);
  103. wk.postMessage([new Uint8Array(buf), true], [buf]);
  104. }
  105. };
  106. } else if (type == 'unzip') {
  107. onmessage = (ev: MessageEvent<Uint8Array>) => {
  108. const bufs = UZIP.parse(ev.data.buffer);
  109. const outBufs: ArrayBuffer[] = [];
  110. for (const k in bufs) {
  111. outBufs.push(bufs[k]);
  112. bufs[k] = new Uint8Array(bufs[k]);
  113. }
  114. wk.postMessage([bufs, true], outBufs);
  115. }
  116. } else {
  117. const chunks: Uint8Array[] = [];
  118. onmessage = (ev: MessageEvent<[Uint8Array, boolean]>) => {
  119. chunks.push(ev.data[0]);
  120. if (ev.data[1]) {
  121. const out = concat(chunks);
  122. const buf = type == 'inflate'
  123. ? UZIP.inflateRaw(out)
  124. : type == 'deflate'
  125. ? UZIP.deflateRaw(out)
  126. : type == 'zlib'
  127. ? UZIP.deflate(out)
  128. : type == 'unzlib'
  129. ? UZIP.inflate(out)
  130. : type == 'gzip'
  131. ? uzGzip(out)
  132. // we can pray that there's no special header
  133. : UZIP.inflateRaw(out.subarray(10, -8));
  134. wk.postMessage([buf, true], [buf.buffer]);
  135. }
  136. }
  137. }
  138. }
  139. }