Affected files: .obsidian/plugins/obsidian-excalidraw-plugin/data.json .obsidian/plugins/obsidian-reminder-plugin/main.js .obsidian/plugins/obsidian-reminder-plugin/manifest.json .obsidian/plugins/obsidian-reminder-plugin/styles.css .obsidian/plugins/obsidian-spaced-repetition/main.js .obsidian/plugins/obsidian-spaced-repetition/manifest.json .obsidian/plugins/obsidian-spaced-repetition/styles.css .obsidian/plugins/obsidian-tasks-plugin/main.js .obsidian/plugins/obsidian-tasks-plugin/manifest.json .obsidian/plugins/obsidian-tasks-plugin/styles.css .obsidian/plugins/obsidian-tracker/main.js .obsidian/plugins/obsidian-tracker/manifest.json .obsidian/plugins/omnisearch/data.json .obsidian/plugins/omnisearch/main.js .obsidian/plugins/omnisearch/manifest.json .obsidian/plugins/omnisearch/styles.css .obsidian/plugins/readwise-official/main.js .obsidian/plugins/readwise-official/manifest.json .obsidian/plugins/smart-connections/main.js .obsidian/plugins/smart-connections/manifest.json .obsidian/plugins/smart-connections/styles.css .obsidian/plugins/tag-wrangler/main.js .obsidian/plugins/tag-wrangler/manifest.json .obsidian/plugins/templater-obsidian/main.js .obsidian/plugins/templater-obsidian/manifest.json .obsidian/plugins/templater-obsidian/styles.css .obsidian/plugins/text-extractor/data.json .obsidian/plugins/text-extractor/main.js .obsidian/plugins/text-extractor/manifest.json .obsidian/types.json .obsidian/workspace.json 2 Personal/Home Lab/Drawing 2026-01-09 15.01.17.excalidraw.md
10770 lines
371 KiB
JavaScript
10770 lines
371 KiB
JavaScript
/*
|
|
THIS IS A GENERATED/BUNDLED FILE BY ROLLUP
|
|
if you want to view the source visit the plugins github repository
|
|
*/
|
|
|
|
'use strict';
|
|
|
|
var obsidian = require('obsidian');
|
|
|
|
/******************************************************************************
|
|
Copyright (c) Microsoft Corporation.
|
|
|
|
Permission to use, copy, modify, and/or distribute this software for any
|
|
purpose with or without fee is hereby granted.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
PERFORMANCE OF THIS SOFTWARE.
|
|
***************************************************************************** */
|
|
|
|
function __awaiter(thisArg, _arguments, P, generator) {
|
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
return new (P || (P = Promise))(function (resolve, reject) {
|
|
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
});
|
|
}
|
|
|
|
typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
|
|
var e = new Error(message);
|
|
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
};
|
|
|
|
/*
|
|
Copyright (c) 2022 Gildas Lormeau. All rights reserved.
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
modification, are permitted provided that the following conditions are met:
|
|
|
|
1. Redistributions of source code must retain the above copyright notice,
|
|
this list of conditions and the following disclaimer.
|
|
|
|
2. Redistributions in binary form must reproduce the above copyright
|
|
notice, this list of conditions and the following disclaimer in
|
|
the documentation and/or other materials provided with the distribution.
|
|
|
|
3. The names of the authors may not be used to endorse or promote products
|
|
derived from this software without specific prior written permission.
|
|
|
|
THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
|
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
|
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
|
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
|
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
/*
|
|
* This program is based on JZlib 1.0.2 ymnk, JCraft,Inc.
|
|
* JZlib is based on zlib-1.1.3, so all credit should go authors
|
|
* Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
|
|
* and contributors of zlib.
|
|
*/
|
|
|
|
// deno-lint-ignore-file no-this-alias prefer-const
|
|
|
|
// Global
|
|
|
|
const MAX_BITS$1 = 15;
|
|
const D_CODES = 30;
|
|
const BL_CODES = 19;
|
|
|
|
const LENGTH_CODES = 29;
|
|
const LITERALS = 256;
|
|
const L_CODES = (LITERALS + 1 + LENGTH_CODES);
|
|
const HEAP_SIZE = (2 * L_CODES + 1);
|
|
|
|
const END_BLOCK = 256;
|
|
|
|
// Bit length codes must not exceed MAX_BL_BITS bits
|
|
const MAX_BL_BITS = 7;
|
|
|
|
// repeat previous bit length 3-6 times (2 bits of repeat count)
|
|
const REP_3_6 = 16;
|
|
|
|
// repeat a zero length 3-10 times (3 bits of repeat count)
|
|
const REPZ_3_10 = 17;
|
|
|
|
// repeat a zero length 11-138 times (7 bits of repeat count)
|
|
const REPZ_11_138 = 18;
|
|
|
|
// The lengths of the bit length codes are sent in order of decreasing
|
|
// probability, to avoid transmitting the lengths for unused bit
|
|
// length codes.
|
|
|
|
const Buf_size = 8 * 2;
|
|
|
|
// JZlib version : "1.0.2"
|
|
const Z_DEFAULT_COMPRESSION = -1;
|
|
|
|
// compression strategy
|
|
const Z_FILTERED = 1;
|
|
const Z_HUFFMAN_ONLY = 2;
|
|
const Z_DEFAULT_STRATEGY = 0;
|
|
|
|
const Z_NO_FLUSH$1 = 0;
|
|
const Z_PARTIAL_FLUSH = 1;
|
|
const Z_FULL_FLUSH = 3;
|
|
const Z_FINISH$1 = 4;
|
|
|
|
const Z_OK$1 = 0;
|
|
const Z_STREAM_END$1 = 1;
|
|
const Z_NEED_DICT$1 = 2;
|
|
const Z_STREAM_ERROR$1 = -2;
|
|
const Z_DATA_ERROR$1 = -3;
|
|
const Z_BUF_ERROR$1 = -5;
|
|
|
|
// Tree
|
|
|
|
function extractArray(array) {
|
|
return flatArray(array.map(([length, value]) => (new Array(length)).fill(value, 0, length)));
|
|
}
|
|
|
|
function flatArray(array) {
|
|
return array.reduce((a, b) => a.concat(Array.isArray(b) ? flatArray(b) : b), []);
|
|
}
|
|
|
|
// see definition of array dist_code below
|
|
const _dist_code = [0, 1, 2, 3].concat(...extractArray([
|
|
[2, 4], [2, 5], [4, 6], [4, 7], [8, 8], [8, 9], [16, 10], [16, 11], [32, 12], [32, 13], [64, 14], [64, 15], [2, 0], [1, 16],
|
|
[1, 17], [2, 18], [2, 19], [4, 20], [4, 21], [8, 22], [8, 23], [16, 24], [16, 25], [32, 26], [32, 27], [64, 28], [64, 29]
|
|
]));
|
|
|
|
function Tree() {
|
|
const that = this;
|
|
|
|
// dyn_tree; // the dynamic tree
|
|
// max_code; // largest code with non zero frequency
|
|
// stat_desc; // the corresponding static tree
|
|
|
|
// Compute the optimal bit lengths for a tree and update the total bit
|
|
// length
|
|
// for the current block.
|
|
// IN assertion: the fields freq and dad are set, heap[heap_max] and
|
|
// above are the tree nodes sorted by increasing frequency.
|
|
// OUT assertions: the field len is set to the optimal bit length, the
|
|
// array bl_count contains the frequencies for each bit length.
|
|
// The length opt_len is updated; static_len is also updated if stree is
|
|
// not null.
|
|
function gen_bitlen(s) {
|
|
const tree = that.dyn_tree;
|
|
const stree = that.stat_desc.static_tree;
|
|
const extra = that.stat_desc.extra_bits;
|
|
const base = that.stat_desc.extra_base;
|
|
const max_length = that.stat_desc.max_length;
|
|
let h; // heap index
|
|
let n, m; // iterate over the tree elements
|
|
let bits; // bit length
|
|
let xbits; // extra bits
|
|
let f; // frequency
|
|
let overflow = 0; // number of elements with bit length too large
|
|
|
|
for (bits = 0; bits <= MAX_BITS$1; bits++)
|
|
s.bl_count[bits] = 0;
|
|
|
|
// In a first pass, compute the optimal bit lengths (which may
|
|
// overflow in the case of the bit length tree).
|
|
tree[s.heap[s.heap_max] * 2 + 1] = 0; // root of the heap
|
|
|
|
for (h = s.heap_max + 1; h < HEAP_SIZE; h++) {
|
|
n = s.heap[h];
|
|
bits = tree[tree[n * 2 + 1] * 2 + 1] + 1;
|
|
if (bits > max_length) {
|
|
bits = max_length;
|
|
overflow++;
|
|
}
|
|
tree[n * 2 + 1] = bits;
|
|
// We overwrite tree[n*2+1] which is no longer needed
|
|
|
|
if (n > that.max_code)
|
|
continue; // not a leaf node
|
|
|
|
s.bl_count[bits]++;
|
|
xbits = 0;
|
|
if (n >= base)
|
|
xbits = extra[n - base];
|
|
f = tree[n * 2];
|
|
s.opt_len += f * (bits + xbits);
|
|
if (stree)
|
|
s.static_len += f * (stree[n * 2 + 1] + xbits);
|
|
}
|
|
if (overflow === 0)
|
|
return;
|
|
|
|
// This happens for example on obj2 and pic of the Calgary corpus
|
|
// Find the first bit length which could increase:
|
|
do {
|
|
bits = max_length - 1;
|
|
while (s.bl_count[bits] === 0)
|
|
bits--;
|
|
s.bl_count[bits]--; // move one leaf down the tree
|
|
s.bl_count[bits + 1] += 2; // move one overflow item as its brother
|
|
s.bl_count[max_length]--;
|
|
// The brother of the overflow item also moves one step up,
|
|
// but this does not affect bl_count[max_length]
|
|
overflow -= 2;
|
|
} while (overflow > 0);
|
|
|
|
for (bits = max_length; bits !== 0; bits--) {
|
|
n = s.bl_count[bits];
|
|
while (n !== 0) {
|
|
m = s.heap[--h];
|
|
if (m > that.max_code)
|
|
continue;
|
|
if (tree[m * 2 + 1] != bits) {
|
|
s.opt_len += (bits - tree[m * 2 + 1]) * tree[m * 2];
|
|
tree[m * 2 + 1] = bits;
|
|
}
|
|
n--;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Reverse the first len bits of a code, using straightforward code (a
|
|
// faster
|
|
// method would use a table)
|
|
// IN assertion: 1 <= len <= 15
|
|
function bi_reverse(code, // the value to invert
|
|
len // its bit length
|
|
) {
|
|
let res = 0;
|
|
do {
|
|
res |= code & 1;
|
|
code >>>= 1;
|
|
res <<= 1;
|
|
} while (--len > 0);
|
|
return res >>> 1;
|
|
}
|
|
|
|
// Generate the codes for a given tree and bit counts (which need not be
|
|
// optimal).
|
|
// IN assertion: the array bl_count contains the bit length statistics for
|
|
// the given tree and the field len is set for all tree elements.
|
|
// OUT assertion: the field code is set for all tree elements of non
|
|
// zero code length.
|
|
function gen_codes(tree, // the tree to decorate
|
|
max_code, // largest code with non zero frequency
|
|
bl_count // number of codes at each bit length
|
|
) {
|
|
const next_code = []; // next code value for each
|
|
// bit length
|
|
let code = 0; // running code value
|
|
let bits; // bit index
|
|
let n; // code index
|
|
let len;
|
|
|
|
// The distribution counts are first used to generate the code values
|
|
// without bit reversal.
|
|
for (bits = 1; bits <= MAX_BITS$1; bits++) {
|
|
next_code[bits] = code = ((code + bl_count[bits - 1]) << 1);
|
|
}
|
|
|
|
// Check that the bit counts in bl_count are consistent. The last code
|
|
// must be all ones.
|
|
// Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1,
|
|
// "inconsistent bit counts");
|
|
// Tracev((stderr,"gen_codes: max_code %d ", max_code));
|
|
|
|
for (n = 0; n <= max_code; n++) {
|
|
len = tree[n * 2 + 1];
|
|
if (len === 0)
|
|
continue;
|
|
// Now reverse the bits
|
|
tree[n * 2] = bi_reverse(next_code[len]++, len);
|
|
}
|
|
}
|
|
|
|
// Construct one Huffman tree and assigns the code bit strings and lengths.
|
|
// Update the total bit length for the current block.
|
|
// IN assertion: the field freq is set for all tree elements.
|
|
// OUT assertions: the fields len and code are set to the optimal bit length
|
|
// and corresponding code. The length opt_len is updated; static_len is
|
|
// also updated if stree is not null. The field max_code is set.
|
|
that.build_tree = function (s) {
|
|
const tree = that.dyn_tree;
|
|
const stree = that.stat_desc.static_tree;
|
|
const elems = that.stat_desc.elems;
|
|
let n, m; // iterate over heap elements
|
|
let max_code = -1; // largest code with non zero frequency
|
|
let node; // new node being created
|
|
|
|
// Construct the initial heap, with least frequent element in
|
|
// heap[1]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
|
|
// heap[0] is not used.
|
|
s.heap_len = 0;
|
|
s.heap_max = HEAP_SIZE;
|
|
|
|
for (n = 0; n < elems; n++) {
|
|
if (tree[n * 2] !== 0) {
|
|
s.heap[++s.heap_len] = max_code = n;
|
|
s.depth[n] = 0;
|
|
} else {
|
|
tree[n * 2 + 1] = 0;
|
|
}
|
|
}
|
|
|
|
// The pkzip format requires that at least one distance code exists,
|
|
// and that at least one bit should be sent even if there is only one
|
|
// possible code. So to avoid special checks later on we force at least
|
|
// two codes of non zero frequency.
|
|
while (s.heap_len < 2) {
|
|
node = s.heap[++s.heap_len] = max_code < 2 ? ++max_code : 0;
|
|
tree[node * 2] = 1;
|
|
s.depth[node] = 0;
|
|
s.opt_len--;
|
|
if (stree)
|
|
s.static_len -= stree[node * 2 + 1];
|
|
// node is 0 or 1 so it does not have extra bits
|
|
}
|
|
that.max_code = max_code;
|
|
|
|
// The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
|
|
// establish sub-heaps of increasing lengths:
|
|
|
|
for (n = Math.floor(s.heap_len / 2); n >= 1; n--)
|
|
s.pqdownheap(tree, n);
|
|
|
|
// Construct the Huffman tree by repeatedly combining the least two
|
|
// frequent nodes.
|
|
|
|
node = elems; // next internal node of the tree
|
|
do {
|
|
// n = node of least frequency
|
|
n = s.heap[1];
|
|
s.heap[1] = s.heap[s.heap_len--];
|
|
s.pqdownheap(tree, 1);
|
|
m = s.heap[1]; // m = node of next least frequency
|
|
|
|
s.heap[--s.heap_max] = n; // keep the nodes sorted by frequency
|
|
s.heap[--s.heap_max] = m;
|
|
|
|
// Create a new node father of n and m
|
|
tree[node * 2] = (tree[n * 2] + tree[m * 2]);
|
|
s.depth[node] = Math.max(s.depth[n], s.depth[m]) + 1;
|
|
tree[n * 2 + 1] = tree[m * 2 + 1] = node;
|
|
|
|
// and insert the new node in the heap
|
|
s.heap[1] = node++;
|
|
s.pqdownheap(tree, 1);
|
|
} while (s.heap_len >= 2);
|
|
|
|
s.heap[--s.heap_max] = s.heap[1];
|
|
|
|
// At this point, the fields freq and dad are set. We can now
|
|
// generate the bit lengths.
|
|
|
|
gen_bitlen(s);
|
|
|
|
// The field len is now set, we can generate the bit codes
|
|
gen_codes(tree, that.max_code, s.bl_count);
|
|
};
|
|
|
|
}
|
|
|
|
Tree._length_code = [0, 1, 2, 3, 4, 5, 6, 7].concat(...extractArray([
|
|
[2, 8], [2, 9], [2, 10], [2, 11], [4, 12], [4, 13], [4, 14], [4, 15], [8, 16], [8, 17], [8, 18], [8, 19],
|
|
[16, 20], [16, 21], [16, 22], [16, 23], [32, 24], [32, 25], [32, 26], [31, 27], [1, 28]]));
|
|
|
|
Tree.base_length = [0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 0];
|
|
|
|
Tree.base_dist = [0, 1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384,
|
|
24576];
|
|
|
|
// Mapping from a distance to a distance code. dist is the distance - 1 and
|
|
// must not have side effects. _dist_code[256] and _dist_code[257] are never
|
|
// used.
|
|
Tree.d_code = function (dist) {
|
|
return ((dist) < 256 ? _dist_code[dist] : _dist_code[256 + ((dist) >>> 7)]);
|
|
};
|
|
|
|
// extra bits for each length code
|
|
Tree.extra_lbits = [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0];
|
|
|
|
// extra bits for each distance code
|
|
Tree.extra_dbits = [0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13];
|
|
|
|
// extra bits for each bit length code
|
|
Tree.extra_blbits = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 7];
|
|
|
|
Tree.bl_order = [16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15];
|
|
|
|
// StaticTree
|
|
|
|
function StaticTree(static_tree, extra_bits, extra_base, elems, max_length) {
|
|
const that = this;
|
|
that.static_tree = static_tree;
|
|
that.extra_bits = extra_bits;
|
|
that.extra_base = extra_base;
|
|
that.elems = elems;
|
|
that.max_length = max_length;
|
|
}
|
|
|
|
const static_ltree2_first_part = [12, 140, 76, 204, 44, 172, 108, 236, 28, 156, 92, 220, 60, 188, 124, 252, 2, 130, 66, 194, 34, 162, 98, 226, 18, 146, 82,
|
|
210, 50, 178, 114, 242, 10, 138, 74, 202, 42, 170, 106, 234, 26, 154, 90, 218, 58, 186, 122, 250, 6, 134, 70, 198, 38, 166, 102, 230, 22, 150, 86,
|
|
214, 54, 182, 118, 246, 14, 142, 78, 206, 46, 174, 110, 238, 30, 158, 94, 222, 62, 190, 126, 254, 1, 129, 65, 193, 33, 161, 97, 225, 17, 145, 81,
|
|
209, 49, 177, 113, 241, 9, 137, 73, 201, 41, 169, 105, 233, 25, 153, 89, 217, 57, 185, 121, 249, 5, 133, 69, 197, 37, 165, 101, 229, 21, 149, 85,
|
|
213, 53, 181, 117, 245, 13, 141, 77, 205, 45, 173, 109, 237, 29, 157, 93, 221, 61, 189, 125, 253, 19, 275, 147, 403, 83, 339, 211, 467, 51, 307,
|
|
179, 435, 115, 371, 243, 499, 11, 267, 139, 395, 75, 331, 203, 459, 43, 299, 171, 427, 107, 363, 235, 491, 27, 283, 155, 411, 91, 347, 219, 475,
|
|
59, 315, 187, 443, 123, 379, 251, 507, 7, 263, 135, 391, 71, 327, 199, 455, 39, 295, 167, 423, 103, 359, 231, 487, 23, 279, 151, 407, 87, 343, 215,
|
|
471, 55, 311, 183, 439, 119, 375, 247, 503, 15, 271, 143, 399, 79, 335, 207, 463, 47, 303, 175, 431, 111, 367, 239, 495, 31, 287, 159, 415, 95,
|
|
351, 223, 479, 63, 319, 191, 447, 127, 383, 255, 511, 0, 64, 32, 96, 16, 80, 48, 112, 8, 72, 40, 104, 24, 88, 56, 120, 4, 68, 36, 100, 20, 84, 52,
|
|
116, 3, 131, 67, 195, 35, 163, 99, 227];
|
|
const static_ltree2_second_part = extractArray([[144, 8], [112, 9], [24, 7], [8, 8]]);
|
|
StaticTree.static_ltree = flatArray(static_ltree2_first_part.map((value, index) => [value, static_ltree2_second_part[index]]));
|
|
|
|
const static_dtree_first_part = [0, 16, 8, 24, 4, 20, 12, 28, 2, 18, 10, 26, 6, 22, 14, 30, 1, 17, 9, 25, 5, 21, 13, 29, 3, 19, 11, 27, 7, 23];
|
|
const static_dtree_second_part = extractArray([[30, 5]]);
|
|
StaticTree.static_dtree = flatArray(static_dtree_first_part.map((value, index) => [value, static_dtree_second_part[index]]));
|
|
|
|
StaticTree.static_l_desc = new StaticTree(StaticTree.static_ltree, Tree.extra_lbits, LITERALS + 1, L_CODES, MAX_BITS$1);
|
|
|
|
StaticTree.static_d_desc = new StaticTree(StaticTree.static_dtree, Tree.extra_dbits, 0, D_CODES, MAX_BITS$1);
|
|
|
|
StaticTree.static_bl_desc = new StaticTree(null, Tree.extra_blbits, 0, BL_CODES, MAX_BL_BITS);
|
|
|
|
// Deflate
|
|
|
|
const MAX_MEM_LEVEL = 9;
|
|
const DEF_MEM_LEVEL = 8;
|
|
|
|
function Config(good_length, max_lazy, nice_length, max_chain, func) {
|
|
const that = this;
|
|
that.good_length = good_length;
|
|
that.max_lazy = max_lazy;
|
|
that.nice_length = nice_length;
|
|
that.max_chain = max_chain;
|
|
that.func = func;
|
|
}
|
|
|
|
const STORED$1 = 0;
|
|
const FAST = 1;
|
|
const SLOW = 2;
|
|
const config_table = [
|
|
new Config(0, 0, 0, 0, STORED$1),
|
|
new Config(4, 4, 8, 4, FAST),
|
|
new Config(4, 5, 16, 8, FAST),
|
|
new Config(4, 6, 32, 32, FAST),
|
|
new Config(4, 4, 16, 16, SLOW),
|
|
new Config(8, 16, 32, 32, SLOW),
|
|
new Config(8, 16, 128, 128, SLOW),
|
|
new Config(8, 32, 128, 256, SLOW),
|
|
new Config(32, 128, 258, 1024, SLOW),
|
|
new Config(32, 258, 258, 4096, SLOW)
|
|
];
|
|
|
|
const z_errmsg = ["need dictionary", // Z_NEED_DICT
|
|
// 2
|
|
"stream end", // Z_STREAM_END 1
|
|
"", // Z_OK 0
|
|
"", // Z_ERRNO (-1)
|
|
"stream error", // Z_STREAM_ERROR (-2)
|
|
"data error", // Z_DATA_ERROR (-3)
|
|
"", // Z_MEM_ERROR (-4)
|
|
"buffer error", // Z_BUF_ERROR (-5)
|
|
"",// Z_VERSION_ERROR (-6)
|
|
""];
|
|
|
|
// block not completed, need more input or more output
|
|
const NeedMore = 0;
|
|
|
|
// block flush performed
|
|
const BlockDone = 1;
|
|
|
|
// finish started, need only more output at next deflate
|
|
const FinishStarted = 2;
|
|
|
|
// finish done, accept no more input or output
|
|
const FinishDone = 3;
|
|
|
|
// preset dictionary flag in zlib header
|
|
const PRESET_DICT$1 = 0x20;
|
|
|
|
const INIT_STATE = 42;
|
|
const BUSY_STATE = 113;
|
|
const FINISH_STATE = 666;
|
|
|
|
// The deflate compression method
|
|
const Z_DEFLATED$1 = 8;
|
|
|
|
const STORED_BLOCK = 0;
|
|
const STATIC_TREES = 1;
|
|
const DYN_TREES = 2;
|
|
|
|
const MIN_MATCH = 3;
|
|
const MAX_MATCH = 258;
|
|
const MIN_LOOKAHEAD = (MAX_MATCH + MIN_MATCH + 1);
|
|
|
|
function smaller(tree, n, m, depth) {
|
|
const tn2 = tree[n * 2];
|
|
const tm2 = tree[m * 2];
|
|
return (tn2 < tm2 || (tn2 == tm2 && depth[n] <= depth[m]));
|
|
}
|
|
|
|
function Deflate() {
|
|
|
|
const that = this;
|
|
let strm; // pointer back to this zlib stream
|
|
let status; // as the name implies
|
|
// pending_buf; // output still pending
|
|
let pending_buf_size; // size of pending_buf
|
|
// pending_out; // next pending byte to output to the stream
|
|
// pending; // nb of bytes in the pending buffer
|
|
|
|
// dist_buf; // buffer for distances
|
|
// lc_buf; // buffer for literals or lengths
|
|
// To simplify the code, dist_buf and lc_buf have the same number of elements.
|
|
// To use different lengths, an extra flag array would be necessary.
|
|
|
|
let last_flush; // value of flush param for previous deflate call
|
|
|
|
let w_size; // LZ77 win size (32K by default)
|
|
let w_bits; // log2(w_size) (8..16)
|
|
let w_mask; // w_size - 1
|
|
|
|
let win;
|
|
// Sliding win. Input bytes are read into the second half of the win,
|
|
// and move to the first half later to keep a dictionary of at least wSize
|
|
// bytes. With this organization, matches are limited to a distance of
|
|
// wSize-MAX_MATCH bytes, but this ensures that IO is always
|
|
// performed with a length multiple of the block size. Also, it limits
|
|
// the win size to 64K, which is quite useful on MSDOS.
|
|
// To do: use the user input buffer as sliding win.
|
|
|
|
let window_size;
|
|
// Actual size of win: 2*wSize, except when the user input buffer
|
|
// is directly used as sliding win.
|
|
|
|
let prev;
|
|
// Link to older string with same hash index. To limit the size of this
|
|
// array to 64K, this link is maintained only for the last 32K strings.
|
|
// An index in this array is thus a win index modulo 32K.
|
|
|
|
let head; // Heads of the hash chains or NIL.
|
|
|
|
let ins_h; // hash index of string to be inserted
|
|
let hash_size; // number of elements in hash table
|
|
let hash_bits; // log2(hash_size)
|
|
let hash_mask; // hash_size-1
|
|
|
|
// Number of bits by which ins_h must be shifted at each input
|
|
// step. It must be such that after MIN_MATCH steps, the oldest
|
|
// byte no longer takes part in the hash key, that is:
|
|
// hash_shift * MIN_MATCH >= hash_bits
|
|
let hash_shift;
|
|
|
|
// Window position at the beginning of the current output block. Gets
|
|
// negative when the win is moved backwards.
|
|
|
|
let block_start;
|
|
|
|
let match_length; // length of best match
|
|
let prev_match; // previous match
|
|
let match_available; // set if previous match exists
|
|
let strstart; // start of string to insert
|
|
let match_start; // start of matching string
|
|
let lookahead; // number of valid bytes ahead in win
|
|
|
|
// Length of the best match at previous step. Matches not greater than this
|
|
// are discarded. This is used in the lazy match evaluation.
|
|
let prev_length;
|
|
|
|
// To speed up deflation, hash chains are never searched beyond this
|
|
// length. A higher limit improves compression ratio but degrades the speed.
|
|
let max_chain_length;
|
|
|
|
// Attempt to find a better match only when the current match is strictly
|
|
// smaller than this value. This mechanism is used only for compression
|
|
// levels >= 4.
|
|
let max_lazy_match;
|
|
|
|
// Insert new strings in the hash table only if the match length is not
|
|
// greater than this length. This saves time but degrades compression.
|
|
// max_insert_length is used only for compression levels <= 3.
|
|
|
|
let level; // compression level (1..9)
|
|
let strategy; // favor or force Huffman coding
|
|
|
|
// Use a faster search when the previous match is longer than this
|
|
let good_match;
|
|
|
|
// Stop searching when current match exceeds this
|
|
let nice_match;
|
|
|
|
let dyn_ltree; // literal and length tree
|
|
let dyn_dtree; // distance tree
|
|
let bl_tree; // Huffman tree for bit lengths
|
|
|
|
const l_desc = new Tree(); // desc for literal tree
|
|
const d_desc = new Tree(); // desc for distance tree
|
|
const bl_desc = new Tree(); // desc for bit length tree
|
|
|
|
// that.heap_len; // number of elements in the heap
|
|
// that.heap_max; // element of largest frequency
|
|
// The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
|
|
// The same heap array is used to build all trees.
|
|
|
|
// Depth of each subtree used as tie breaker for trees of equal frequency
|
|
that.depth = [];
|
|
|
|
// Size of match buffer for literals/lengths. There are 4 reasons for
|
|
// limiting lit_bufsize to 64K:
|
|
// - frequencies can be kept in 16 bit counters
|
|
// - if compression is not successful for the first block, all input
|
|
// data is still in the win so we can still emit a stored block even
|
|
// when input comes from standard input. (This can also be done for
|
|
// all blocks if lit_bufsize is not greater than 32K.)
|
|
// - if compression is not successful for a file smaller than 64K, we can
|
|
// even emit a stored file instead of a stored block (saving 5 bytes).
|
|
// This is applicable only for zip (not gzip or zlib).
|
|
// - creating new Huffman trees less frequently may not provide fast
|
|
// adaptation to changes in the input data statistics. (Take for
|
|
// example a binary file with poorly compressible code followed by
|
|
// a highly compressible string table.) Smaller buffer sizes give
|
|
// fast adaptation but have of course the overhead of transmitting
|
|
// trees more frequently.
|
|
// - I can't count above 4
|
|
let lit_bufsize;
|
|
|
|
let last_lit; // running index in dist_buf and lc_buf
|
|
|
|
// that.opt_len; // bit length of current block with optimal trees
|
|
// that.static_len; // bit length of current block with static trees
|
|
let matches; // number of string matches in current block
|
|
let last_eob_len; // bit length of EOB code for last block
|
|
|
|
// Output buffer. bits are inserted starting at the bottom (least
|
|
// significant bits).
|
|
let bi_buf;
|
|
|
|
// Number of valid bits in bi_buf. All bits above the last valid bit
|
|
// are always zero.
|
|
let bi_valid;
|
|
|
|
// number of codes at each bit length for an optimal tree
|
|
that.bl_count = [];
|
|
|
|
// heap used to build the Huffman trees
|
|
that.heap = [];
|
|
|
|
dyn_ltree = [];
|
|
dyn_dtree = [];
|
|
bl_tree = [];
|
|
|
|
function lm_init() {
|
|
window_size = 2 * w_size;
|
|
|
|
head[hash_size - 1] = 0;
|
|
for (let i = 0; i < hash_size - 1; i++) {
|
|
head[i] = 0;
|
|
}
|
|
|
|
// Set the default configuration parameters:
|
|
max_lazy_match = config_table[level].max_lazy;
|
|
good_match = config_table[level].good_length;
|
|
nice_match = config_table[level].nice_length;
|
|
max_chain_length = config_table[level].max_chain;
|
|
|
|
strstart = 0;
|
|
block_start = 0;
|
|
lookahead = 0;
|
|
match_length = prev_length = MIN_MATCH - 1;
|
|
match_available = 0;
|
|
ins_h = 0;
|
|
}
|
|
|
|
function init_block() {
|
|
let i;
|
|
// Initialize the trees.
|
|
for (i = 0; i < L_CODES; i++)
|
|
dyn_ltree[i * 2] = 0;
|
|
for (i = 0; i < D_CODES; i++)
|
|
dyn_dtree[i * 2] = 0;
|
|
for (i = 0; i < BL_CODES; i++)
|
|
bl_tree[i * 2] = 0;
|
|
|
|
dyn_ltree[END_BLOCK * 2] = 1;
|
|
that.opt_len = that.static_len = 0;
|
|
last_lit = matches = 0;
|
|
}
|
|
|
|
// Initialize the tree data structures for a new zlib stream.
|
|
function tr_init() {
|
|
|
|
l_desc.dyn_tree = dyn_ltree;
|
|
l_desc.stat_desc = StaticTree.static_l_desc;
|
|
|
|
d_desc.dyn_tree = dyn_dtree;
|
|
d_desc.stat_desc = StaticTree.static_d_desc;
|
|
|
|
bl_desc.dyn_tree = bl_tree;
|
|
bl_desc.stat_desc = StaticTree.static_bl_desc;
|
|
|
|
bi_buf = 0;
|
|
bi_valid = 0;
|
|
last_eob_len = 8; // enough lookahead for inflate
|
|
|
|
// Initialize the first block of the first file:
|
|
init_block();
|
|
}
|
|
|
|
// Restore the heap property by moving down the tree starting at node k,
|
|
// exchanging a node with the smallest of its two sons if necessary,
|
|
// stopping
|
|
// when the heap property is re-established (each father smaller than its
|
|
// two sons).
|
|
that.pqdownheap = function (tree, // the tree to restore
|
|
k // node to move down
|
|
) {
|
|
const heap = that.heap;
|
|
const v = heap[k];
|
|
let j = k << 1; // left son of k
|
|
while (j <= that.heap_len) {
|
|
// Set j to the smallest of the two sons:
|
|
if (j < that.heap_len && smaller(tree, heap[j + 1], heap[j], that.depth)) {
|
|
j++;
|
|
}
|
|
// Exit if v is smaller than both sons
|
|
if (smaller(tree, v, heap[j], that.depth))
|
|
break;
|
|
|
|
// Exchange v with the smallest son
|
|
heap[k] = heap[j];
|
|
k = j;
|
|
// And continue down the tree, setting j to the left son of k
|
|
j <<= 1;
|
|
}
|
|
heap[k] = v;
|
|
};
|
|
|
|
// Scan a literal or distance tree to determine the frequencies of the codes
|
|
// in the bit length tree.
|
|
function scan_tree(tree,// the tree to be scanned
|
|
max_code // and its largest code of non zero frequency
|
|
) {
|
|
let prevlen = -1; // last emitted length
|
|
let curlen; // length of current code
|
|
let nextlen = tree[0 * 2 + 1]; // length of next code
|
|
let count = 0; // repeat count of the current code
|
|
let max_count = 7; // max repeat count
|
|
let min_count = 4; // min repeat count
|
|
|
|
if (nextlen === 0) {
|
|
max_count = 138;
|
|
min_count = 3;
|
|
}
|
|
tree[(max_code + 1) * 2 + 1] = 0xffff; // guard
|
|
|
|
for (let n = 0; n <= max_code; n++) {
|
|
curlen = nextlen;
|
|
nextlen = tree[(n + 1) * 2 + 1];
|
|
if (++count < max_count && curlen == nextlen) {
|
|
continue;
|
|
} else if (count < min_count) {
|
|
bl_tree[curlen * 2] += count;
|
|
} else if (curlen !== 0) {
|
|
if (curlen != prevlen)
|
|
bl_tree[curlen * 2]++;
|
|
bl_tree[REP_3_6 * 2]++;
|
|
} else if (count <= 10) {
|
|
bl_tree[REPZ_3_10 * 2]++;
|
|
} else {
|
|
bl_tree[REPZ_11_138 * 2]++;
|
|
}
|
|
count = 0;
|
|
prevlen = curlen;
|
|
if (nextlen === 0) {
|
|
max_count = 138;
|
|
min_count = 3;
|
|
} else if (curlen == nextlen) {
|
|
max_count = 6;
|
|
min_count = 3;
|
|
} else {
|
|
max_count = 7;
|
|
min_count = 4;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Construct the Huffman tree for the bit lengths and return the index in
|
|
// bl_order of the last bit length code to send.
|
|
function build_bl_tree() {
|
|
let max_blindex; // index of last bit length code of non zero freq
|
|
|
|
// Determine the bit length frequencies for literal and distance trees
|
|
scan_tree(dyn_ltree, l_desc.max_code);
|
|
scan_tree(dyn_dtree, d_desc.max_code);
|
|
|
|
// Build the bit length tree:
|
|
bl_desc.build_tree(that);
|
|
// opt_len now includes the length of the tree representations, except
|
|
// the lengths of the bit lengths codes and the 5+5+4 bits for the
|
|
// counts.
|
|
|
|
// Determine the number of bit length codes to send. The pkzip format
|
|
// requires that at least 4 bit length codes be sent. (appnote.txt says
|
|
// 3 but the actual value used is 4.)
|
|
for (max_blindex = BL_CODES - 1; max_blindex >= 3; max_blindex--) {
|
|
if (bl_tree[Tree.bl_order[max_blindex] * 2 + 1] !== 0)
|
|
break;
|
|
}
|
|
// Update opt_len to include the bit length tree and counts
|
|
that.opt_len += 3 * (max_blindex + 1) + 5 + 5 + 4;
|
|
|
|
return max_blindex;
|
|
}
|
|
|
|
// Output a byte on the stream.
|
|
// IN assertion: there is enough room in pending_buf.
|
|
function put_byte(p) {
|
|
that.pending_buf[that.pending++] = p;
|
|
}
|
|
|
|
function put_short(w) {
|
|
put_byte(w & 0xff);
|
|
put_byte((w >>> 8) & 0xff);
|
|
}
|
|
|
|
function putShortMSB(b) {
|
|
put_byte((b >> 8) & 0xff);
|
|
put_byte((b & 0xff) & 0xff);
|
|
}
|
|
|
|
function send_bits(value, length) {
|
|
let val;
|
|
const len = length;
|
|
if (bi_valid > Buf_size - len) {
|
|
val = value;
|
|
// bi_buf |= (val << bi_valid);
|
|
bi_buf |= ((val << bi_valid) & 0xffff);
|
|
put_short(bi_buf);
|
|
bi_buf = val >>> (Buf_size - bi_valid);
|
|
bi_valid += len - Buf_size;
|
|
} else {
|
|
// bi_buf |= (value) << bi_valid;
|
|
bi_buf |= (((value) << bi_valid) & 0xffff);
|
|
bi_valid += len;
|
|
}
|
|
}
|
|
|
|
function send_code(c, tree) {
|
|
const c2 = c * 2;
|
|
send_bits(tree[c2] & 0xffff, tree[c2 + 1] & 0xffff);
|
|
}
|
|
|
|
// Send a literal or distance tree in compressed form, using the codes in
|
|
// bl_tree.
|
|
function send_tree(tree,// the tree to be sent
|
|
max_code // and its largest code of non zero frequency
|
|
) {
|
|
let n; // iterates over all tree elements
|
|
let prevlen = -1; // last emitted length
|
|
let curlen; // length of current code
|
|
let nextlen = tree[0 * 2 + 1]; // length of next code
|
|
let count = 0; // repeat count of the current code
|
|
let max_count = 7; // max repeat count
|
|
let min_count = 4; // min repeat count
|
|
|
|
if (nextlen === 0) {
|
|
max_count = 138;
|
|
min_count = 3;
|
|
}
|
|
|
|
for (n = 0; n <= max_code; n++) {
|
|
curlen = nextlen;
|
|
nextlen = tree[(n + 1) * 2 + 1];
|
|
if (++count < max_count && curlen == nextlen) {
|
|
continue;
|
|
} else if (count < min_count) {
|
|
do {
|
|
send_code(curlen, bl_tree);
|
|
} while (--count !== 0);
|
|
} else if (curlen !== 0) {
|
|
if (curlen != prevlen) {
|
|
send_code(curlen, bl_tree);
|
|
count--;
|
|
}
|
|
send_code(REP_3_6, bl_tree);
|
|
send_bits(count - 3, 2);
|
|
} else if (count <= 10) {
|
|
send_code(REPZ_3_10, bl_tree);
|
|
send_bits(count - 3, 3);
|
|
} else {
|
|
send_code(REPZ_11_138, bl_tree);
|
|
send_bits(count - 11, 7);
|
|
}
|
|
count = 0;
|
|
prevlen = curlen;
|
|
if (nextlen === 0) {
|
|
max_count = 138;
|
|
min_count = 3;
|
|
} else if (curlen == nextlen) {
|
|
max_count = 6;
|
|
min_count = 3;
|
|
} else {
|
|
max_count = 7;
|
|
min_count = 4;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Send the header for a block using dynamic Huffman trees: the counts, the
|
|
// lengths of the bit length codes, the literal tree and the distance tree.
|
|
// IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
|
|
function send_all_trees(lcodes, dcodes, blcodes) {
|
|
let rank; // index in bl_order
|
|
|
|
send_bits(lcodes - 257, 5); // not +255 as stated in appnote.txt
|
|
send_bits(dcodes - 1, 5);
|
|
send_bits(blcodes - 4, 4); // not -3 as stated in appnote.txt
|
|
for (rank = 0; rank < blcodes; rank++) {
|
|
send_bits(bl_tree[Tree.bl_order[rank] * 2 + 1], 3);
|
|
}
|
|
send_tree(dyn_ltree, lcodes - 1); // literal tree
|
|
send_tree(dyn_dtree, dcodes - 1); // distance tree
|
|
}
|
|
|
|
// Flush the bit buffer, keeping at most 7 bits in it.
|
|
function bi_flush() {
|
|
if (bi_valid == 16) {
|
|
put_short(bi_buf);
|
|
bi_buf = 0;
|
|
bi_valid = 0;
|
|
} else if (bi_valid >= 8) {
|
|
put_byte(bi_buf & 0xff);
|
|
bi_buf >>>= 8;
|
|
bi_valid -= 8;
|
|
}
|
|
}
|
|
|
|
// Send one empty static block to give enough lookahead for inflate.
|
|
// This takes 10 bits, of which 7 may remain in the bit buffer.
|
|
// The current inflate code requires 9 bits of lookahead. If the
|
|
// last two codes for the previous block (real code plus EOB) were coded
|
|
// on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode
|
|
// the last real code. In this case we send two empty static blocks instead
|
|
// of one. (There are no problems if the previous block is stored or fixed.)
|
|
// To simplify the code, we assume the worst case of last real code encoded
|
|
// on one bit only.
|
|
function _tr_align() {
|
|
send_bits(STATIC_TREES << 1, 3);
|
|
send_code(END_BLOCK, StaticTree.static_ltree);
|
|
|
|
bi_flush();
|
|
|
|
// Of the 10 bits for the empty block, we have already sent
|
|
// (10 - bi_valid) bits. The lookahead for the last real code (before
|
|
// the EOB of the previous block) was thus at least one plus the length
|
|
// of the EOB plus what we have just sent of the empty static block.
|
|
if (1 + last_eob_len + 10 - bi_valid < 9) {
|
|
send_bits(STATIC_TREES << 1, 3);
|
|
send_code(END_BLOCK, StaticTree.static_ltree);
|
|
bi_flush();
|
|
}
|
|
last_eob_len = 7;
|
|
}
|
|
|
|
// Save the match info and tally the frequency counts. Return true if
|
|
// the current block must be flushed.
|
|
function _tr_tally(dist, // distance of matched string
|
|
lc // match length-MIN_MATCH or unmatched char (if dist==0)
|
|
) {
|
|
let out_length, in_length, dcode;
|
|
that.dist_buf[last_lit] = dist;
|
|
that.lc_buf[last_lit] = lc & 0xff;
|
|
last_lit++;
|
|
|
|
if (dist === 0) {
|
|
// lc is the unmatched char
|
|
dyn_ltree[lc * 2]++;
|
|
} else {
|
|
matches++;
|
|
// Here, lc is the match length - MIN_MATCH
|
|
dist--; // dist = match distance - 1
|
|
dyn_ltree[(Tree._length_code[lc] + LITERALS + 1) * 2]++;
|
|
dyn_dtree[Tree.d_code(dist) * 2]++;
|
|
}
|
|
|
|
if ((last_lit & 0x1fff) === 0 && level > 2) {
|
|
// Compute an upper bound for the compressed length
|
|
out_length = last_lit * 8;
|
|
in_length = strstart - block_start;
|
|
for (dcode = 0; dcode < D_CODES; dcode++) {
|
|
out_length += dyn_dtree[dcode * 2] * (5 + Tree.extra_dbits[dcode]);
|
|
}
|
|
out_length >>>= 3;
|
|
if ((matches < Math.floor(last_lit / 2)) && out_length < Math.floor(in_length / 2))
|
|
return true;
|
|
}
|
|
|
|
return (last_lit == lit_bufsize - 1);
|
|
// We avoid equality with lit_bufsize because of wraparound at 64K
|
|
// on 16 bit machines and because stored blocks are restricted to
|
|
// 64K-1 bytes.
|
|
}
|
|
|
|
// Send the block data compressed using the given Huffman trees
|
|
function compress_block(ltree, dtree) {
|
|
let dist; // distance of matched string
|
|
let lc; // match length or unmatched char (if dist === 0)
|
|
let lx = 0; // running index in dist_buf and lc_buf
|
|
let code; // the code to send
|
|
let extra; // number of extra bits to send
|
|
|
|
if (last_lit !== 0) {
|
|
do {
|
|
dist = that.dist_buf[lx];
|
|
lc = that.lc_buf[lx];
|
|
lx++;
|
|
|
|
if (dist === 0) {
|
|
send_code(lc, ltree); // send a literal byte
|
|
} else {
|
|
// Here, lc is the match length - MIN_MATCH
|
|
code = Tree._length_code[lc];
|
|
|
|
send_code(code + LITERALS + 1, ltree); // send the length
|
|
// code
|
|
extra = Tree.extra_lbits[code];
|
|
if (extra !== 0) {
|
|
lc -= Tree.base_length[code];
|
|
send_bits(lc, extra); // send the extra length bits
|
|
}
|
|
dist--; // dist is now the match distance - 1
|
|
code = Tree.d_code(dist);
|
|
|
|
send_code(code, dtree); // send the distance code
|
|
extra = Tree.extra_dbits[code];
|
|
if (extra !== 0) {
|
|
dist -= Tree.base_dist[code];
|
|
send_bits(dist, extra); // send the extra distance bits
|
|
}
|
|
} // literal or match pair ?
|
|
} while (lx < last_lit);
|
|
}
|
|
|
|
send_code(END_BLOCK, ltree);
|
|
last_eob_len = ltree[END_BLOCK * 2 + 1];
|
|
}
|
|
|
|
// Flush the bit buffer and align the output on a byte boundary
|
|
function bi_windup() {
|
|
if (bi_valid > 8) {
|
|
put_short(bi_buf);
|
|
} else if (bi_valid > 0) {
|
|
put_byte(bi_buf & 0xff);
|
|
}
|
|
bi_buf = 0;
|
|
bi_valid = 0;
|
|
}
|
|
|
|
// Copy a stored block, storing first the length and its
|
|
// one's complement if requested.
|
|
function copy_block(buf, // the input data
|
|
len, // its length
|
|
header // true if block header must be written
|
|
) {
|
|
bi_windup(); // align on byte boundary
|
|
last_eob_len = 8; // enough lookahead for inflate
|
|
|
|
if (header) {
|
|
put_short(len);
|
|
put_short(~len);
|
|
}
|
|
|
|
that.pending_buf.set(win.subarray(buf, buf + len), that.pending);
|
|
that.pending += len;
|
|
}
|
|
|
|
// Send a stored block
|
|
function _tr_stored_block(buf, // input block
|
|
stored_len, // length of input block
|
|
eof // true if this is the last block for a file
|
|
) {
|
|
send_bits((STORED_BLOCK << 1) + (eof ? 1 : 0), 3); // send block type
|
|
copy_block(buf, stored_len, true); // with header
|
|
}
|
|
|
|
// Determine the best encoding for the current block: dynamic trees, static
|
|
// trees or store, and output the encoded block to the zip file.
|
|
function _tr_flush_block(buf, // input block, or NULL if too old
|
|
stored_len, // length of input block
|
|
eof // true if this is the last block for a file
|
|
) {
|
|
let opt_lenb, static_lenb;// opt_len and static_len in bytes
|
|
let max_blindex = 0; // index of last bit length code of non zero freq
|
|
|
|
// Build the Huffman trees unless a stored block is forced
|
|
if (level > 0) {
|
|
// Construct the literal and distance trees
|
|
l_desc.build_tree(that);
|
|
|
|
d_desc.build_tree(that);
|
|
|
|
// At this point, opt_len and static_len are the total bit lengths
|
|
// of
|
|
// the compressed block data, excluding the tree representations.
|
|
|
|
// Build the bit length tree for the above two trees, and get the
|
|
// index
|
|
// in bl_order of the last bit length code to send.
|
|
max_blindex = build_bl_tree();
|
|
|
|
// Determine the best encoding. Compute first the block length in
|
|
// bytes
|
|
opt_lenb = (that.opt_len + 3 + 7) >>> 3;
|
|
static_lenb = (that.static_len + 3 + 7) >>> 3;
|
|
|
|
if (static_lenb <= opt_lenb)
|
|
opt_lenb = static_lenb;
|
|
} else {
|
|
opt_lenb = static_lenb = stored_len + 5; // force a stored block
|
|
}
|
|
|
|
if ((stored_len + 4 <= opt_lenb) && buf != -1) {
|
|
// 4: two words for the lengths
|
|
// The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
|
|
// Otherwise we can't have processed more than WSIZE input bytes
|
|
// since
|
|
// the last block flush, because compression would have been
|
|
// successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
|
|
// transform a block into a stored block.
|
|
_tr_stored_block(buf, stored_len, eof);
|
|
} else if (static_lenb == opt_lenb) {
|
|
send_bits((STATIC_TREES << 1) + (eof ? 1 : 0), 3);
|
|
compress_block(StaticTree.static_ltree, StaticTree.static_dtree);
|
|
} else {
|
|
send_bits((DYN_TREES << 1) + (eof ? 1 : 0), 3);
|
|
send_all_trees(l_desc.max_code + 1, d_desc.max_code + 1, max_blindex + 1);
|
|
compress_block(dyn_ltree, dyn_dtree);
|
|
}
|
|
|
|
// The above check is made mod 2^32, for files larger than 512 MB
|
|
// and uLong implemented on 32 bits.
|
|
|
|
init_block();
|
|
|
|
if (eof) {
|
|
bi_windup();
|
|
}
|
|
}
|
|
|
|
function flush_block_only(eof) {
|
|
_tr_flush_block(block_start >= 0 ? block_start : -1, strstart - block_start, eof);
|
|
block_start = strstart;
|
|
strm.flush_pending();
|
|
}
|
|
|
|
// Fill the win when the lookahead becomes insufficient.
|
|
// Updates strstart and lookahead.
|
|
//
|
|
// IN assertion: lookahead < MIN_LOOKAHEAD
|
|
// OUT assertions: strstart <= window_size-MIN_LOOKAHEAD
|
|
// At least one byte has been read, or avail_in === 0; reads are
|
|
// performed for at least two bytes (required for the zip translate_eol
|
|
// option -- not supported here).
|
|
function fill_window() {
|
|
let n, m;
|
|
let p;
|
|
let more; // Amount of free space at the end of the win.
|
|
|
|
do {
|
|
more = (window_size - lookahead - strstart);
|
|
|
|
// Deal with !@#$% 64K limit:
|
|
if (more === 0 && strstart === 0 && lookahead === 0) {
|
|
more = w_size;
|
|
} else if (more == -1) {
|
|
// Very unlikely, but possible on 16 bit machine if strstart ==
|
|
// 0
|
|
// and lookahead == 1 (input done one byte at time)
|
|
more--;
|
|
|
|
// If the win is almost full and there is insufficient
|
|
// lookahead,
|
|
// move the upper half to the lower one to make room in the
|
|
// upper half.
|
|
} else if (strstart >= w_size + w_size - MIN_LOOKAHEAD) {
|
|
win.set(win.subarray(w_size, w_size + w_size), 0);
|
|
|
|
match_start -= w_size;
|
|
strstart -= w_size; // we now have strstart >= MAX_DIST
|
|
block_start -= w_size;
|
|
|
|
// Slide the hash table (could be avoided with 32 bit values
|
|
// at the expense of memory usage). We slide even when level ==
|
|
// 0
|
|
// to keep the hash table consistent if we switch back to level
|
|
// > 0
|
|
// later. (Using level 0 permanently is not an optimal usage of
|
|
// zlib, so we don't care about this pathological case.)
|
|
|
|
n = hash_size;
|
|
p = n;
|
|
do {
|
|
m = (head[--p] & 0xffff);
|
|
head[p] = (m >= w_size ? m - w_size : 0);
|
|
} while (--n !== 0);
|
|
|
|
n = w_size;
|
|
p = n;
|
|
do {
|
|
m = (prev[--p] & 0xffff);
|
|
prev[p] = (m >= w_size ? m - w_size : 0);
|
|
// If n is not on any hash chain, prev[n] is garbage but
|
|
// its value will never be used.
|
|
} while (--n !== 0);
|
|
more += w_size;
|
|
}
|
|
|
|
if (strm.avail_in === 0)
|
|
return;
|
|
|
|
// If there was no sliding:
|
|
// strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&
|
|
// more == window_size - lookahead - strstart
|
|
// => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)
|
|
// => more >= window_size - 2*WSIZE + 2
|
|
// In the BIG_MEM or MMAP case (not yet supported),
|
|
// window_size == input_size + MIN_LOOKAHEAD &&
|
|
// strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD.
|
|
// Otherwise, window_size == 2*WSIZE so more >= 2.
|
|
// If there was sliding, more >= WSIZE. So in all cases, more >= 2.
|
|
|
|
n = strm.read_buf(win, strstart + lookahead, more);
|
|
lookahead += n;
|
|
|
|
// Initialize the hash value now that we have some input:
|
|
if (lookahead >= MIN_MATCH) {
|
|
ins_h = win[strstart] & 0xff;
|
|
ins_h = (((ins_h) << hash_shift) ^ (win[strstart + 1] & 0xff)) & hash_mask;
|
|
}
|
|
// If the whole input has less than MIN_MATCH bytes, ins_h is
|
|
// garbage,
|
|
// but this is not important since only literal bytes will be
|
|
// emitted.
|
|
} while (lookahead < MIN_LOOKAHEAD && strm.avail_in !== 0);
|
|
}
|
|
|
|
// Copy without compression as much as possible from the input stream,
|
|
// return
|
|
// the current block state.
|
|
// This function does not insert new strings in the dictionary since
|
|
// uncompressible data is probably not useful. This function is used
|
|
// only for the level=0 compression option.
|
|
// NOTE: this function should be optimized to avoid extra copying from
|
|
// win to pending_buf.
|
|
function deflate_stored(flush) {
|
|
// Stored blocks are limited to 0xffff bytes, pending_buf is limited
|
|
// to pending_buf_size, and each stored block has a 5 byte header:
|
|
|
|
let max_block_size = 0xffff;
|
|
let max_start;
|
|
|
|
if (max_block_size > pending_buf_size - 5) {
|
|
max_block_size = pending_buf_size - 5;
|
|
}
|
|
|
|
// Copy as much as possible from input to output:
|
|
// eslint-disable-next-line no-constant-condition
|
|
while (true) {
|
|
// Fill the win as much as possible:
|
|
if (lookahead <= 1) {
|
|
fill_window();
|
|
if (lookahead === 0 && flush == Z_NO_FLUSH$1)
|
|
return NeedMore;
|
|
if (lookahead === 0)
|
|
break; // flush the current block
|
|
}
|
|
|
|
strstart += lookahead;
|
|
lookahead = 0;
|
|
|
|
// Emit a stored block if pending_buf will be full:
|
|
max_start = block_start + max_block_size;
|
|
if (strstart === 0 || strstart >= max_start) {
|
|
// strstart === 0 is possible when wraparound on 16-bit machine
|
|
lookahead = (strstart - max_start);
|
|
strstart = max_start;
|
|
|
|
flush_block_only(false);
|
|
if (strm.avail_out === 0)
|
|
return NeedMore;
|
|
|
|
}
|
|
|
|
// Flush if we may have to slide, otherwise block_start may become
|
|
// negative and the data will be gone:
|
|
if (strstart - block_start >= w_size - MIN_LOOKAHEAD) {
|
|
flush_block_only(false);
|
|
if (strm.avail_out === 0)
|
|
return NeedMore;
|
|
}
|
|
}
|
|
|
|
flush_block_only(flush == Z_FINISH$1);
|
|
if (strm.avail_out === 0)
|
|
return (flush == Z_FINISH$1) ? FinishStarted : NeedMore;
|
|
|
|
return flush == Z_FINISH$1 ? FinishDone : BlockDone;
|
|
}
|
|
|
|
function longest_match(cur_match) {
|
|
let chain_length = max_chain_length; // max hash chain length
|
|
let scan = strstart; // current string
|
|
let match; // matched string
|
|
let len; // length of current match
|
|
let best_len = prev_length; // best match length so far
|
|
const limit = strstart > (w_size - MIN_LOOKAHEAD) ? strstart - (w_size - MIN_LOOKAHEAD) : 0;
|
|
let _nice_match = nice_match;
|
|
|
|
// Stop when cur_match becomes <= limit. To simplify the code,
|
|
// we prevent matches with the string of win index 0.
|
|
|
|
const wmask = w_mask;
|
|
|
|
const strend = strstart + MAX_MATCH;
|
|
let scan_end1 = win[scan + best_len - 1];
|
|
let scan_end = win[scan + best_len];
|
|
|
|
// The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of
|
|
// 16.
|
|
// It is easy to get rid of this optimization if necessary.
|
|
|
|
// Do not waste too much time if we already have a good match:
|
|
if (prev_length >= good_match) {
|
|
chain_length >>= 2;
|
|
}
|
|
|
|
// Do not look for matches beyond the end of the input. This is
|
|
// necessary
|
|
// to make deflate deterministic.
|
|
if (_nice_match > lookahead)
|
|
_nice_match = lookahead;
|
|
|
|
do {
|
|
match = cur_match;
|
|
|
|
// Skip to next match if the match length cannot increase
|
|
// or if the match length is less than 2:
|
|
if (win[match + best_len] != scan_end || win[match + best_len - 1] != scan_end1 || win[match] != win[scan]
|
|
|| win[++match] != win[scan + 1])
|
|
continue;
|
|
|
|
// The check at best_len-1 can be removed because it will be made
|
|
// again later. (This heuristic is not always a win.)
|
|
// It is not necessary to compare scan[2] and match[2] since they
|
|
// are always equal when the other bytes match, given that
|
|
// the hash keys are equal and that HASH_BITS >= 8.
|
|
scan += 2;
|
|
match++;
|
|
|
|
// We check for insufficient lookahead only every 8th comparison;
|
|
// the 256th check will be made at strstart+258.
|
|
// eslint-disable-next-line no-empty
|
|
do {
|
|
// empty block
|
|
} while (win[++scan] == win[++match] && win[++scan] == win[++match] && win[++scan] == win[++match]
|
|
&& win[++scan] == win[++match] && win[++scan] == win[++match] && win[++scan] == win[++match]
|
|
&& win[++scan] == win[++match] && win[++scan] == win[++match] && scan < strend);
|
|
|
|
len = MAX_MATCH - (strend - scan);
|
|
scan = strend - MAX_MATCH;
|
|
|
|
if (len > best_len) {
|
|
match_start = cur_match;
|
|
best_len = len;
|
|
if (len >= _nice_match)
|
|
break;
|
|
scan_end1 = win[scan + best_len - 1];
|
|
scan_end = win[scan + best_len];
|
|
}
|
|
|
|
} while ((cur_match = (prev[cur_match & wmask] & 0xffff)) > limit && --chain_length !== 0);
|
|
|
|
if (best_len <= lookahead)
|
|
return best_len;
|
|
return lookahead;
|
|
}
|
|
|
|
// Compress as much as possible from the input stream, return the current
|
|
// block state.
|
|
// This function does not perform lazy evaluation of matches and inserts
|
|
// new strings in the dictionary only for unmatched strings or for short
|
|
// matches. It is used only for the fast compression options.
|
|
function deflate_fast(flush) {
|
|
// short hash_head = 0; // head of the hash chain
|
|
let hash_head = 0; // head of the hash chain
|
|
let bflush; // set if current block must be flushed
|
|
|
|
// eslint-disable-next-line no-constant-condition
|
|
while (true) {
|
|
// Make sure that we always have enough lookahead, except
|
|
// at the end of the input file. We need MAX_MATCH bytes
|
|
// for the next match, plus MIN_MATCH bytes to insert the
|
|
// string following the next match.
|
|
if (lookahead < MIN_LOOKAHEAD) {
|
|
fill_window();
|
|
if (lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH$1) {
|
|
return NeedMore;
|
|
}
|
|
if (lookahead === 0)
|
|
break; // flush the current block
|
|
}
|
|
|
|
// Insert the string win[strstart .. strstart+2] in the
|
|
// dictionary, and set hash_head to the head of the hash chain:
|
|
if (lookahead >= MIN_MATCH) {
|
|
ins_h = (((ins_h) << hash_shift) ^ (win[(strstart) + (MIN_MATCH - 1)] & 0xff)) & hash_mask;
|
|
|
|
// prev[strstart&w_mask]=hash_head=head[ins_h];
|
|
hash_head = (head[ins_h] & 0xffff);
|
|
prev[strstart & w_mask] = head[ins_h];
|
|
head[ins_h] = strstart;
|
|
}
|
|
|
|
// Find the longest match, discarding those <= prev_length.
|
|
// At this point we have always match_length < MIN_MATCH
|
|
|
|
if (hash_head !== 0 && ((strstart - hash_head) & 0xffff) <= w_size - MIN_LOOKAHEAD) {
|
|
// To simplify the code, we prevent matches with the string
|
|
// of win index 0 (in particular we have to avoid a match
|
|
// of the string with itself at the start of the input file).
|
|
if (strategy != Z_HUFFMAN_ONLY) {
|
|
match_length = longest_match(hash_head);
|
|
}
|
|
// longest_match() sets match_start
|
|
}
|
|
if (match_length >= MIN_MATCH) {
|
|
// check_match(strstart, match_start, match_length);
|
|
|
|
bflush = _tr_tally(strstart - match_start, match_length - MIN_MATCH);
|
|
|
|
lookahead -= match_length;
|
|
|
|
// Insert new strings in the hash table only if the match length
|
|
// is not too large. This saves time but degrades compression.
|
|
if (match_length <= max_lazy_match && lookahead >= MIN_MATCH) {
|
|
match_length--; // string at strstart already in hash table
|
|
do {
|
|
strstart++;
|
|
|
|
ins_h = ((ins_h << hash_shift) ^ (win[(strstart) + (MIN_MATCH - 1)] & 0xff)) & hash_mask;
|
|
// prev[strstart&w_mask]=hash_head=head[ins_h];
|
|
hash_head = (head[ins_h] & 0xffff);
|
|
prev[strstart & w_mask] = head[ins_h];
|
|
head[ins_h] = strstart;
|
|
|
|
// strstart never exceeds WSIZE-MAX_MATCH, so there are
|
|
// always MIN_MATCH bytes ahead.
|
|
} while (--match_length !== 0);
|
|
strstart++;
|
|
} else {
|
|
strstart += match_length;
|
|
match_length = 0;
|
|
ins_h = win[strstart] & 0xff;
|
|
|
|
ins_h = (((ins_h) << hash_shift) ^ (win[strstart + 1] & 0xff)) & hash_mask;
|
|
// If lookahead < MIN_MATCH, ins_h is garbage, but it does
|
|
// not
|
|
// matter since it will be recomputed at next deflate call.
|
|
}
|
|
} else {
|
|
// No match, output a literal byte
|
|
|
|
bflush = _tr_tally(0, win[strstart] & 0xff);
|
|
lookahead--;
|
|
strstart++;
|
|
}
|
|
if (bflush) {
|
|
|
|
flush_block_only(false);
|
|
if (strm.avail_out === 0)
|
|
return NeedMore;
|
|
}
|
|
}
|
|
|
|
flush_block_only(flush == Z_FINISH$1);
|
|
if (strm.avail_out === 0) {
|
|
if (flush == Z_FINISH$1)
|
|
return FinishStarted;
|
|
else
|
|
return NeedMore;
|
|
}
|
|
return flush == Z_FINISH$1 ? FinishDone : BlockDone;
|
|
}
|
|
|
|
// Same as above, but achieves better compression. We use a lazy
|
|
// evaluation for matches: a match is finally adopted only if there is
|
|
// no better match at the next win position.
|
|
function deflate_slow(flush) {
|
|
// short hash_head = 0; // head of hash chain
|
|
let hash_head = 0; // head of hash chain
|
|
let bflush; // set if current block must be flushed
|
|
let max_insert;
|
|
|
|
// Process the input block.
|
|
// eslint-disable-next-line no-constant-condition
|
|
while (true) {
|
|
// Make sure that we always have enough lookahead, except
|
|
// at the end of the input file. We need MAX_MATCH bytes
|
|
// for the next match, plus MIN_MATCH bytes to insert the
|
|
// string following the next match.
|
|
|
|
if (lookahead < MIN_LOOKAHEAD) {
|
|
fill_window();
|
|
if (lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH$1) {
|
|
return NeedMore;
|
|
}
|
|
if (lookahead === 0)
|
|
break; // flush the current block
|
|
}
|
|
|
|
// Insert the string win[strstart .. strstart+2] in the
|
|
// dictionary, and set hash_head to the head of the hash chain:
|
|
|
|
if (lookahead >= MIN_MATCH) {
|
|
ins_h = (((ins_h) << hash_shift) ^ (win[(strstart) + (MIN_MATCH - 1)] & 0xff)) & hash_mask;
|
|
// prev[strstart&w_mask]=hash_head=head[ins_h];
|
|
hash_head = (head[ins_h] & 0xffff);
|
|
prev[strstart & w_mask] = head[ins_h];
|
|
head[ins_h] = strstart;
|
|
}
|
|
|
|
// Find the longest match, discarding those <= prev_length.
|
|
prev_length = match_length;
|
|
prev_match = match_start;
|
|
match_length = MIN_MATCH - 1;
|
|
|
|
if (hash_head !== 0 && prev_length < max_lazy_match && ((strstart - hash_head) & 0xffff) <= w_size - MIN_LOOKAHEAD) {
|
|
// To simplify the code, we prevent matches with the string
|
|
// of win index 0 (in particular we have to avoid a match
|
|
// of the string with itself at the start of the input file).
|
|
|
|
if (strategy != Z_HUFFMAN_ONLY) {
|
|
match_length = longest_match(hash_head);
|
|
}
|
|
// longest_match() sets match_start
|
|
|
|
if (match_length <= 5 && (strategy == Z_FILTERED || (match_length == MIN_MATCH && strstart - match_start > 4096))) {
|
|
|
|
// If prev_match is also MIN_MATCH, match_start is garbage
|
|
// but we will ignore the current match anyway.
|
|
match_length = MIN_MATCH - 1;
|
|
}
|
|
}
|
|
|
|
// If there was a match at the previous step and the current
|
|
// match is not better, output the previous match:
|
|
if (prev_length >= MIN_MATCH && match_length <= prev_length) {
|
|
max_insert = strstart + lookahead - MIN_MATCH;
|
|
// Do not insert strings in hash table beyond this.
|
|
|
|
// check_match(strstart-1, prev_match, prev_length);
|
|
|
|
bflush = _tr_tally(strstart - 1 - prev_match, prev_length - MIN_MATCH);
|
|
|
|
// Insert in hash table all strings up to the end of the match.
|
|
// strstart-1 and strstart are already inserted. If there is not
|
|
// enough lookahead, the last two strings are not inserted in
|
|
// the hash table.
|
|
lookahead -= prev_length - 1;
|
|
prev_length -= 2;
|
|
do {
|
|
if (++strstart <= max_insert) {
|
|
ins_h = (((ins_h) << hash_shift) ^ (win[(strstart) + (MIN_MATCH - 1)] & 0xff)) & hash_mask;
|
|
// prev[strstart&w_mask]=hash_head=head[ins_h];
|
|
hash_head = (head[ins_h] & 0xffff);
|
|
prev[strstart & w_mask] = head[ins_h];
|
|
head[ins_h] = strstart;
|
|
}
|
|
} while (--prev_length !== 0);
|
|
match_available = 0;
|
|
match_length = MIN_MATCH - 1;
|
|
strstart++;
|
|
|
|
if (bflush) {
|
|
flush_block_only(false);
|
|
if (strm.avail_out === 0)
|
|
return NeedMore;
|
|
}
|
|
} else if (match_available !== 0) {
|
|
|
|
// If there was no match at the previous position, output a
|
|
// single literal. If there was a match but the current match
|
|
// is longer, truncate the previous match to a single literal.
|
|
|
|
bflush = _tr_tally(0, win[strstart - 1] & 0xff);
|
|
|
|
if (bflush) {
|
|
flush_block_only(false);
|
|
}
|
|
strstart++;
|
|
lookahead--;
|
|
if (strm.avail_out === 0)
|
|
return NeedMore;
|
|
} else {
|
|
// There is no previous match to compare with, wait for
|
|
// the next step to decide.
|
|
|
|
match_available = 1;
|
|
strstart++;
|
|
lookahead--;
|
|
}
|
|
}
|
|
|
|
if (match_available !== 0) {
|
|
bflush = _tr_tally(0, win[strstart - 1] & 0xff);
|
|
match_available = 0;
|
|
}
|
|
flush_block_only(flush == Z_FINISH$1);
|
|
|
|
if (strm.avail_out === 0) {
|
|
if (flush == Z_FINISH$1)
|
|
return FinishStarted;
|
|
else
|
|
return NeedMore;
|
|
}
|
|
|
|
return flush == Z_FINISH$1 ? FinishDone : BlockDone;
|
|
}
|
|
|
|
function deflateReset(strm) {
|
|
strm.total_in = strm.total_out = 0;
|
|
strm.msg = null; //
|
|
|
|
that.pending = 0;
|
|
that.pending_out = 0;
|
|
|
|
status = BUSY_STATE;
|
|
|
|
last_flush = Z_NO_FLUSH$1;
|
|
|
|
tr_init();
|
|
lm_init();
|
|
return Z_OK$1;
|
|
}
|
|
|
|
that.deflateInit = function (strm, _level, bits, _method, memLevel, _strategy) {
|
|
if (!_method)
|
|
_method = Z_DEFLATED$1;
|
|
if (!memLevel)
|
|
memLevel = DEF_MEM_LEVEL;
|
|
if (!_strategy)
|
|
_strategy = Z_DEFAULT_STRATEGY;
|
|
|
|
// byte[] my_version=ZLIB_VERSION;
|
|
|
|
//
|
|
// if (!version || version[0] != my_version[0]
|
|
// || stream_size != sizeof(z_stream)) {
|
|
// return Z_VERSION_ERROR;
|
|
// }
|
|
|
|
strm.msg = null;
|
|
|
|
if (_level == Z_DEFAULT_COMPRESSION)
|
|
_level = 6;
|
|
|
|
if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || _method != Z_DEFLATED$1 || bits < 9 || bits > 15 || _level < 0 || _level > 9 || _strategy < 0
|
|
|| _strategy > Z_HUFFMAN_ONLY) {
|
|
return Z_STREAM_ERROR$1;
|
|
}
|
|
|
|
strm.dstate = that;
|
|
|
|
w_bits = bits;
|
|
w_size = 1 << w_bits;
|
|
w_mask = w_size - 1;
|
|
|
|
hash_bits = memLevel + 7;
|
|
hash_size = 1 << hash_bits;
|
|
hash_mask = hash_size - 1;
|
|
hash_shift = Math.floor((hash_bits + MIN_MATCH - 1) / MIN_MATCH);
|
|
|
|
win = new Uint8Array(w_size * 2);
|
|
prev = [];
|
|
head = [];
|
|
|
|
lit_bufsize = 1 << (memLevel + 6); // 16K elements by default
|
|
|
|
that.pending_buf = new Uint8Array(lit_bufsize * 4);
|
|
pending_buf_size = lit_bufsize * 4;
|
|
|
|
that.dist_buf = new Uint16Array(lit_bufsize);
|
|
that.lc_buf = new Uint8Array(lit_bufsize);
|
|
|
|
level = _level;
|
|
|
|
strategy = _strategy;
|
|
|
|
return deflateReset(strm);
|
|
};
|
|
|
|
that.deflateEnd = function () {
|
|
if (status != INIT_STATE && status != BUSY_STATE && status != FINISH_STATE) {
|
|
return Z_STREAM_ERROR$1;
|
|
}
|
|
// Deallocate in reverse order of allocations:
|
|
that.lc_buf = null;
|
|
that.dist_buf = null;
|
|
that.pending_buf = null;
|
|
head = null;
|
|
prev = null;
|
|
win = null;
|
|
// free
|
|
that.dstate = null;
|
|
return status == BUSY_STATE ? Z_DATA_ERROR$1 : Z_OK$1;
|
|
};
|
|
|
|
that.deflateParams = function (strm, _level, _strategy) {
|
|
let err = Z_OK$1;
|
|
|
|
if (_level == Z_DEFAULT_COMPRESSION) {
|
|
_level = 6;
|
|
}
|
|
if (_level < 0 || _level > 9 || _strategy < 0 || _strategy > Z_HUFFMAN_ONLY) {
|
|
return Z_STREAM_ERROR$1;
|
|
}
|
|
|
|
if (config_table[level].func != config_table[_level].func && strm.total_in !== 0) {
|
|
// Flush the last buffer:
|
|
err = strm.deflate(Z_PARTIAL_FLUSH);
|
|
}
|
|
|
|
if (level != _level) {
|
|
level = _level;
|
|
max_lazy_match = config_table[level].max_lazy;
|
|
good_match = config_table[level].good_length;
|
|
nice_match = config_table[level].nice_length;
|
|
max_chain_length = config_table[level].max_chain;
|
|
}
|
|
strategy = _strategy;
|
|
return err;
|
|
};
|
|
|
|
that.deflateSetDictionary = function (_strm, dictionary, dictLength) {
|
|
let length = dictLength;
|
|
let n, index = 0;
|
|
|
|
if (!dictionary || status != INIT_STATE)
|
|
return Z_STREAM_ERROR$1;
|
|
|
|
if (length < MIN_MATCH)
|
|
return Z_OK$1;
|
|
if (length > w_size - MIN_LOOKAHEAD) {
|
|
length = w_size - MIN_LOOKAHEAD;
|
|
index = dictLength - length; // use the tail of the dictionary
|
|
}
|
|
win.set(dictionary.subarray(index, index + length), 0);
|
|
|
|
strstart = length;
|
|
block_start = length;
|
|
|
|
// Insert all strings in the hash table (except for the last two bytes).
|
|
// s->lookahead stays null, so s->ins_h will be recomputed at the next
|
|
// call of fill_window.
|
|
|
|
ins_h = win[0] & 0xff;
|
|
ins_h = (((ins_h) << hash_shift) ^ (win[1] & 0xff)) & hash_mask;
|
|
|
|
for (n = 0; n <= length - MIN_MATCH; n++) {
|
|
ins_h = (((ins_h) << hash_shift) ^ (win[(n) + (MIN_MATCH - 1)] & 0xff)) & hash_mask;
|
|
prev[n & w_mask] = head[ins_h];
|
|
head[ins_h] = n;
|
|
}
|
|
return Z_OK$1;
|
|
};
|
|
|
|
that.deflate = function (_strm, flush) {
|
|
let i, header, level_flags, old_flush, bstate;
|
|
|
|
if (flush > Z_FINISH$1 || flush < 0) {
|
|
return Z_STREAM_ERROR$1;
|
|
}
|
|
|
|
if (!_strm.next_out || (!_strm.next_in && _strm.avail_in !== 0) || (status == FINISH_STATE && flush != Z_FINISH$1)) {
|
|
_strm.msg = z_errmsg[Z_NEED_DICT$1 - (Z_STREAM_ERROR$1)];
|
|
return Z_STREAM_ERROR$1;
|
|
}
|
|
if (_strm.avail_out === 0) {
|
|
_strm.msg = z_errmsg[Z_NEED_DICT$1 - (Z_BUF_ERROR$1)];
|
|
return Z_BUF_ERROR$1;
|
|
}
|
|
|
|
strm = _strm; // just in case
|
|
old_flush = last_flush;
|
|
last_flush = flush;
|
|
|
|
// Write the zlib header
|
|
if (status == INIT_STATE) {
|
|
header = (Z_DEFLATED$1 + ((w_bits - 8) << 4)) << 8;
|
|
level_flags = ((level - 1) & 0xff) >> 1;
|
|
|
|
if (level_flags > 3)
|
|
level_flags = 3;
|
|
header |= (level_flags << 6);
|
|
if (strstart !== 0)
|
|
header |= PRESET_DICT$1;
|
|
header += 31 - (header % 31);
|
|
|
|
status = BUSY_STATE;
|
|
putShortMSB(header);
|
|
}
|
|
|
|
// Flush as much pending output as possible
|
|
if (that.pending !== 0) {
|
|
strm.flush_pending();
|
|
if (strm.avail_out === 0) {
|
|
// console.log(" avail_out==0");
|
|
// Since avail_out is 0, deflate will be called again with
|
|
// more output space, but possibly with both pending and
|
|
// avail_in equal to zero. There won't be anything to do,
|
|
// but this is not an error situation so make sure we
|
|
// return OK instead of BUF_ERROR at next call of deflate:
|
|
last_flush = -1;
|
|
return Z_OK$1;
|
|
}
|
|
|
|
// Make sure there is something to do and avoid duplicate
|
|
// consecutive
|
|
// flushes. For repeated and useless calls with Z_FINISH, we keep
|
|
// returning Z_STREAM_END instead of Z_BUFF_ERROR.
|
|
} else if (strm.avail_in === 0 && flush <= old_flush && flush != Z_FINISH$1) {
|
|
strm.msg = z_errmsg[Z_NEED_DICT$1 - (Z_BUF_ERROR$1)];
|
|
return Z_BUF_ERROR$1;
|
|
}
|
|
|
|
// User must not provide more input after the first FINISH:
|
|
if (status == FINISH_STATE && strm.avail_in !== 0) {
|
|
_strm.msg = z_errmsg[Z_NEED_DICT$1 - (Z_BUF_ERROR$1)];
|
|
return Z_BUF_ERROR$1;
|
|
}
|
|
|
|
// Start a new block or continue the current one.
|
|
if (strm.avail_in !== 0 || lookahead !== 0 || (flush != Z_NO_FLUSH$1 && status != FINISH_STATE)) {
|
|
bstate = -1;
|
|
switch (config_table[level].func) {
|
|
case STORED$1:
|
|
bstate = deflate_stored(flush);
|
|
break;
|
|
case FAST:
|
|
bstate = deflate_fast(flush);
|
|
break;
|
|
case SLOW:
|
|
bstate = deflate_slow(flush);
|
|
break;
|
|
}
|
|
|
|
if (bstate == FinishStarted || bstate == FinishDone) {
|
|
status = FINISH_STATE;
|
|
}
|
|
if (bstate == NeedMore || bstate == FinishStarted) {
|
|
if (strm.avail_out === 0) {
|
|
last_flush = -1; // avoid BUF_ERROR next call, see above
|
|
}
|
|
return Z_OK$1;
|
|
// If flush != Z_NO_FLUSH && avail_out === 0, the next call
|
|
// of deflate should use the same flush parameter to make sure
|
|
// that the flush is complete. So we don't have to output an
|
|
// empty block here, this will be done at next call. This also
|
|
// ensures that for a very small output buffer, we emit at most
|
|
// one empty block.
|
|
}
|
|
|
|
if (bstate == BlockDone) {
|
|
if (flush == Z_PARTIAL_FLUSH) {
|
|
_tr_align();
|
|
} else { // FULL_FLUSH or SYNC_FLUSH
|
|
_tr_stored_block(0, 0, false);
|
|
// For a full flush, this empty block will be recognized
|
|
// as a special marker by inflate_sync().
|
|
if (flush == Z_FULL_FLUSH) {
|
|
// state.head[s.hash_size-1]=0;
|
|
for (i = 0; i < hash_size/*-1*/; i++)
|
|
// forget history
|
|
head[i] = 0;
|
|
}
|
|
}
|
|
strm.flush_pending();
|
|
if (strm.avail_out === 0) {
|
|
last_flush = -1; // avoid BUF_ERROR at next call, see above
|
|
return Z_OK$1;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (flush != Z_FINISH$1)
|
|
return Z_OK$1;
|
|
return Z_STREAM_END$1;
|
|
};
|
|
}
|
|
|
|
// ZStream
|
|
|
|
function ZStream$1() {
|
|
const that = this;
|
|
that.next_in_index = 0;
|
|
that.next_out_index = 0;
|
|
// that.next_in; // next input byte
|
|
that.avail_in = 0; // number of bytes available at next_in
|
|
that.total_in = 0; // total nb of input bytes read so far
|
|
// that.next_out; // next output byte should be put there
|
|
that.avail_out = 0; // remaining free space at next_out
|
|
that.total_out = 0; // total nb of bytes output so far
|
|
// that.msg;
|
|
// that.dstate;
|
|
}
|
|
|
|
ZStream$1.prototype = {
|
|
deflateInit(level, bits) {
|
|
const that = this;
|
|
that.dstate = new Deflate();
|
|
if (!bits)
|
|
bits = MAX_BITS$1;
|
|
return that.dstate.deflateInit(that, level, bits);
|
|
},
|
|
|
|
deflate(flush) {
|
|
const that = this;
|
|
if (!that.dstate) {
|
|
return Z_STREAM_ERROR$1;
|
|
}
|
|
return that.dstate.deflate(that, flush);
|
|
},
|
|
|
|
deflateEnd() {
|
|
const that = this;
|
|
if (!that.dstate)
|
|
return Z_STREAM_ERROR$1;
|
|
const ret = that.dstate.deflateEnd();
|
|
that.dstate = null;
|
|
return ret;
|
|
},
|
|
|
|
deflateParams(level, strategy) {
|
|
const that = this;
|
|
if (!that.dstate)
|
|
return Z_STREAM_ERROR$1;
|
|
return that.dstate.deflateParams(that, level, strategy);
|
|
},
|
|
|
|
deflateSetDictionary(dictionary, dictLength) {
|
|
const that = this;
|
|
if (!that.dstate)
|
|
return Z_STREAM_ERROR$1;
|
|
return that.dstate.deflateSetDictionary(that, dictionary, dictLength);
|
|
},
|
|
|
|
// Read a new buffer from the current input stream, update the
|
|
// total number of bytes read. All deflate() input goes through
|
|
// this function so some applications may wish to modify it to avoid
|
|
// allocating a large strm->next_in buffer and copying from it.
|
|
// (See also flush_pending()).
|
|
read_buf(buf, start, size) {
|
|
const that = this;
|
|
let len = that.avail_in;
|
|
if (len > size)
|
|
len = size;
|
|
if (len === 0)
|
|
return 0;
|
|
that.avail_in -= len;
|
|
buf.set(that.next_in.subarray(that.next_in_index, that.next_in_index + len), start);
|
|
that.next_in_index += len;
|
|
that.total_in += len;
|
|
return len;
|
|
},
|
|
|
|
// Flush as much pending output as possible. All deflate() output goes
|
|
// through this function so some applications may wish to modify it
|
|
// to avoid allocating a large strm->next_out buffer and copying into it.
|
|
// (See also read_buf()).
|
|
flush_pending() {
|
|
const that = this;
|
|
let len = that.dstate.pending;
|
|
|
|
if (len > that.avail_out)
|
|
len = that.avail_out;
|
|
if (len === 0)
|
|
return;
|
|
|
|
// if (that.dstate.pending_buf.length <= that.dstate.pending_out || that.next_out.length <= that.next_out_index
|
|
// || that.dstate.pending_buf.length < (that.dstate.pending_out + len) || that.next_out.length < (that.next_out_index +
|
|
// len)) {
|
|
// console.log(that.dstate.pending_buf.length + ", " + that.dstate.pending_out + ", " + that.next_out.length + ", " +
|
|
// that.next_out_index + ", " + len);
|
|
// console.log("avail_out=" + that.avail_out);
|
|
// }
|
|
|
|
that.next_out.set(that.dstate.pending_buf.subarray(that.dstate.pending_out, that.dstate.pending_out + len), that.next_out_index);
|
|
|
|
that.next_out_index += len;
|
|
that.dstate.pending_out += len;
|
|
that.total_out += len;
|
|
that.avail_out -= len;
|
|
that.dstate.pending -= len;
|
|
if (that.dstate.pending === 0) {
|
|
that.dstate.pending_out = 0;
|
|
}
|
|
}
|
|
};
|
|
|
|
// Deflate
|
|
|
|
function ZipDeflate(options) {
|
|
const that = this;
|
|
const z = new ZStream$1();
|
|
const bufsize = getMaximumCompressedSize(options && options.chunkSize ? options.chunkSize : 64 * 1024);
|
|
const flush = Z_NO_FLUSH$1;
|
|
const buf = new Uint8Array(bufsize);
|
|
let level = options ? options.level : Z_DEFAULT_COMPRESSION;
|
|
if (typeof level == "undefined")
|
|
level = Z_DEFAULT_COMPRESSION;
|
|
z.deflateInit(level);
|
|
z.next_out = buf;
|
|
|
|
that.append = function (data, onprogress) {
|
|
let err, array, lastIndex = 0, bufferIndex = 0, bufferSize = 0;
|
|
const buffers = [];
|
|
if (!data.length)
|
|
return;
|
|
z.next_in_index = 0;
|
|
z.next_in = data;
|
|
z.avail_in = data.length;
|
|
do {
|
|
z.next_out_index = 0;
|
|
z.avail_out = bufsize;
|
|
err = z.deflate(flush);
|
|
if (err != Z_OK$1)
|
|
throw new Error("deflating: " + z.msg);
|
|
if (z.next_out_index)
|
|
if (z.next_out_index == bufsize)
|
|
buffers.push(new Uint8Array(buf));
|
|
else
|
|
buffers.push(buf.subarray(0, z.next_out_index));
|
|
bufferSize += z.next_out_index;
|
|
if (onprogress && z.next_in_index > 0 && z.next_in_index != lastIndex) {
|
|
onprogress(z.next_in_index);
|
|
lastIndex = z.next_in_index;
|
|
}
|
|
} while (z.avail_in > 0 || z.avail_out === 0);
|
|
if (buffers.length > 1) {
|
|
array = new Uint8Array(bufferSize);
|
|
buffers.forEach(function (chunk) {
|
|
array.set(chunk, bufferIndex);
|
|
bufferIndex += chunk.length;
|
|
});
|
|
} else {
|
|
array = buffers[0] ? new Uint8Array(buffers[0]) : new Uint8Array();
|
|
}
|
|
return array;
|
|
};
|
|
that.flush = function () {
|
|
let err, array, bufferIndex = 0, bufferSize = 0;
|
|
const buffers = [];
|
|
do {
|
|
z.next_out_index = 0;
|
|
z.avail_out = bufsize;
|
|
err = z.deflate(Z_FINISH$1);
|
|
if (err != Z_STREAM_END$1 && err != Z_OK$1)
|
|
throw new Error("deflating: " + z.msg);
|
|
if (bufsize - z.avail_out > 0)
|
|
buffers.push(buf.slice(0, z.next_out_index));
|
|
bufferSize += z.next_out_index;
|
|
} while (z.avail_in > 0 || z.avail_out === 0);
|
|
z.deflateEnd();
|
|
array = new Uint8Array(bufferSize);
|
|
buffers.forEach(function (chunk) {
|
|
array.set(chunk, bufferIndex);
|
|
bufferIndex += chunk.length;
|
|
});
|
|
return array;
|
|
};
|
|
}
|
|
|
|
function getMaximumCompressedSize(uncompressedSize) {
|
|
return uncompressedSize + (5 * (Math.floor(uncompressedSize / 16383) + 1));
|
|
}
|
|
|
|
/*
|
|
Copyright (c) 2022 Gildas Lormeau. All rights reserved.
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
modification, are permitted provided that the following conditions are met:
|
|
|
|
1. Redistributions of source code must retain the above copyright notice,
|
|
this list of conditions and the following disclaimer.
|
|
|
|
2. Redistributions in binary form must reproduce the above copyright
|
|
notice, this list of conditions and the following disclaimer in
|
|
the documentation and/or other materials provided with the distribution.
|
|
|
|
3. The names of the authors may not be used to endorse or promote products
|
|
derived from this software without specific prior written permission.
|
|
|
|
THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
|
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
|
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
|
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
|
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
/*
|
|
* This program is based on JZlib 1.0.2 ymnk, JCraft,Inc.
|
|
* JZlib is based on zlib-1.1.3, so all credit should go authors
|
|
* Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
|
|
* and contributors of zlib.
|
|
*/
|
|
|
|
// deno-lint-ignore-file no-this-alias prefer-const
|
|
|
|
// Global
|
|
|
|
const MAX_BITS = 15;
|
|
|
|
const Z_OK = 0;
|
|
const Z_STREAM_END = 1;
|
|
const Z_NEED_DICT = 2;
|
|
const Z_STREAM_ERROR = -2;
|
|
const Z_DATA_ERROR = -3;
|
|
const Z_MEM_ERROR = -4;
|
|
const Z_BUF_ERROR = -5;
|
|
|
|
const inflate_mask = [0x00000000, 0x00000001, 0x00000003, 0x00000007, 0x0000000f, 0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff, 0x000001ff, 0x000003ff,
|
|
0x000007ff, 0x00000fff, 0x00001fff, 0x00003fff, 0x00007fff, 0x0000ffff];
|
|
|
|
const MANY = 1440;
|
|
|
|
// JZlib version : "1.0.2"
|
|
const Z_NO_FLUSH = 0;
|
|
const Z_FINISH = 4;
|
|
|
|
// InfTree
|
|
const fixed_bl = 9;
|
|
const fixed_bd = 5;
|
|
|
|
const fixed_tl = [96, 7, 256, 0, 8, 80, 0, 8, 16, 84, 8, 115, 82, 7, 31, 0, 8, 112, 0, 8, 48, 0, 9, 192, 80, 7, 10, 0, 8, 96, 0, 8, 32, 0, 9, 160, 0, 8, 0,
|
|
0, 8, 128, 0, 8, 64, 0, 9, 224, 80, 7, 6, 0, 8, 88, 0, 8, 24, 0, 9, 144, 83, 7, 59, 0, 8, 120, 0, 8, 56, 0, 9, 208, 81, 7, 17, 0, 8, 104, 0, 8, 40,
|
|
0, 9, 176, 0, 8, 8, 0, 8, 136, 0, 8, 72, 0, 9, 240, 80, 7, 4, 0, 8, 84, 0, 8, 20, 85, 8, 227, 83, 7, 43, 0, 8, 116, 0, 8, 52, 0, 9, 200, 81, 7, 13,
|
|
0, 8, 100, 0, 8, 36, 0, 9, 168, 0, 8, 4, 0, 8, 132, 0, 8, 68, 0, 9, 232, 80, 7, 8, 0, 8, 92, 0, 8, 28, 0, 9, 152, 84, 7, 83, 0, 8, 124, 0, 8, 60,
|
|
0, 9, 216, 82, 7, 23, 0, 8, 108, 0, 8, 44, 0, 9, 184, 0, 8, 12, 0, 8, 140, 0, 8, 76, 0, 9, 248, 80, 7, 3, 0, 8, 82, 0, 8, 18, 85, 8, 163, 83, 7,
|
|
35, 0, 8, 114, 0, 8, 50, 0, 9, 196, 81, 7, 11, 0, 8, 98, 0, 8, 34, 0, 9, 164, 0, 8, 2, 0, 8, 130, 0, 8, 66, 0, 9, 228, 80, 7, 7, 0, 8, 90, 0, 8,
|
|
26, 0, 9, 148, 84, 7, 67, 0, 8, 122, 0, 8, 58, 0, 9, 212, 82, 7, 19, 0, 8, 106, 0, 8, 42, 0, 9, 180, 0, 8, 10, 0, 8, 138, 0, 8, 74, 0, 9, 244, 80,
|
|
7, 5, 0, 8, 86, 0, 8, 22, 192, 8, 0, 83, 7, 51, 0, 8, 118, 0, 8, 54, 0, 9, 204, 81, 7, 15, 0, 8, 102, 0, 8, 38, 0, 9, 172, 0, 8, 6, 0, 8, 134, 0,
|
|
8, 70, 0, 9, 236, 80, 7, 9, 0, 8, 94, 0, 8, 30, 0, 9, 156, 84, 7, 99, 0, 8, 126, 0, 8, 62, 0, 9, 220, 82, 7, 27, 0, 8, 110, 0, 8, 46, 0, 9, 188, 0,
|
|
8, 14, 0, 8, 142, 0, 8, 78, 0, 9, 252, 96, 7, 256, 0, 8, 81, 0, 8, 17, 85, 8, 131, 82, 7, 31, 0, 8, 113, 0, 8, 49, 0, 9, 194, 80, 7, 10, 0, 8, 97,
|
|
0, 8, 33, 0, 9, 162, 0, 8, 1, 0, 8, 129, 0, 8, 65, 0, 9, 226, 80, 7, 6, 0, 8, 89, 0, 8, 25, 0, 9, 146, 83, 7, 59, 0, 8, 121, 0, 8, 57, 0, 9, 210,
|
|
81, 7, 17, 0, 8, 105, 0, 8, 41, 0, 9, 178, 0, 8, 9, 0, 8, 137, 0, 8, 73, 0, 9, 242, 80, 7, 4, 0, 8, 85, 0, 8, 21, 80, 8, 258, 83, 7, 43, 0, 8, 117,
|
|
0, 8, 53, 0, 9, 202, 81, 7, 13, 0, 8, 101, 0, 8, 37, 0, 9, 170, 0, 8, 5, 0, 8, 133, 0, 8, 69, 0, 9, 234, 80, 7, 8, 0, 8, 93, 0, 8, 29, 0, 9, 154,
|
|
84, 7, 83, 0, 8, 125, 0, 8, 61, 0, 9, 218, 82, 7, 23, 0, 8, 109, 0, 8, 45, 0, 9, 186, 0, 8, 13, 0, 8, 141, 0, 8, 77, 0, 9, 250, 80, 7, 3, 0, 8, 83,
|
|
0, 8, 19, 85, 8, 195, 83, 7, 35, 0, 8, 115, 0, 8, 51, 0, 9, 198, 81, 7, 11, 0, 8, 99, 0, 8, 35, 0, 9, 166, 0, 8, 3, 0, 8, 131, 0, 8, 67, 0, 9, 230,
|
|
80, 7, 7, 0, 8, 91, 0, 8, 27, 0, 9, 150, 84, 7, 67, 0, 8, 123, 0, 8, 59, 0, 9, 214, 82, 7, 19, 0, 8, 107, 0, 8, 43, 0, 9, 182, 0, 8, 11, 0, 8, 139,
|
|
0, 8, 75, 0, 9, 246, 80, 7, 5, 0, 8, 87, 0, 8, 23, 192, 8, 0, 83, 7, 51, 0, 8, 119, 0, 8, 55, 0, 9, 206, 81, 7, 15, 0, 8, 103, 0, 8, 39, 0, 9, 174,
|
|
0, 8, 7, 0, 8, 135, 0, 8, 71, 0, 9, 238, 80, 7, 9, 0, 8, 95, 0, 8, 31, 0, 9, 158, 84, 7, 99, 0, 8, 127, 0, 8, 63, 0, 9, 222, 82, 7, 27, 0, 8, 111,
|
|
0, 8, 47, 0, 9, 190, 0, 8, 15, 0, 8, 143, 0, 8, 79, 0, 9, 254, 96, 7, 256, 0, 8, 80, 0, 8, 16, 84, 8, 115, 82, 7, 31, 0, 8, 112, 0, 8, 48, 0, 9,
|
|
193, 80, 7, 10, 0, 8, 96, 0, 8, 32, 0, 9, 161, 0, 8, 0, 0, 8, 128, 0, 8, 64, 0, 9, 225, 80, 7, 6, 0, 8, 88, 0, 8, 24, 0, 9, 145, 83, 7, 59, 0, 8,
|
|
120, 0, 8, 56, 0, 9, 209, 81, 7, 17, 0, 8, 104, 0, 8, 40, 0, 9, 177, 0, 8, 8, 0, 8, 136, 0, 8, 72, 0, 9, 241, 80, 7, 4, 0, 8, 84, 0, 8, 20, 85, 8,
|
|
227, 83, 7, 43, 0, 8, 116, 0, 8, 52, 0, 9, 201, 81, 7, 13, 0, 8, 100, 0, 8, 36, 0, 9, 169, 0, 8, 4, 0, 8, 132, 0, 8, 68, 0, 9, 233, 80, 7, 8, 0, 8,
|
|
92, 0, 8, 28, 0, 9, 153, 84, 7, 83, 0, 8, 124, 0, 8, 60, 0, 9, 217, 82, 7, 23, 0, 8, 108, 0, 8, 44, 0, 9, 185, 0, 8, 12, 0, 8, 140, 0, 8, 76, 0, 9,
|
|
249, 80, 7, 3, 0, 8, 82, 0, 8, 18, 85, 8, 163, 83, 7, 35, 0, 8, 114, 0, 8, 50, 0, 9, 197, 81, 7, 11, 0, 8, 98, 0, 8, 34, 0, 9, 165, 0, 8, 2, 0, 8,
|
|
130, 0, 8, 66, 0, 9, 229, 80, 7, 7, 0, 8, 90, 0, 8, 26, 0, 9, 149, 84, 7, 67, 0, 8, 122, 0, 8, 58, 0, 9, 213, 82, 7, 19, 0, 8, 106, 0, 8, 42, 0, 9,
|
|
181, 0, 8, 10, 0, 8, 138, 0, 8, 74, 0, 9, 245, 80, 7, 5, 0, 8, 86, 0, 8, 22, 192, 8, 0, 83, 7, 51, 0, 8, 118, 0, 8, 54, 0, 9, 205, 81, 7, 15, 0, 8,
|
|
102, 0, 8, 38, 0, 9, 173, 0, 8, 6, 0, 8, 134, 0, 8, 70, 0, 9, 237, 80, 7, 9, 0, 8, 94, 0, 8, 30, 0, 9, 157, 84, 7, 99, 0, 8, 126, 0, 8, 62, 0, 9,
|
|
221, 82, 7, 27, 0, 8, 110, 0, 8, 46, 0, 9, 189, 0, 8, 14, 0, 8, 142, 0, 8, 78, 0, 9, 253, 96, 7, 256, 0, 8, 81, 0, 8, 17, 85, 8, 131, 82, 7, 31, 0,
|
|
8, 113, 0, 8, 49, 0, 9, 195, 80, 7, 10, 0, 8, 97, 0, 8, 33, 0, 9, 163, 0, 8, 1, 0, 8, 129, 0, 8, 65, 0, 9, 227, 80, 7, 6, 0, 8, 89, 0, 8, 25, 0, 9,
|
|
147, 83, 7, 59, 0, 8, 121, 0, 8, 57, 0, 9, 211, 81, 7, 17, 0, 8, 105, 0, 8, 41, 0, 9, 179, 0, 8, 9, 0, 8, 137, 0, 8, 73, 0, 9, 243, 80, 7, 4, 0, 8,
|
|
85, 0, 8, 21, 80, 8, 258, 83, 7, 43, 0, 8, 117, 0, 8, 53, 0, 9, 203, 81, 7, 13, 0, 8, 101, 0, 8, 37, 0, 9, 171, 0, 8, 5, 0, 8, 133, 0, 8, 69, 0, 9,
|
|
235, 80, 7, 8, 0, 8, 93, 0, 8, 29, 0, 9, 155, 84, 7, 83, 0, 8, 125, 0, 8, 61, 0, 9, 219, 82, 7, 23, 0, 8, 109, 0, 8, 45, 0, 9, 187, 0, 8, 13, 0, 8,
|
|
141, 0, 8, 77, 0, 9, 251, 80, 7, 3, 0, 8, 83, 0, 8, 19, 85, 8, 195, 83, 7, 35, 0, 8, 115, 0, 8, 51, 0, 9, 199, 81, 7, 11, 0, 8, 99, 0, 8, 35, 0, 9,
|
|
167, 0, 8, 3, 0, 8, 131, 0, 8, 67, 0, 9, 231, 80, 7, 7, 0, 8, 91, 0, 8, 27, 0, 9, 151, 84, 7, 67, 0, 8, 123, 0, 8, 59, 0, 9, 215, 82, 7, 19, 0, 8,
|
|
107, 0, 8, 43, 0, 9, 183, 0, 8, 11, 0, 8, 139, 0, 8, 75, 0, 9, 247, 80, 7, 5, 0, 8, 87, 0, 8, 23, 192, 8, 0, 83, 7, 51, 0, 8, 119, 0, 8, 55, 0, 9,
|
|
207, 81, 7, 15, 0, 8, 103, 0, 8, 39, 0, 9, 175, 0, 8, 7, 0, 8, 135, 0, 8, 71, 0, 9, 239, 80, 7, 9, 0, 8, 95, 0, 8, 31, 0, 9, 159, 84, 7, 99, 0, 8,
|
|
127, 0, 8, 63, 0, 9, 223, 82, 7, 27, 0, 8, 111, 0, 8, 47, 0, 9, 191, 0, 8, 15, 0, 8, 143, 0, 8, 79, 0, 9, 255];
|
|
const fixed_td = [80, 5, 1, 87, 5, 257, 83, 5, 17, 91, 5, 4097, 81, 5, 5, 89, 5, 1025, 85, 5, 65, 93, 5, 16385, 80, 5, 3, 88, 5, 513, 84, 5, 33, 92, 5,
|
|
8193, 82, 5, 9, 90, 5, 2049, 86, 5, 129, 192, 5, 24577, 80, 5, 2, 87, 5, 385, 83, 5, 25, 91, 5, 6145, 81, 5, 7, 89, 5, 1537, 85, 5, 97, 93, 5,
|
|
24577, 80, 5, 4, 88, 5, 769, 84, 5, 49, 92, 5, 12289, 82, 5, 13, 90, 5, 3073, 86, 5, 193, 192, 5, 24577];
|
|
|
|
// Tables for deflate from PKZIP's appnote.txt.
|
|
const cplens = [ // Copy lengths for literal codes 257..285
|
|
3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0];
|
|
|
|
// see note #13 above about 258
|
|
const cplext = [ // Extra bits for literal codes 257..285
|
|
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 112, 112 // 112==invalid
|
|
];
|
|
|
|
const cpdist = [ // Copy offsets for distance codes 0..29
|
|
1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577];
|
|
|
|
const cpdext = [ // Extra bits for distance codes
|
|
0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13];
|
|
|
|
// If BMAX needs to be larger than 16, then h and x[] should be uLong.
|
|
const BMAX = 15; // maximum bit length of any code
|
|
|
|
function InfTree() {
|
|
const that = this;
|
|
|
|
let hn; // hufts used in space
|
|
let v; // work area for huft_build
|
|
let c; // bit length count table
|
|
let r; // table entry for structure assignment
|
|
let u; // table stack
|
|
let x; // bit offsets, then code stack
|
|
|
|
function huft_build(b, // code lengths in bits (all assumed <=
|
|
// BMAX)
|
|
bindex, n, // number of codes (assumed <= 288)
|
|
s, // number of simple-valued codes (0..s-1)
|
|
d, // list of base values for non-simple codes
|
|
e, // list of extra bits for non-simple codes
|
|
t, // result: starting table
|
|
m, // maximum lookup bits, returns actual
|
|
hp,// space for trees
|
|
hn,// hufts used in space
|
|
v // working area: values in order of bit length
|
|
) {
|
|
// Given a list of code lengths and a maximum table size, make a set of
|
|
// tables to decode that set of codes. Return Z_OK on success,
|
|
// Z_BUF_ERROR
|
|
// if the given code set is incomplete (the tables are still built in
|
|
// this
|
|
// case), Z_DATA_ERROR if the input is invalid (an over-subscribed set
|
|
// of
|
|
// lengths), or Z_MEM_ERROR if not enough memory.
|
|
|
|
let a; // counter for codes of length k
|
|
let f; // i repeats in table every f entries
|
|
let g; // maximum code length
|
|
let h; // table level
|
|
let i; // counter, current code
|
|
let j; // counter
|
|
let k; // number of bits in current code
|
|
let l; // bits per table (returned in m)
|
|
let mask; // (1 << w) - 1, to avoid cc -O bug on HP
|
|
let p; // pointer into c[], b[], or v[]
|
|
let q; // points to current table
|
|
let w; // bits before this table == (l * h)
|
|
let xp; // pointer into x
|
|
let y; // number of dummy codes added
|
|
let z; // number of entries in current table
|
|
|
|
// Generate counts for each bit length
|
|
|
|
p = 0;
|
|
i = n;
|
|
do {
|
|
c[b[bindex + p]]++;
|
|
p++;
|
|
i--; // assume all entries <= BMAX
|
|
} while (i !== 0);
|
|
|
|
if (c[0] == n) { // null input--all zero length codes
|
|
t[0] = -1;
|
|
m[0] = 0;
|
|
return Z_OK;
|
|
}
|
|
|
|
// Find minimum and maximum length, bound *m by those
|
|
l = m[0];
|
|
for (j = 1; j <= BMAX; j++)
|
|
if (c[j] !== 0)
|
|
break;
|
|
k = j; // minimum code length
|
|
if (l < j) {
|
|
l = j;
|
|
}
|
|
for (i = BMAX; i !== 0; i--) {
|
|
if (c[i] !== 0)
|
|
break;
|
|
}
|
|
g = i; // maximum code length
|
|
if (l > i) {
|
|
l = i;
|
|
}
|
|
m[0] = l;
|
|
|
|
// Adjust last length count to fill out codes, if needed
|
|
for (y = 1 << j; j < i; j++, y <<= 1) {
|
|
if ((y -= c[j]) < 0) {
|
|
return Z_DATA_ERROR;
|
|
}
|
|
}
|
|
if ((y -= c[i]) < 0) {
|
|
return Z_DATA_ERROR;
|
|
}
|
|
c[i] += y;
|
|
|
|
// Generate starting offsets into the value table for each length
|
|
x[1] = j = 0;
|
|
p = 1;
|
|
xp = 2;
|
|
while (--i !== 0) { // note that i == g from above
|
|
x[xp] = (j += c[p]);
|
|
xp++;
|
|
p++;
|
|
}
|
|
|
|
// Make a table of values in order of bit lengths
|
|
i = 0;
|
|
p = 0;
|
|
do {
|
|
if ((j = b[bindex + p]) !== 0) {
|
|
v[x[j]++] = i;
|
|
}
|
|
p++;
|
|
} while (++i < n);
|
|
n = x[g]; // set n to length of v
|
|
|
|
// Generate the Huffman codes and for each, make the table entries
|
|
x[0] = i = 0; // first Huffman code is zero
|
|
p = 0; // grab values in bit order
|
|
h = -1; // no tables yet--level -1
|
|
w = -l; // bits decoded == (l * h)
|
|
u[0] = 0; // just to keep compilers happy
|
|
q = 0; // ditto
|
|
z = 0; // ditto
|
|
|
|
// go through the bit lengths (k already is bits in shortest code)
|
|
for (; k <= g; k++) {
|
|
a = c[k];
|
|
while (a-- !== 0) {
|
|
// here i is the Huffman code of length k bits for value *p
|
|
// make tables up to required level
|
|
while (k > w + l) {
|
|
h++;
|
|
w += l; // previous table always l bits
|
|
// compute minimum size table less than or equal to l bits
|
|
z = g - w;
|
|
z = (z > l) ? l : z; // table size upper limit
|
|
if ((f = 1 << (j = k - w)) > a + 1) { // try a k-w bit table
|
|
// too few codes for
|
|
// k-w bit table
|
|
f -= a + 1; // deduct codes from patterns left
|
|
xp = k;
|
|
if (j < z) {
|
|
while (++j < z) { // try smaller tables up to z bits
|
|
if ((f <<= 1) <= c[++xp])
|
|
break; // enough codes to use up j bits
|
|
f -= c[xp]; // else deduct codes from patterns
|
|
}
|
|
}
|
|
}
|
|
z = 1 << j; // table entries for j-bit table
|
|
|
|
// allocate new table
|
|
if (hn[0] + z > MANY) { // (note: doesn't matter for fixed)
|
|
return Z_DATA_ERROR; // overflow of MANY
|
|
}
|
|
u[h] = q = /* hp+ */hn[0]; // DEBUG
|
|
hn[0] += z;
|
|
|
|
// connect to last table, if there is one
|
|
if (h !== 0) {
|
|
x[h] = i; // save pattern for backing up
|
|
r[0] = /* (byte) */j; // bits in this table
|
|
r[1] = /* (byte) */l; // bits to dump before this table
|
|
j = i >>> (w - l);
|
|
r[2] = /* (int) */(q - u[h - 1] - j); // offset to this table
|
|
hp.set(r, (u[h - 1] + j) * 3);
|
|
// to
|
|
// last
|
|
// table
|
|
} else {
|
|
t[0] = q; // first table is returned result
|
|
}
|
|
}
|
|
|
|
// set up table entry in r
|
|
r[1] = /* (byte) */(k - w);
|
|
if (p >= n) {
|
|
r[0] = 128 + 64; // out of values--invalid code
|
|
} else if (v[p] < s) {
|
|
r[0] = /* (byte) */(v[p] < 256 ? 0 : 32 + 64); // 256 is
|
|
// end-of-block
|
|
r[2] = v[p++]; // simple code is just the value
|
|
} else {
|
|
r[0] = /* (byte) */(e[v[p] - s] + 16 + 64); // non-simple--look
|
|
// up in lists
|
|
r[2] = d[v[p++] - s];
|
|
}
|
|
|
|
// fill code-like entries with r
|
|
f = 1 << (k - w);
|
|
for (j = i >>> w; j < z; j += f) {
|
|
hp.set(r, (q + j) * 3);
|
|
}
|
|
|
|
// backwards increment the k-bit code i
|
|
for (j = 1 << (k - 1); (i & j) !== 0; j >>>= 1) {
|
|
i ^= j;
|
|
}
|
|
i ^= j;
|
|
|
|
// backup over finished tables
|
|
mask = (1 << w) - 1; // needed on HP, cc -O bug
|
|
while ((i & mask) != x[h]) {
|
|
h--; // don't need to update q
|
|
w -= l;
|
|
mask = (1 << w) - 1;
|
|
}
|
|
}
|
|
}
|
|
// Return Z_BUF_ERROR if we were given an incomplete table
|
|
return y !== 0 && g != 1 ? Z_BUF_ERROR : Z_OK;
|
|
}
|
|
|
|
function initWorkArea(vsize) {
|
|
let i;
|
|
if (!hn) {
|
|
hn = []; // []; //new Array(1);
|
|
v = []; // new Array(vsize);
|
|
c = new Int32Array(BMAX + 1); // new Array(BMAX + 1);
|
|
r = []; // new Array(3);
|
|
u = new Int32Array(BMAX); // new Array(BMAX);
|
|
x = new Int32Array(BMAX + 1); // new Array(BMAX + 1);
|
|
}
|
|
if (v.length < vsize) {
|
|
v = []; // new Array(vsize);
|
|
}
|
|
for (i = 0; i < vsize; i++) {
|
|
v[i] = 0;
|
|
}
|
|
for (i = 0; i < BMAX + 1; i++) {
|
|
c[i] = 0;
|
|
}
|
|
for (i = 0; i < 3; i++) {
|
|
r[i] = 0;
|
|
}
|
|
// for(int i=0; i<BMAX; i++){u[i]=0;}
|
|
u.set(c.subarray(0, BMAX), 0);
|
|
// for(int i=0; i<BMAX+1; i++){x[i]=0;}
|
|
x.set(c.subarray(0, BMAX + 1), 0);
|
|
}
|
|
|
|
that.inflate_trees_bits = function (c, // 19 code lengths
|
|
bb, // bits tree desired/actual depth
|
|
tb, // bits tree result
|
|
hp, // space for trees
|
|
z // for messages
|
|
) {
|
|
let result;
|
|
initWorkArea(19);
|
|
hn[0] = 0;
|
|
result = huft_build(c, 0, 19, 19, null, null, tb, bb, hp, hn, v);
|
|
|
|
if (result == Z_DATA_ERROR) {
|
|
z.msg = "oversubscribed dynamic bit lengths tree";
|
|
} else if (result == Z_BUF_ERROR || bb[0] === 0) {
|
|
z.msg = "incomplete dynamic bit lengths tree";
|
|
result = Z_DATA_ERROR;
|
|
}
|
|
return result;
|
|
};
|
|
|
|
that.inflate_trees_dynamic = function (nl, // number of literal/length codes
|
|
nd, // number of distance codes
|
|
c, // that many (total) code lengths
|
|
bl, // literal desired/actual bit depth
|
|
bd, // distance desired/actual bit depth
|
|
tl, // literal/length tree result
|
|
td, // distance tree result
|
|
hp, // space for trees
|
|
z // for messages
|
|
) {
|
|
let result;
|
|
|
|
// build literal/length tree
|
|
initWorkArea(288);
|
|
hn[0] = 0;
|
|
result = huft_build(c, 0, nl, 257, cplens, cplext, tl, bl, hp, hn, v);
|
|
if (result != Z_OK || bl[0] === 0) {
|
|
if (result == Z_DATA_ERROR) {
|
|
z.msg = "oversubscribed literal/length tree";
|
|
} else if (result != Z_MEM_ERROR) {
|
|
z.msg = "incomplete literal/length tree";
|
|
result = Z_DATA_ERROR;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
// build distance tree
|
|
initWorkArea(288);
|
|
result = huft_build(c, nl, nd, 0, cpdist, cpdext, td, bd, hp, hn, v);
|
|
|
|
if (result != Z_OK || (bd[0] === 0 && nl > 257)) {
|
|
if (result == Z_DATA_ERROR) {
|
|
z.msg = "oversubscribed distance tree";
|
|
} else if (result == Z_BUF_ERROR) {
|
|
z.msg = "incomplete distance tree";
|
|
result = Z_DATA_ERROR;
|
|
} else if (result != Z_MEM_ERROR) {
|
|
z.msg = "empty distance tree with lengths";
|
|
result = Z_DATA_ERROR;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
return Z_OK;
|
|
};
|
|
|
|
}
|
|
|
|
InfTree.inflate_trees_fixed = function (bl, // literal desired/actual bit depth
|
|
bd, // distance desired/actual bit depth
|
|
tl,// literal/length tree result
|
|
td// distance tree result
|
|
) {
|
|
bl[0] = fixed_bl;
|
|
bd[0] = fixed_bd;
|
|
tl[0] = fixed_tl;
|
|
td[0] = fixed_td;
|
|
return Z_OK;
|
|
};
|
|
|
|
// InfCodes
|
|
|
|
// waiting for "i:"=input,
|
|
// "o:"=output,
|
|
// "x:"=nothing
|
|
const START = 0; // x: set up for LEN
|
|
const LEN = 1; // i: get length/literal/eob next
|
|
const LENEXT = 2; // i: getting length extra (have base)
|
|
const DIST = 3; // i: get distance next
|
|
const DISTEXT = 4;// i: getting distance extra
|
|
const COPY = 5; // o: copying bytes in win, waiting
|
|
// for space
|
|
const LIT = 6; // o: got literal, waiting for output
|
|
// space
|
|
const WASH = 7; // o: got eob, possibly still output
|
|
// waiting
|
|
const END = 8; // x: got eob and all data flushed
|
|
const BADCODE = 9;// x: got error
|
|
|
|
function InfCodes() {
|
|
const that = this;
|
|
|
|
let mode; // current inflate_codes mode
|
|
|
|
// mode dependent information
|
|
let len = 0;
|
|
|
|
let tree; // pointer into tree
|
|
let tree_index = 0;
|
|
let need = 0; // bits needed
|
|
|
|
let lit = 0;
|
|
|
|
// if EXT or COPY, where and how much
|
|
let get = 0; // bits to get for extra
|
|
let dist = 0; // distance back to copy from
|
|
|
|
let lbits = 0; // ltree bits decoded per branch
|
|
let dbits = 0; // dtree bits decoder per branch
|
|
let ltree; // literal/length/eob tree
|
|
let ltree_index = 0; // literal/length/eob tree
|
|
let dtree; // distance tree
|
|
let dtree_index = 0; // distance tree
|
|
|
|
// Called with number of bytes left to write in win at least 258
|
|
// (the maximum string length) and number of input bytes available
|
|
// at least ten. The ten bytes are six bytes for the longest length/
|
|
// distance pair plus four bytes for overloading the bit buffer.
|
|
|
|
function inflate_fast(bl, bd, tl, tl_index, td, td_index, s, z) {
|
|
let t; // temporary pointer
|
|
let tp; // temporary pointer
|
|
let tp_index; // temporary pointer
|
|
let e; // extra bits or operation
|
|
let b; // bit buffer
|
|
let k; // bits in bit buffer
|
|
let p; // input data pointer
|
|
let n; // bytes available there
|
|
let q; // output win write pointer
|
|
let m; // bytes to end of win or read pointer
|
|
let ml; // mask for literal/length tree
|
|
let md; // mask for distance tree
|
|
let c; // bytes to copy
|
|
let d; // distance back to copy from
|
|
let r; // copy source pointer
|
|
|
|
let tp_index_t_3; // (tp_index+t)*3
|
|
|
|
// load input, output, bit values
|
|
p = z.next_in_index;
|
|
n = z.avail_in;
|
|
b = s.bitb;
|
|
k = s.bitk;
|
|
q = s.write;
|
|
m = q < s.read ? s.read - q - 1 : s.end - q;
|
|
|
|
// initialize masks
|
|
ml = inflate_mask[bl];
|
|
md = inflate_mask[bd];
|
|
|
|
// do until not enough input or output space for fast loop
|
|
do { // assume called with m >= 258 && n >= 10
|
|
// get literal/length code
|
|
while (k < (20)) { // max bits for literal/length code
|
|
n--;
|
|
b |= (z.read_byte(p++) & 0xff) << k;
|
|
k += 8;
|
|
}
|
|
|
|
t = b & ml;
|
|
tp = tl;
|
|
tp_index = tl_index;
|
|
tp_index_t_3 = (tp_index + t) * 3;
|
|
if ((e = tp[tp_index_t_3]) === 0) {
|
|
b >>= (tp[tp_index_t_3 + 1]);
|
|
k -= (tp[tp_index_t_3 + 1]);
|
|
|
|
s.win[q++] = /* (byte) */tp[tp_index_t_3 + 2];
|
|
m--;
|
|
continue;
|
|
}
|
|
do {
|
|
|
|
b >>= (tp[tp_index_t_3 + 1]);
|
|
k -= (tp[tp_index_t_3 + 1]);
|
|
|
|
if ((e & 16) !== 0) {
|
|
e &= 15;
|
|
c = tp[tp_index_t_3 + 2] + (/* (int) */b & inflate_mask[e]);
|
|
|
|
b >>= e;
|
|
k -= e;
|
|
|
|
// decode distance base of block to copy
|
|
while (k < (15)) { // max bits for distance code
|
|
n--;
|
|
b |= (z.read_byte(p++) & 0xff) << k;
|
|
k += 8;
|
|
}
|
|
|
|
t = b & md;
|
|
tp = td;
|
|
tp_index = td_index;
|
|
tp_index_t_3 = (tp_index + t) * 3;
|
|
e = tp[tp_index_t_3];
|
|
|
|
do {
|
|
|
|
b >>= (tp[tp_index_t_3 + 1]);
|
|
k -= (tp[tp_index_t_3 + 1]);
|
|
|
|
if ((e & 16) !== 0) {
|
|
// get extra bits to add to distance base
|
|
e &= 15;
|
|
while (k < (e)) { // get extra bits (up to 13)
|
|
n--;
|
|
b |= (z.read_byte(p++) & 0xff) << k;
|
|
k += 8;
|
|
}
|
|
|
|
d = tp[tp_index_t_3 + 2] + (b & inflate_mask[e]);
|
|
|
|
b >>= (e);
|
|
k -= (e);
|
|
|
|
// do the copy
|
|
m -= c;
|
|
if (q >= d) { // offset before dest
|
|
// just copy
|
|
r = q - d;
|
|
if (q - r > 0 && 2 > (q - r)) {
|
|
s.win[q++] = s.win[r++]; // minimum
|
|
// count is
|
|
// three,
|
|
s.win[q++] = s.win[r++]; // so unroll
|
|
// loop a
|
|
// little
|
|
c -= 2;
|
|
} else {
|
|
s.win.set(s.win.subarray(r, r + 2), q);
|
|
q += 2;
|
|
r += 2;
|
|
c -= 2;
|
|
}
|
|
} else { // else offset after destination
|
|
r = q - d;
|
|
do {
|
|
r += s.end; // force pointer in win
|
|
} while (r < 0); // covers invalid distances
|
|
e = s.end - r;
|
|
if (c > e) { // if source crosses,
|
|
c -= e; // wrapped copy
|
|
if (q - r > 0 && e > (q - r)) {
|
|
do {
|
|
s.win[q++] = s.win[r++];
|
|
} while (--e !== 0);
|
|
} else {
|
|
s.win.set(s.win.subarray(r, r + e), q);
|
|
q += e;
|
|
r += e;
|
|
e = 0;
|
|
}
|
|
r = 0; // copy rest from start of win
|
|
}
|
|
|
|
}
|
|
|
|
// copy all or what's left
|
|
if (q - r > 0 && c > (q - r)) {
|
|
do {
|
|
s.win[q++] = s.win[r++];
|
|
} while (--c !== 0);
|
|
} else {
|
|
s.win.set(s.win.subarray(r, r + c), q);
|
|
q += c;
|
|
r += c;
|
|
c = 0;
|
|
}
|
|
break;
|
|
} else if ((e & 64) === 0) {
|
|
t += tp[tp_index_t_3 + 2];
|
|
t += (b & inflate_mask[e]);
|
|
tp_index_t_3 = (tp_index + t) * 3;
|
|
e = tp[tp_index_t_3];
|
|
} else {
|
|
z.msg = "invalid distance code";
|
|
|
|
c = z.avail_in - n;
|
|
c = (k >> 3) < c ? k >> 3 : c;
|
|
n += c;
|
|
p -= c;
|
|
k -= c << 3;
|
|
|
|
s.bitb = b;
|
|
s.bitk = k;
|
|
z.avail_in = n;
|
|
z.total_in += p - z.next_in_index;
|
|
z.next_in_index = p;
|
|
s.write = q;
|
|
|
|
return Z_DATA_ERROR;
|
|
}
|
|
// eslint-disable-next-line no-constant-condition
|
|
} while (true);
|
|
break;
|
|
}
|
|
|
|
if ((e & 64) === 0) {
|
|
t += tp[tp_index_t_3 + 2];
|
|
t += (b & inflate_mask[e]);
|
|
tp_index_t_3 = (tp_index + t) * 3;
|
|
if ((e = tp[tp_index_t_3]) === 0) {
|
|
|
|
b >>= (tp[tp_index_t_3 + 1]);
|
|
k -= (tp[tp_index_t_3 + 1]);
|
|
|
|
s.win[q++] = /* (byte) */tp[tp_index_t_3 + 2];
|
|
m--;
|
|
break;
|
|
}
|
|
} else if ((e & 32) !== 0) {
|
|
|
|
c = z.avail_in - n;
|
|
c = (k >> 3) < c ? k >> 3 : c;
|
|
n += c;
|
|
p -= c;
|
|
k -= c << 3;
|
|
|
|
s.bitb = b;
|
|
s.bitk = k;
|
|
z.avail_in = n;
|
|
z.total_in += p - z.next_in_index;
|
|
z.next_in_index = p;
|
|
s.write = q;
|
|
|
|
return Z_STREAM_END;
|
|
} else {
|
|
z.msg = "invalid literal/length code";
|
|
|
|
c = z.avail_in - n;
|
|
c = (k >> 3) < c ? k >> 3 : c;
|
|
n += c;
|
|
p -= c;
|
|
k -= c << 3;
|
|
|
|
s.bitb = b;
|
|
s.bitk = k;
|
|
z.avail_in = n;
|
|
z.total_in += p - z.next_in_index;
|
|
z.next_in_index = p;
|
|
s.write = q;
|
|
|
|
return Z_DATA_ERROR;
|
|
}
|
|
// eslint-disable-next-line no-constant-condition
|
|
} while (true);
|
|
} while (m >= 258 && n >= 10);
|
|
|
|
// not enough input or output--restore pointers and return
|
|
c = z.avail_in - n;
|
|
c = (k >> 3) < c ? k >> 3 : c;
|
|
n += c;
|
|
p -= c;
|
|
k -= c << 3;
|
|
|
|
s.bitb = b;
|
|
s.bitk = k;
|
|
z.avail_in = n;
|
|
z.total_in += p - z.next_in_index;
|
|
z.next_in_index = p;
|
|
s.write = q;
|
|
|
|
return Z_OK;
|
|
}
|
|
|
|
that.init = function (bl, bd, tl, tl_index, td, td_index) {
|
|
mode = START;
|
|
lbits = /* (byte) */bl;
|
|
dbits = /* (byte) */bd;
|
|
ltree = tl;
|
|
ltree_index = tl_index;
|
|
dtree = td;
|
|
dtree_index = td_index;
|
|
tree = null;
|
|
};
|
|
|
|
that.proc = function (s, z, r) {
|
|
let j; // temporary storage
|
|
let tindex; // temporary pointer
|
|
let e; // extra bits or operation
|
|
let b = 0; // bit buffer
|
|
let k = 0; // bits in bit buffer
|
|
let p = 0; // input data pointer
|
|
let n; // bytes available there
|
|
let q; // output win write pointer
|
|
let m; // bytes to end of win or read pointer
|
|
let f; // pointer to copy strings from
|
|
|
|
// copy input/output information to locals (UPDATE macro restores)
|
|
p = z.next_in_index;
|
|
n = z.avail_in;
|
|
b = s.bitb;
|
|
k = s.bitk;
|
|
q = s.write;
|
|
m = q < s.read ? s.read - q - 1 : s.end - q;
|
|
|
|
// process input and output based on current state
|
|
// eslint-disable-next-line no-constant-condition
|
|
while (true) {
|
|
switch (mode) {
|
|
// waiting for "i:"=input, "o:"=output, "x:"=nothing
|
|
case START: // x: set up for LEN
|
|
if (m >= 258 && n >= 10) {
|
|
|
|
s.bitb = b;
|
|
s.bitk = k;
|
|
z.avail_in = n;
|
|
z.total_in += p - z.next_in_index;
|
|
z.next_in_index = p;
|
|
s.write = q;
|
|
r = inflate_fast(lbits, dbits, ltree, ltree_index, dtree, dtree_index, s, z);
|
|
|
|
p = z.next_in_index;
|
|
n = z.avail_in;
|
|
b = s.bitb;
|
|
k = s.bitk;
|
|
q = s.write;
|
|
m = q < s.read ? s.read - q - 1 : s.end - q;
|
|
|
|
if (r != Z_OK) {
|
|
mode = r == Z_STREAM_END ? WASH : BADCODE;
|
|
break;
|
|
}
|
|
}
|
|
need = lbits;
|
|
tree = ltree;
|
|
tree_index = ltree_index;
|
|
|
|
mode = LEN;
|
|
/* falls through */
|
|
case LEN: // i: get length/literal/eob next
|
|
j = need;
|
|
|
|
while (k < (j)) {
|
|
if (n !== 0)
|
|
r = Z_OK;
|
|
else {
|
|
|
|
s.bitb = b;
|
|
s.bitk = k;
|
|
z.avail_in = n;
|
|
z.total_in += p - z.next_in_index;
|
|
z.next_in_index = p;
|
|
s.write = q;
|
|
return s.inflate_flush(z, r);
|
|
}
|
|
n--;
|
|
b |= (z.read_byte(p++) & 0xff) << k;
|
|
k += 8;
|
|
}
|
|
|
|
tindex = (tree_index + (b & inflate_mask[j])) * 3;
|
|
|
|
b >>>= (tree[tindex + 1]);
|
|
k -= (tree[tindex + 1]);
|
|
|
|
e = tree[tindex];
|
|
|
|
if (e === 0) { // literal
|
|
lit = tree[tindex + 2];
|
|
mode = LIT;
|
|
break;
|
|
}
|
|
if ((e & 16) !== 0) { // length
|
|
get = e & 15;
|
|
len = tree[tindex + 2];
|
|
mode = LENEXT;
|
|
break;
|
|
}
|
|
if ((e & 64) === 0) { // next table
|
|
need = e;
|
|
tree_index = tindex / 3 + tree[tindex + 2];
|
|
break;
|
|
}
|
|
if ((e & 32) !== 0) { // end of block
|
|
mode = WASH;
|
|
break;
|
|
}
|
|
mode = BADCODE; // invalid code
|
|
z.msg = "invalid literal/length code";
|
|
r = Z_DATA_ERROR;
|
|
|
|
s.bitb = b;
|
|
s.bitk = k;
|
|
z.avail_in = n;
|
|
z.total_in += p - z.next_in_index;
|
|
z.next_in_index = p;
|
|
s.write = q;
|
|
return s.inflate_flush(z, r);
|
|
|
|
case LENEXT: // i: getting length extra (have base)
|
|
j = get;
|
|
|
|
while (k < (j)) {
|
|
if (n !== 0)
|
|
r = Z_OK;
|
|
else {
|
|
|
|
s.bitb = b;
|
|
s.bitk = k;
|
|
z.avail_in = n;
|
|
z.total_in += p - z.next_in_index;
|
|
z.next_in_index = p;
|
|
s.write = q;
|
|
return s.inflate_flush(z, r);
|
|
}
|
|
n--;
|
|
b |= (z.read_byte(p++) & 0xff) << k;
|
|
k += 8;
|
|
}
|
|
|
|
len += (b & inflate_mask[j]);
|
|
|
|
b >>= j;
|
|
k -= j;
|
|
|
|
need = dbits;
|
|
tree = dtree;
|
|
tree_index = dtree_index;
|
|
mode = DIST;
|
|
/* falls through */
|
|
case DIST: // i: get distance next
|
|
j = need;
|
|
|
|
while (k < (j)) {
|
|
if (n !== 0)
|
|
r = Z_OK;
|
|
else {
|
|
|
|
s.bitb = b;
|
|
s.bitk = k;
|
|
z.avail_in = n;
|
|
z.total_in += p - z.next_in_index;
|
|
z.next_in_index = p;
|
|
s.write = q;
|
|
return s.inflate_flush(z, r);
|
|
}
|
|
n--;
|
|
b |= (z.read_byte(p++) & 0xff) << k;
|
|
k += 8;
|
|
}
|
|
|
|
tindex = (tree_index + (b & inflate_mask[j])) * 3;
|
|
|
|
b >>= tree[tindex + 1];
|
|
k -= tree[tindex + 1];
|
|
|
|
e = (tree[tindex]);
|
|
if ((e & 16) !== 0) { // distance
|
|
get = e & 15;
|
|
dist = tree[tindex + 2];
|
|
mode = DISTEXT;
|
|
break;
|
|
}
|
|
if ((e & 64) === 0) { // next table
|
|
need = e;
|
|
tree_index = tindex / 3 + tree[tindex + 2];
|
|
break;
|
|
}
|
|
mode = BADCODE; // invalid code
|
|
z.msg = "invalid distance code";
|
|
r = Z_DATA_ERROR;
|
|
|
|
s.bitb = b;
|
|
s.bitk = k;
|
|
z.avail_in = n;
|
|
z.total_in += p - z.next_in_index;
|
|
z.next_in_index = p;
|
|
s.write = q;
|
|
return s.inflate_flush(z, r);
|
|
|
|
case DISTEXT: // i: getting distance extra
|
|
j = get;
|
|
|
|
while (k < (j)) {
|
|
if (n !== 0)
|
|
r = Z_OK;
|
|
else {
|
|
|
|
s.bitb = b;
|
|
s.bitk = k;
|
|
z.avail_in = n;
|
|
z.total_in += p - z.next_in_index;
|
|
z.next_in_index = p;
|
|
s.write = q;
|
|
return s.inflate_flush(z, r);
|
|
}
|
|
n--;
|
|
b |= (z.read_byte(p++) & 0xff) << k;
|
|
k += 8;
|
|
}
|
|
|
|
dist += (b & inflate_mask[j]);
|
|
|
|
b >>= j;
|
|
k -= j;
|
|
|
|
mode = COPY;
|
|
/* falls through */
|
|
case COPY: // o: copying bytes in win, waiting for space
|
|
f = q - dist;
|
|
while (f < 0) { // modulo win size-"while" instead
|
|
f += s.end; // of "if" handles invalid distances
|
|
}
|
|
while (len !== 0) {
|
|
|
|
if (m === 0) {
|
|
if (q == s.end && s.read !== 0) {
|
|
q = 0;
|
|
m = q < s.read ? s.read - q - 1 : s.end - q;
|
|
}
|
|
if (m === 0) {
|
|
s.write = q;
|
|
r = s.inflate_flush(z, r);
|
|
q = s.write;
|
|
m = q < s.read ? s.read - q - 1 : s.end - q;
|
|
|
|
if (q == s.end && s.read !== 0) {
|
|
q = 0;
|
|
m = q < s.read ? s.read - q - 1 : s.end - q;
|
|
}
|
|
|
|
if (m === 0) {
|
|
s.bitb = b;
|
|
s.bitk = k;
|
|
z.avail_in = n;
|
|
z.total_in += p - z.next_in_index;
|
|
z.next_in_index = p;
|
|
s.write = q;
|
|
return s.inflate_flush(z, r);
|
|
}
|
|
}
|
|
}
|
|
|
|
s.win[q++] = s.win[f++];
|
|
m--;
|
|
|
|
if (f == s.end)
|
|
f = 0;
|
|
len--;
|
|
}
|
|
mode = START;
|
|
break;
|
|
case LIT: // o: got literal, waiting for output space
|
|
if (m === 0) {
|
|
if (q == s.end && s.read !== 0) {
|
|
q = 0;
|
|
m = q < s.read ? s.read - q - 1 : s.end - q;
|
|
}
|
|
if (m === 0) {
|
|
s.write = q;
|
|
r = s.inflate_flush(z, r);
|
|
q = s.write;
|
|
m = q < s.read ? s.read - q - 1 : s.end - q;
|
|
|
|
if (q == s.end && s.read !== 0) {
|
|
q = 0;
|
|
m = q < s.read ? s.read - q - 1 : s.end - q;
|
|
}
|
|
if (m === 0) {
|
|
s.bitb = b;
|
|
s.bitk = k;
|
|
z.avail_in = n;
|
|
z.total_in += p - z.next_in_index;
|
|
z.next_in_index = p;
|
|
s.write = q;
|
|
return s.inflate_flush(z, r);
|
|
}
|
|
}
|
|
}
|
|
r = Z_OK;
|
|
|
|
s.win[q++] = /* (byte) */lit;
|
|
m--;
|
|
|
|
mode = START;
|
|
break;
|
|
case WASH: // o: got eob, possibly more output
|
|
if (k > 7) { // return unused byte, if any
|
|
k -= 8;
|
|
n++;
|
|
p--; // can always return one
|
|
}
|
|
|
|
s.write = q;
|
|
r = s.inflate_flush(z, r);
|
|
q = s.write;
|
|
m = q < s.read ? s.read - q - 1 : s.end - q;
|
|
|
|
if (s.read != s.write) {
|
|
s.bitb = b;
|
|
s.bitk = k;
|
|
z.avail_in = n;
|
|
z.total_in += p - z.next_in_index;
|
|
z.next_in_index = p;
|
|
s.write = q;
|
|
return s.inflate_flush(z, r);
|
|
}
|
|
mode = END;
|
|
/* falls through */
|
|
case END:
|
|
r = Z_STREAM_END;
|
|
s.bitb = b;
|
|
s.bitk = k;
|
|
z.avail_in = n;
|
|
z.total_in += p - z.next_in_index;
|
|
z.next_in_index = p;
|
|
s.write = q;
|
|
return s.inflate_flush(z, r);
|
|
|
|
case BADCODE: // x: got error
|
|
|
|
r = Z_DATA_ERROR;
|
|
|
|
s.bitb = b;
|
|
s.bitk = k;
|
|
z.avail_in = n;
|
|
z.total_in += p - z.next_in_index;
|
|
z.next_in_index = p;
|
|
s.write = q;
|
|
return s.inflate_flush(z, r);
|
|
|
|
default:
|
|
r = Z_STREAM_ERROR;
|
|
|
|
s.bitb = b;
|
|
s.bitk = k;
|
|
z.avail_in = n;
|
|
z.total_in += p - z.next_in_index;
|
|
z.next_in_index = p;
|
|
s.write = q;
|
|
return s.inflate_flush(z, r);
|
|
}
|
|
}
|
|
};
|
|
|
|
that.free = function () {
|
|
// ZFREE(z, c);
|
|
};
|
|
|
|
}
|
|
|
|
// InfBlocks
|
|
|
|
// Table for deflate from PKZIP's appnote.txt.
|
|
const border = [ // Order of the bit length code lengths
|
|
16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15];
|
|
|
|
const TYPE = 0; // get type bits (3, including end bit)
|
|
const LENS = 1; // get lengths for stored
|
|
const STORED = 2;// processing stored block
|
|
const TABLE = 3; // get table lengths
|
|
const BTREE = 4; // get bit lengths tree for a dynamic
|
|
// block
|
|
const DTREE = 5; // get length, distance trees for a
|
|
// dynamic block
|
|
const CODES = 6; // processing fixed or dynamic block
|
|
const DRY = 7; // output remaining win bytes
|
|
const DONELOCKS = 8; // finished last block, done
|
|
const BADBLOCKS = 9; // ot a data error--stuck here
|
|
|
|
function InfBlocks(z, w) {
|
|
const that = this;
|
|
|
|
let mode = TYPE; // current inflate_block mode
|
|
|
|
let left = 0; // if STORED, bytes left to copy
|
|
|
|
let table = 0; // table lengths (14 bits)
|
|
let index = 0; // index into blens (or border)
|
|
let blens; // bit lengths of codes
|
|
const bb = [0]; // bit length tree depth
|
|
const tb = [0]; // bit length decoding tree
|
|
|
|
const codes = new InfCodes(); // if CODES, current state
|
|
|
|
let last = 0; // true if this block is the last block
|
|
|
|
let hufts = new Int32Array(MANY * 3); // single malloc for tree space
|
|
const check = 0; // check on output
|
|
const inftree = new InfTree();
|
|
|
|
that.bitk = 0; // bits in bit buffer
|
|
that.bitb = 0; // bit buffer
|
|
that.win = new Uint8Array(w); // sliding win
|
|
that.end = w; // one byte after sliding win
|
|
that.read = 0; // win read pointer
|
|
that.write = 0; // win write pointer
|
|
|
|
that.reset = function (z, c) {
|
|
if (c)
|
|
c[0] = check;
|
|
// if (mode == BTREE || mode == DTREE) {
|
|
// }
|
|
if (mode == CODES) {
|
|
codes.free(z);
|
|
}
|
|
mode = TYPE;
|
|
that.bitk = 0;
|
|
that.bitb = 0;
|
|
that.read = that.write = 0;
|
|
};
|
|
|
|
that.reset(z, null);
|
|
|
|
// copy as much as possible from the sliding win to the output area
|
|
that.inflate_flush = function (z, r) {
|
|
let n;
|
|
let p;
|
|
let q;
|
|
|
|
// local copies of source and destination pointers
|
|
p = z.next_out_index;
|
|
q = that.read;
|
|
|
|
// compute number of bytes to copy as far as end of win
|
|
n = /* (int) */((q <= that.write ? that.write : that.end) - q);
|
|
if (n > z.avail_out)
|
|
n = z.avail_out;
|
|
if (n !== 0 && r == Z_BUF_ERROR)
|
|
r = Z_OK;
|
|
|
|
// update counters
|
|
z.avail_out -= n;
|
|
z.total_out += n;
|
|
|
|
// copy as far as end of win
|
|
z.next_out.set(that.win.subarray(q, q + n), p);
|
|
p += n;
|
|
q += n;
|
|
|
|
// see if more to copy at beginning of win
|
|
if (q == that.end) {
|
|
// wrap pointers
|
|
q = 0;
|
|
if (that.write == that.end)
|
|
that.write = 0;
|
|
|
|
// compute bytes to copy
|
|
n = that.write - q;
|
|
if (n > z.avail_out)
|
|
n = z.avail_out;
|
|
if (n !== 0 && r == Z_BUF_ERROR)
|
|
r = Z_OK;
|
|
|
|
// update counters
|
|
z.avail_out -= n;
|
|
z.total_out += n;
|
|
|
|
// copy
|
|
z.next_out.set(that.win.subarray(q, q + n), p);
|
|
p += n;
|
|
q += n;
|
|
}
|
|
|
|
// update pointers
|
|
z.next_out_index = p;
|
|
that.read = q;
|
|
|
|
// done
|
|
return r;
|
|
};
|
|
|
|
that.proc = function (z, r) {
|
|
let t; // temporary storage
|
|
let b; // bit buffer
|
|
let k; // bits in bit buffer
|
|
let p; // input data pointer
|
|
let n; // bytes available there
|
|
let q; // output win write pointer
|
|
let m; // bytes to end of win or read pointer
|
|
|
|
let i;
|
|
|
|
// copy input/output information to locals (UPDATE macro restores)
|
|
// {
|
|
p = z.next_in_index;
|
|
n = z.avail_in;
|
|
b = that.bitb;
|
|
k = that.bitk;
|
|
// }
|
|
// {
|
|
q = that.write;
|
|
m = /* (int) */(q < that.read ? that.read - q - 1 : that.end - q);
|
|
// }
|
|
|
|
// process input based on current state
|
|
// DEBUG dtree
|
|
// eslint-disable-next-line no-constant-condition
|
|
while (true) {
|
|
let bl, bd, tl, td, bl_, bd_, tl_, td_;
|
|
switch (mode) {
|
|
case TYPE:
|
|
|
|
while (k < (3)) {
|
|
if (n !== 0) {
|
|
r = Z_OK;
|
|
} else {
|
|
that.bitb = b;
|
|
that.bitk = k;
|
|
z.avail_in = n;
|
|
z.total_in += p - z.next_in_index;
|
|
z.next_in_index = p;
|
|
that.write = q;
|
|
return that.inflate_flush(z, r);
|
|
}
|
|
n--;
|
|
b |= (z.read_byte(p++) & 0xff) << k;
|
|
k += 8;
|
|
}
|
|
t = /* (int) */(b & 7);
|
|
last = t & 1;
|
|
|
|
switch (t >>> 1) {
|
|
case 0: // stored
|
|
// {
|
|
b >>>= (3);
|
|
k -= (3);
|
|
// }
|
|
t = k & 7; // go to byte boundary
|
|
|
|
// {
|
|
b >>>= (t);
|
|
k -= (t);
|
|
// }
|
|
mode = LENS; // get length of stored block
|
|
break;
|
|
case 1: // fixed
|
|
// {
|
|
bl = []; // new Array(1);
|
|
bd = []; // new Array(1);
|
|
tl = [[]]; // new Array(1);
|
|
td = [[]]; // new Array(1);
|
|
|
|
InfTree.inflate_trees_fixed(bl, bd, tl, td);
|
|
codes.init(bl[0], bd[0], tl[0], 0, td[0], 0);
|
|
// }
|
|
|
|
// {
|
|
b >>>= (3);
|
|
k -= (3);
|
|
// }
|
|
|
|
mode = CODES;
|
|
break;
|
|
case 2: // dynamic
|
|
|
|
// {
|
|
b >>>= (3);
|
|
k -= (3);
|
|
// }
|
|
|
|
mode = TABLE;
|
|
break;
|
|
case 3: // illegal
|
|
|
|
// {
|
|
b >>>= (3);
|
|
k -= (3);
|
|
// }
|
|
mode = BADBLOCKS;
|
|
z.msg = "invalid block type";
|
|
r = Z_DATA_ERROR;
|
|
|
|
that.bitb = b;
|
|
that.bitk = k;
|
|
z.avail_in = n;
|
|
z.total_in += p - z.next_in_index;
|
|
z.next_in_index = p;
|
|
that.write = q;
|
|
return that.inflate_flush(z, r);
|
|
}
|
|
break;
|
|
case LENS:
|
|
|
|
while (k < (32)) {
|
|
if (n !== 0) {
|
|
r = Z_OK;
|
|
} else {
|
|
that.bitb = b;
|
|
that.bitk = k;
|
|
z.avail_in = n;
|
|
z.total_in += p - z.next_in_index;
|
|
z.next_in_index = p;
|
|
that.write = q;
|
|
return that.inflate_flush(z, r);
|
|
}
|
|
n--;
|
|
b |= (z.read_byte(p++) & 0xff) << k;
|
|
k += 8;
|
|
}
|
|
|
|
if ((((~b) >>> 16) & 0xffff) != (b & 0xffff)) {
|
|
mode = BADBLOCKS;
|
|
z.msg = "invalid stored block lengths";
|
|
r = Z_DATA_ERROR;
|
|
|
|
that.bitb = b;
|
|
that.bitk = k;
|
|
z.avail_in = n;
|
|
z.total_in += p - z.next_in_index;
|
|
z.next_in_index = p;
|
|
that.write = q;
|
|
return that.inflate_flush(z, r);
|
|
}
|
|
left = (b & 0xffff);
|
|
b = k = 0; // dump bits
|
|
mode = left !== 0 ? STORED : (last !== 0 ? DRY : TYPE);
|
|
break;
|
|
case STORED:
|
|
if (n === 0) {
|
|
that.bitb = b;
|
|
that.bitk = k;
|
|
z.avail_in = n;
|
|
z.total_in += p - z.next_in_index;
|
|
z.next_in_index = p;
|
|
that.write = q;
|
|
return that.inflate_flush(z, r);
|
|
}
|
|
|
|
if (m === 0) {
|
|
if (q == that.end && that.read !== 0) {
|
|
q = 0;
|
|
m = /* (int) */(q < that.read ? that.read - q - 1 : that.end - q);
|
|
}
|
|
if (m === 0) {
|
|
that.write = q;
|
|
r = that.inflate_flush(z, r);
|
|
q = that.write;
|
|
m = /* (int) */(q < that.read ? that.read - q - 1 : that.end - q);
|
|
if (q == that.end && that.read !== 0) {
|
|
q = 0;
|
|
m = /* (int) */(q < that.read ? that.read - q - 1 : that.end - q);
|
|
}
|
|
if (m === 0) {
|
|
that.bitb = b;
|
|
that.bitk = k;
|
|
z.avail_in = n;
|
|
z.total_in += p - z.next_in_index;
|
|
z.next_in_index = p;
|
|
that.write = q;
|
|
return that.inflate_flush(z, r);
|
|
}
|
|
}
|
|
}
|
|
r = Z_OK;
|
|
|
|
t = left;
|
|
if (t > n)
|
|
t = n;
|
|
if (t > m)
|
|
t = m;
|
|
that.win.set(z.read_buf(p, t), q);
|
|
p += t;
|
|
n -= t;
|
|
q += t;
|
|
m -= t;
|
|
if ((left -= t) !== 0)
|
|
break;
|
|
mode = last !== 0 ? DRY : TYPE;
|
|
break;
|
|
case TABLE:
|
|
|
|
while (k < (14)) {
|
|
if (n !== 0) {
|
|
r = Z_OK;
|
|
} else {
|
|
that.bitb = b;
|
|
that.bitk = k;
|
|
z.avail_in = n;
|
|
z.total_in += p - z.next_in_index;
|
|
z.next_in_index = p;
|
|
that.write = q;
|
|
return that.inflate_flush(z, r);
|
|
}
|
|
|
|
n--;
|
|
b |= (z.read_byte(p++) & 0xff) << k;
|
|
k += 8;
|
|
}
|
|
|
|
table = t = (b & 0x3fff);
|
|
if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29) {
|
|
mode = BADBLOCKS;
|
|
z.msg = "too many length or distance symbols";
|
|
r = Z_DATA_ERROR;
|
|
|
|
that.bitb = b;
|
|
that.bitk = k;
|
|
z.avail_in = n;
|
|
z.total_in += p - z.next_in_index;
|
|
z.next_in_index = p;
|
|
that.write = q;
|
|
return that.inflate_flush(z, r);
|
|
}
|
|
t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f);
|
|
if (!blens || blens.length < t) {
|
|
blens = []; // new Array(t);
|
|
} else {
|
|
for (i = 0; i < t; i++) {
|
|
blens[i] = 0;
|
|
}
|
|
}
|
|
|
|
// {
|
|
b >>>= (14);
|
|
k -= (14);
|
|
// }
|
|
|
|
index = 0;
|
|
mode = BTREE;
|
|
/* falls through */
|
|
case BTREE:
|
|
while (index < 4 + (table >>> 10)) {
|
|
while (k < (3)) {
|
|
if (n !== 0) {
|
|
r = Z_OK;
|
|
} else {
|
|
that.bitb = b;
|
|
that.bitk = k;
|
|
z.avail_in = n;
|
|
z.total_in += p - z.next_in_index;
|
|
z.next_in_index = p;
|
|
that.write = q;
|
|
return that.inflate_flush(z, r);
|
|
}
|
|
n--;
|
|
b |= (z.read_byte(p++) & 0xff) << k;
|
|
k += 8;
|
|
}
|
|
|
|
blens[border[index++]] = b & 7;
|
|
|
|
// {
|
|
b >>>= (3);
|
|
k -= (3);
|
|
// }
|
|
}
|
|
|
|
while (index < 19) {
|
|
blens[border[index++]] = 0;
|
|
}
|
|
|
|
bb[0] = 7;
|
|
t = inftree.inflate_trees_bits(blens, bb, tb, hufts, z);
|
|
if (t != Z_OK) {
|
|
r = t;
|
|
if (r == Z_DATA_ERROR) {
|
|
blens = null;
|
|
mode = BADBLOCKS;
|
|
}
|
|
|
|
that.bitb = b;
|
|
that.bitk = k;
|
|
z.avail_in = n;
|
|
z.total_in += p - z.next_in_index;
|
|
z.next_in_index = p;
|
|
that.write = q;
|
|
return that.inflate_flush(z, r);
|
|
}
|
|
|
|
index = 0;
|
|
mode = DTREE;
|
|
/* falls through */
|
|
case DTREE:
|
|
// eslint-disable-next-line no-constant-condition
|
|
while (true) {
|
|
t = table;
|
|
if (index >= 258 + (t & 0x1f) + ((t >> 5) & 0x1f)) {
|
|
break;
|
|
}
|
|
|
|
let j, c;
|
|
|
|
t = bb[0];
|
|
|
|
while (k < (t)) {
|
|
if (n !== 0) {
|
|
r = Z_OK;
|
|
} else {
|
|
that.bitb = b;
|
|
that.bitk = k;
|
|
z.avail_in = n;
|
|
z.total_in += p - z.next_in_index;
|
|
z.next_in_index = p;
|
|
that.write = q;
|
|
return that.inflate_flush(z, r);
|
|
}
|
|
n--;
|
|
b |= (z.read_byte(p++) & 0xff) << k;
|
|
k += 8;
|
|
}
|
|
|
|
// if (tb[0] == -1) {
|
|
// System.err.println("null...");
|
|
// }
|
|
|
|
t = hufts[(tb[0] + (b & inflate_mask[t])) * 3 + 1];
|
|
c = hufts[(tb[0] + (b & inflate_mask[t])) * 3 + 2];
|
|
|
|
if (c < 16) {
|
|
b >>>= (t);
|
|
k -= (t);
|
|
blens[index++] = c;
|
|
} else { // c == 16..18
|
|
i = c == 18 ? 7 : c - 14;
|
|
j = c == 18 ? 11 : 3;
|
|
|
|
while (k < (t + i)) {
|
|
if (n !== 0) {
|
|
r = Z_OK;
|
|
} else {
|
|
that.bitb = b;
|
|
that.bitk = k;
|
|
z.avail_in = n;
|
|
z.total_in += p - z.next_in_index;
|
|
z.next_in_index = p;
|
|
that.write = q;
|
|
return that.inflate_flush(z, r);
|
|
}
|
|
n--;
|
|
b |= (z.read_byte(p++) & 0xff) << k;
|
|
k += 8;
|
|
}
|
|
|
|
b >>>= (t);
|
|
k -= (t);
|
|
|
|
j += (b & inflate_mask[i]);
|
|
|
|
b >>>= (i);
|
|
k -= (i);
|
|
|
|
i = index;
|
|
t = table;
|
|
if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) || (c == 16 && i < 1)) {
|
|
blens = null;
|
|
mode = BADBLOCKS;
|
|
z.msg = "invalid bit length repeat";
|
|
r = Z_DATA_ERROR;
|
|
|
|
that.bitb = b;
|
|
that.bitk = k;
|
|
z.avail_in = n;
|
|
z.total_in += p - z.next_in_index;
|
|
z.next_in_index = p;
|
|
that.write = q;
|
|
return that.inflate_flush(z, r);
|
|
}
|
|
|
|
c = c == 16 ? blens[i - 1] : 0;
|
|
do {
|
|
blens[i++] = c;
|
|
} while (--j !== 0);
|
|
index = i;
|
|
}
|
|
}
|
|
|
|
tb[0] = -1;
|
|
// {
|
|
bl_ = []; // new Array(1);
|
|
bd_ = []; // new Array(1);
|
|
tl_ = []; // new Array(1);
|
|
td_ = []; // new Array(1);
|
|
bl_[0] = 9; // must be <= 9 for lookahead assumptions
|
|
bd_[0] = 6; // must be <= 9 for lookahead assumptions
|
|
|
|
t = table;
|
|
t = inftree.inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f), blens, bl_, bd_, tl_, td_, hufts, z);
|
|
|
|
if (t != Z_OK) {
|
|
if (t == Z_DATA_ERROR) {
|
|
blens = null;
|
|
mode = BADBLOCKS;
|
|
}
|
|
r = t;
|
|
|
|
that.bitb = b;
|
|
that.bitk = k;
|
|
z.avail_in = n;
|
|
z.total_in += p - z.next_in_index;
|
|
z.next_in_index = p;
|
|
that.write = q;
|
|
return that.inflate_flush(z, r);
|
|
}
|
|
codes.init(bl_[0], bd_[0], hufts, tl_[0], hufts, td_[0]);
|
|
// }
|
|
mode = CODES;
|
|
/* falls through */
|
|
case CODES:
|
|
that.bitb = b;
|
|
that.bitk = k;
|
|
z.avail_in = n;
|
|
z.total_in += p - z.next_in_index;
|
|
z.next_in_index = p;
|
|
that.write = q;
|
|
|
|
if ((r = codes.proc(that, z, r)) != Z_STREAM_END) {
|
|
return that.inflate_flush(z, r);
|
|
}
|
|
r = Z_OK;
|
|
codes.free(z);
|
|
|
|
p = z.next_in_index;
|
|
n = z.avail_in;
|
|
b = that.bitb;
|
|
k = that.bitk;
|
|
q = that.write;
|
|
m = /* (int) */(q < that.read ? that.read - q - 1 : that.end - q);
|
|
|
|
if (last === 0) {
|
|
mode = TYPE;
|
|
break;
|
|
}
|
|
mode = DRY;
|
|
/* falls through */
|
|
case DRY:
|
|
that.write = q;
|
|
r = that.inflate_flush(z, r);
|
|
q = that.write;
|
|
m = /* (int) */(q < that.read ? that.read - q - 1 : that.end - q);
|
|
if (that.read != that.write) {
|
|
that.bitb = b;
|
|
that.bitk = k;
|
|
z.avail_in = n;
|
|
z.total_in += p - z.next_in_index;
|
|
z.next_in_index = p;
|
|
that.write = q;
|
|
return that.inflate_flush(z, r);
|
|
}
|
|
mode = DONELOCKS;
|
|
/* falls through */
|
|
case DONELOCKS:
|
|
r = Z_STREAM_END;
|
|
|
|
that.bitb = b;
|
|
that.bitk = k;
|
|
z.avail_in = n;
|
|
z.total_in += p - z.next_in_index;
|
|
z.next_in_index = p;
|
|
that.write = q;
|
|
return that.inflate_flush(z, r);
|
|
case BADBLOCKS:
|
|
r = Z_DATA_ERROR;
|
|
|
|
that.bitb = b;
|
|
that.bitk = k;
|
|
z.avail_in = n;
|
|
z.total_in += p - z.next_in_index;
|
|
z.next_in_index = p;
|
|
that.write = q;
|
|
return that.inflate_flush(z, r);
|
|
|
|
default:
|
|
r = Z_STREAM_ERROR;
|
|
|
|
that.bitb = b;
|
|
that.bitk = k;
|
|
z.avail_in = n;
|
|
z.total_in += p - z.next_in_index;
|
|
z.next_in_index = p;
|
|
that.write = q;
|
|
return that.inflate_flush(z, r);
|
|
}
|
|
}
|
|
};
|
|
|
|
that.free = function (z) {
|
|
that.reset(z, null);
|
|
that.win = null;
|
|
hufts = null;
|
|
// ZFREE(z, s);
|
|
};
|
|
|
|
that.set_dictionary = function (d, start, n) {
|
|
that.win.set(d.subarray(start, start + n), 0);
|
|
that.read = that.write = n;
|
|
};
|
|
|
|
// Returns true if inflate is currently at the end of a block generated
|
|
// by Z_SYNC_FLUSH or Z_FULL_FLUSH.
|
|
that.sync_point = function () {
|
|
return mode == LENS ? 1 : 0;
|
|
};
|
|
|
|
}
|
|
|
|
// Inflate
|
|
|
|
// preset dictionary flag in zlib header
|
|
const PRESET_DICT = 0x20;
|
|
|
|
const Z_DEFLATED = 8;
|
|
|
|
const METHOD = 0; // waiting for method byte
|
|
const FLAG = 1; // waiting for flag byte
|
|
const DICT4 = 2; // four dictionary check bytes to go
|
|
const DICT3 = 3; // three dictionary check bytes to go
|
|
const DICT2 = 4; // two dictionary check bytes to go
|
|
const DICT1 = 5; // one dictionary check byte to go
|
|
const DICT0 = 6; // waiting for inflateSetDictionary
|
|
const BLOCKS = 7; // decompressing blocks
|
|
const DONE = 12; // finished check, done
|
|
const BAD = 13; // got an error--stay here
|
|
|
|
const mark = [0, 0, 0xff, 0xff];
|
|
|
|
function Inflate() {
|
|
const that = this;
|
|
|
|
that.mode = 0; // current inflate mode
|
|
|
|
// mode dependent information
|
|
that.method = 0; // if FLAGS, method byte
|
|
|
|
// if CHECK, check values to compare
|
|
that.was = [0]; // new Array(1); // computed check value
|
|
that.need = 0; // stream check value
|
|
|
|
// if BAD, inflateSync's marker bytes count
|
|
that.marker = 0;
|
|
|
|
// mode independent information
|
|
that.wbits = 0; // log2(win size) (8..15, defaults to 15)
|
|
|
|
// this.blocks; // current inflate_blocks state
|
|
|
|
function inflateReset(z) {
|
|
if (!z || !z.istate)
|
|
return Z_STREAM_ERROR;
|
|
|
|
z.total_in = z.total_out = 0;
|
|
z.msg = null;
|
|
z.istate.mode = BLOCKS;
|
|
z.istate.blocks.reset(z, null);
|
|
return Z_OK;
|
|
}
|
|
|
|
that.inflateEnd = function (z) {
|
|
if (that.blocks)
|
|
that.blocks.free(z);
|
|
that.blocks = null;
|
|
// ZFREE(z, z->state);
|
|
return Z_OK;
|
|
};
|
|
|
|
that.inflateInit = function (z, w) {
|
|
z.msg = null;
|
|
that.blocks = null;
|
|
|
|
// set win size
|
|
if (w < 8 || w > 15) {
|
|
that.inflateEnd(z);
|
|
return Z_STREAM_ERROR;
|
|
}
|
|
that.wbits = w;
|
|
|
|
z.istate.blocks = new InfBlocks(z, 1 << w);
|
|
|
|
// reset state
|
|
inflateReset(z);
|
|
return Z_OK;
|
|
};
|
|
|
|
that.inflate = function (z, f) {
|
|
let r;
|
|
let b;
|
|
|
|
if (!z || !z.istate || !z.next_in)
|
|
return Z_STREAM_ERROR;
|
|
const istate = z.istate;
|
|
f = f == Z_FINISH ? Z_BUF_ERROR : Z_OK;
|
|
r = Z_BUF_ERROR;
|
|
// eslint-disable-next-line no-constant-condition
|
|
while (true) {
|
|
switch (istate.mode) {
|
|
case METHOD:
|
|
|
|
if (z.avail_in === 0)
|
|
return r;
|
|
r = f;
|
|
|
|
z.avail_in--;
|
|
z.total_in++;
|
|
if (((istate.method = z.read_byte(z.next_in_index++)) & 0xf) != Z_DEFLATED) {
|
|
istate.mode = BAD;
|
|
z.msg = "unknown compression method";
|
|
istate.marker = 5; // can't try inflateSync
|
|
break;
|
|
}
|
|
if ((istate.method >> 4) + 8 > istate.wbits) {
|
|
istate.mode = BAD;
|
|
z.msg = "invalid win size";
|
|
istate.marker = 5; // can't try inflateSync
|
|
break;
|
|
}
|
|
istate.mode = FLAG;
|
|
/* falls through */
|
|
case FLAG:
|
|
|
|
if (z.avail_in === 0)
|
|
return r;
|
|
r = f;
|
|
|
|
z.avail_in--;
|
|
z.total_in++;
|
|
b = (z.read_byte(z.next_in_index++)) & 0xff;
|
|
|
|
if ((((istate.method << 8) + b) % 31) !== 0) {
|
|
istate.mode = BAD;
|
|
z.msg = "incorrect header check";
|
|
istate.marker = 5; // can't try inflateSync
|
|
break;
|
|
}
|
|
|
|
if ((b & PRESET_DICT) === 0) {
|
|
istate.mode = BLOCKS;
|
|
break;
|
|
}
|
|
istate.mode = DICT4;
|
|
/* falls through */
|
|
case DICT4:
|
|
|
|
if (z.avail_in === 0)
|
|
return r;
|
|
r = f;
|
|
|
|
z.avail_in--;
|
|
z.total_in++;
|
|
istate.need = ((z.read_byte(z.next_in_index++) & 0xff) << 24) & 0xff000000;
|
|
istate.mode = DICT3;
|
|
/* falls through */
|
|
case DICT3:
|
|
|
|
if (z.avail_in === 0)
|
|
return r;
|
|
r = f;
|
|
|
|
z.avail_in--;
|
|
z.total_in++;
|
|
istate.need += ((z.read_byte(z.next_in_index++) & 0xff) << 16) & 0xff0000;
|
|
istate.mode = DICT2;
|
|
/* falls through */
|
|
case DICT2:
|
|
|
|
if (z.avail_in === 0)
|
|
return r;
|
|
r = f;
|
|
|
|
z.avail_in--;
|
|
z.total_in++;
|
|
istate.need += ((z.read_byte(z.next_in_index++) & 0xff) << 8) & 0xff00;
|
|
istate.mode = DICT1;
|
|
/* falls through */
|
|
case DICT1:
|
|
|
|
if (z.avail_in === 0)
|
|
return r;
|
|
r = f;
|
|
|
|
z.avail_in--;
|
|
z.total_in++;
|
|
istate.need += (z.read_byte(z.next_in_index++) & 0xff);
|
|
istate.mode = DICT0;
|
|
return Z_NEED_DICT;
|
|
case DICT0:
|
|
istate.mode = BAD;
|
|
z.msg = "need dictionary";
|
|
istate.marker = 0; // can try inflateSync
|
|
return Z_STREAM_ERROR;
|
|
case BLOCKS:
|
|
|
|
r = istate.blocks.proc(z, r);
|
|
if (r == Z_DATA_ERROR) {
|
|
istate.mode = BAD;
|
|
istate.marker = 0; // can try inflateSync
|
|
break;
|
|
}
|
|
if (r == Z_OK) {
|
|
r = f;
|
|
}
|
|
if (r != Z_STREAM_END) {
|
|
return r;
|
|
}
|
|
r = f;
|
|
istate.blocks.reset(z, istate.was);
|
|
istate.mode = DONE;
|
|
/* falls through */
|
|
case DONE:
|
|
z.avail_in = 0;
|
|
return Z_STREAM_END;
|
|
case BAD:
|
|
return Z_DATA_ERROR;
|
|
default:
|
|
return Z_STREAM_ERROR;
|
|
}
|
|
}
|
|
};
|
|
|
|
that.inflateSetDictionary = function (z, dictionary, dictLength) {
|
|
let index = 0, length = dictLength;
|
|
if (!z || !z.istate || z.istate.mode != DICT0)
|
|
return Z_STREAM_ERROR;
|
|
const istate = z.istate;
|
|
if (length >= (1 << istate.wbits)) {
|
|
length = (1 << istate.wbits) - 1;
|
|
index = dictLength - length;
|
|
}
|
|
istate.blocks.set_dictionary(dictionary, index, length);
|
|
istate.mode = BLOCKS;
|
|
return Z_OK;
|
|
};
|
|
|
|
that.inflateSync = function (z) {
|
|
let n; // number of bytes to look at
|
|
let p; // pointer to bytes
|
|
let m; // number of marker bytes found in a row
|
|
let r, w; // temporaries to save total_in and total_out
|
|
|
|
// set up
|
|
if (!z || !z.istate)
|
|
return Z_STREAM_ERROR;
|
|
const istate = z.istate;
|
|
if (istate.mode != BAD) {
|
|
istate.mode = BAD;
|
|
istate.marker = 0;
|
|
}
|
|
if ((n = z.avail_in) === 0)
|
|
return Z_BUF_ERROR;
|
|
p = z.next_in_index;
|
|
m = istate.marker;
|
|
|
|
// search
|
|
while (n !== 0 && m < 4) {
|
|
if (z.read_byte(p) == mark[m]) {
|
|
m++;
|
|
} else if (z.read_byte(p) !== 0) {
|
|
m = 0;
|
|
} else {
|
|
m = 4 - m;
|
|
}
|
|
p++;
|
|
n--;
|
|
}
|
|
|
|
// restore
|
|
z.total_in += p - z.next_in_index;
|
|
z.next_in_index = p;
|
|
z.avail_in = n;
|
|
istate.marker = m;
|
|
|
|
// return no joy or set up to restart on a new block
|
|
if (m != 4) {
|
|
return Z_DATA_ERROR;
|
|
}
|
|
r = z.total_in;
|
|
w = z.total_out;
|
|
inflateReset(z);
|
|
z.total_in = r;
|
|
z.total_out = w;
|
|
istate.mode = BLOCKS;
|
|
return Z_OK;
|
|
};
|
|
|
|
// Returns true if inflate is currently at the end of a block generated
|
|
// by Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP
|
|
// implementation to provide an additional safety check. PPP uses
|
|
// Z_SYNC_FLUSH
|
|
// but removes the length bytes of the resulting empty stored block. When
|
|
// decompressing, PPP checks that at the end of input packet, inflate is
|
|
// waiting for these length bytes.
|
|
that.inflateSyncPoint = function (z) {
|
|
if (!z || !z.istate || !z.istate.blocks)
|
|
return Z_STREAM_ERROR;
|
|
return z.istate.blocks.sync_point();
|
|
};
|
|
}
|
|
|
|
// ZStream
|
|
|
|
function ZStream() {
|
|
}
|
|
|
|
ZStream.prototype = {
|
|
inflateInit(bits) {
|
|
const that = this;
|
|
that.istate = new Inflate();
|
|
if (!bits)
|
|
bits = MAX_BITS;
|
|
return that.istate.inflateInit(that, bits);
|
|
},
|
|
|
|
inflate(f) {
|
|
const that = this;
|
|
if (!that.istate)
|
|
return Z_STREAM_ERROR;
|
|
return that.istate.inflate(that, f);
|
|
},
|
|
|
|
inflateEnd() {
|
|
const that = this;
|
|
if (!that.istate)
|
|
return Z_STREAM_ERROR;
|
|
const ret = that.istate.inflateEnd(that);
|
|
that.istate = null;
|
|
return ret;
|
|
},
|
|
|
|
inflateSync() {
|
|
const that = this;
|
|
if (!that.istate)
|
|
return Z_STREAM_ERROR;
|
|
return that.istate.inflateSync(that);
|
|
},
|
|
inflateSetDictionary(dictionary, dictLength) {
|
|
const that = this;
|
|
if (!that.istate)
|
|
return Z_STREAM_ERROR;
|
|
return that.istate.inflateSetDictionary(that, dictionary, dictLength);
|
|
},
|
|
read_byte(start) {
|
|
const that = this;
|
|
return that.next_in[start];
|
|
},
|
|
read_buf(start, size) {
|
|
const that = this;
|
|
return that.next_in.subarray(start, start + size);
|
|
}
|
|
};
|
|
|
|
// Inflater
|
|
|
|
function ZipInflate(options) {
|
|
const that = this;
|
|
const z = new ZStream();
|
|
const bufsize = options && options.chunkSize ? Math.floor(options.chunkSize * 2) : 128 * 1024;
|
|
const flush = Z_NO_FLUSH;
|
|
const buf = new Uint8Array(bufsize);
|
|
let nomoreinput = false;
|
|
|
|
z.inflateInit();
|
|
z.next_out = buf;
|
|
|
|
that.append = function (data, onprogress) {
|
|
const buffers = [];
|
|
let err, array, lastIndex = 0, bufferIndex = 0, bufferSize = 0;
|
|
if (data.length === 0)
|
|
return;
|
|
z.next_in_index = 0;
|
|
z.next_in = data;
|
|
z.avail_in = data.length;
|
|
do {
|
|
z.next_out_index = 0;
|
|
z.avail_out = bufsize;
|
|
if ((z.avail_in === 0) && (!nomoreinput)) { // if buffer is empty and more input is available, refill it
|
|
z.next_in_index = 0;
|
|
nomoreinput = true;
|
|
}
|
|
err = z.inflate(flush);
|
|
if (nomoreinput && (err === Z_BUF_ERROR)) {
|
|
if (z.avail_in !== 0)
|
|
throw new Error("inflating: bad input");
|
|
} else if (err !== Z_OK && err !== Z_STREAM_END)
|
|
throw new Error("inflating: " + z.msg);
|
|
if ((nomoreinput || err === Z_STREAM_END) && (z.avail_in === data.length))
|
|
throw new Error("inflating: bad input");
|
|
if (z.next_out_index)
|
|
if (z.next_out_index === bufsize)
|
|
buffers.push(new Uint8Array(buf));
|
|
else
|
|
buffers.push(buf.subarray(0, z.next_out_index));
|
|
bufferSize += z.next_out_index;
|
|
if (onprogress && z.next_in_index > 0 && z.next_in_index != lastIndex) {
|
|
onprogress(z.next_in_index);
|
|
lastIndex = z.next_in_index;
|
|
}
|
|
} while (z.avail_in > 0 || z.avail_out === 0);
|
|
if (buffers.length > 1) {
|
|
array = new Uint8Array(bufferSize);
|
|
buffers.forEach(function (chunk) {
|
|
array.set(chunk, bufferIndex);
|
|
bufferIndex += chunk.length;
|
|
});
|
|
} else {
|
|
array = buffers[0] ? new Uint8Array(buffers[0]) : new Uint8Array();
|
|
}
|
|
return array;
|
|
};
|
|
that.flush = function () {
|
|
z.inflateEnd();
|
|
};
|
|
}
|
|
|
|
/*
|
|
Copyright (c) 2022 Gildas Lormeau. All rights reserved.
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
modification, are permitted provided that the following conditions are met:
|
|
|
|
1. Redistributions of source code must retain the above copyright notice,
|
|
this list of conditions and the following disclaimer.
|
|
|
|
2. Redistributions in binary form must reproduce the above copyright
|
|
notice, this list of conditions and the following disclaimer in
|
|
the documentation and/or other materials provided with the distribution.
|
|
|
|
3. The names of the authors may not be used to endorse or promote products
|
|
derived from this software without specific prior written permission.
|
|
|
|
THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
|
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
|
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
|
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
|
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
const MAX_32_BITS = 0xffffffff;
|
|
const MAX_16_BITS = 0xffff;
|
|
const COMPRESSION_METHOD_DEFLATE = 0x08;
|
|
const COMPRESSION_METHOD_STORE = 0x00;
|
|
const COMPRESSION_METHOD_AES = 0x63;
|
|
|
|
const LOCAL_FILE_HEADER_SIGNATURE = 0x04034b50;
|
|
const SPLIT_ZIP_FILE_SIGNATURE = 0x08074b50;
|
|
const CENTRAL_FILE_HEADER_SIGNATURE = 0x02014b50;
|
|
const END_OF_CENTRAL_DIR_SIGNATURE = 0x06054b50;
|
|
const ZIP64_END_OF_CENTRAL_DIR_SIGNATURE = 0x06064b50;
|
|
const ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIGNATURE = 0x07064b50;
|
|
const END_OF_CENTRAL_DIR_LENGTH = 22;
|
|
const ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH = 20;
|
|
const ZIP64_END_OF_CENTRAL_DIR_LENGTH = 56;
|
|
|
|
const EXTRAFIELD_TYPE_ZIP64 = 0x0001;
|
|
const EXTRAFIELD_TYPE_AES = 0x9901;
|
|
const EXTRAFIELD_TYPE_NTFS = 0x000a;
|
|
const EXTRAFIELD_TYPE_NTFS_TAG1 = 0x0001;
|
|
const EXTRAFIELD_TYPE_EXTENDED_TIMESTAMP = 0x5455;
|
|
const EXTRAFIELD_TYPE_UNICODE_PATH = 0x7075;
|
|
const EXTRAFIELD_TYPE_UNICODE_COMMENT = 0x6375;
|
|
const EXTRAFIELD_TYPE_USDZ = 0x1986;
|
|
|
|
const BITFLAG_ENCRYPTED = 0x01;
|
|
const BITFLAG_LEVEL = 0x06;
|
|
const BITFLAG_DATA_DESCRIPTOR = 0x0008;
|
|
const BITFLAG_LANG_ENCODING_FLAG = 0x0800;
|
|
const FILE_ATTR_MSDOS_DIR_MASK = 0x10;
|
|
|
|
const DIRECTORY_SIGNATURE = "/";
|
|
|
|
const UNDEFINED_VALUE = undefined;
|
|
const UNDEFINED_TYPE = "undefined";
|
|
const FUNCTION_TYPE = "function";
|
|
|
|
/*
|
|
Copyright (c) 2022 Gildas Lormeau. All rights reserved.
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
modification, are permitted provided that the following conditions are met:
|
|
|
|
1. Redistributions of source code must retain the above copyright notice,
|
|
this list of conditions and the following disclaimer.
|
|
|
|
2. Redistributions in binary form must reproduce the above copyright
|
|
notice, this list of conditions and the following disclaimer in
|
|
the documentation and/or other materials provided with the distribution.
|
|
|
|
3. The names of the authors may not be used to endorse or promote products
|
|
derived from this software without specific prior written permission.
|
|
|
|
THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
|
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
|
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
|
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
|
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
class StreamAdapter {
|
|
|
|
constructor(Codec) {
|
|
return class extends TransformStream {
|
|
constructor(_format, options) {
|
|
const codec = new Codec(options);
|
|
super({
|
|
transform(chunk, controller) {
|
|
controller.enqueue(codec.append(chunk));
|
|
},
|
|
flush(controller) {
|
|
const chunk = codec.flush();
|
|
if (chunk) {
|
|
controller.enqueue(chunk);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
};
|
|
}
|
|
}
|
|
|
|
/*
|
|
Copyright (c) 2022 Gildas Lormeau. All rights reserved.
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
modification, are permitted provided that the following conditions are met:
|
|
|
|
1. Redistributions of source code must retain the above copyright notice,
|
|
this list of conditions and the following disclaimer.
|
|
|
|
2. Redistributions in binary form must reproduce the above copyright
|
|
notice, this list of conditions and the following disclaimer in
|
|
the documentation and/or other materials provided with the distribution.
|
|
|
|
3. The names of the authors may not be used to endorse or promote products
|
|
derived from this software without specific prior written permission.
|
|
|
|
THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
|
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
|
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
|
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
|
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
const MINIMUM_CHUNK_SIZE = 64;
|
|
let maxWorkers = 2;
|
|
try {
|
|
if (typeof navigator != UNDEFINED_TYPE && navigator.hardwareConcurrency) {
|
|
maxWorkers = navigator.hardwareConcurrency;
|
|
}
|
|
} catch (_error) {
|
|
// ignored
|
|
}
|
|
const DEFAULT_CONFIGURATION = {
|
|
chunkSize: 512 * 1024,
|
|
maxWorkers,
|
|
terminateWorkerTimeout: 5000,
|
|
useWebWorkers: true,
|
|
useCompressionStream: true,
|
|
workerScripts: UNDEFINED_VALUE,
|
|
CompressionStreamNative: typeof CompressionStream != UNDEFINED_TYPE && CompressionStream,
|
|
DecompressionStreamNative: typeof DecompressionStream != UNDEFINED_TYPE && DecompressionStream
|
|
};
|
|
|
|
const config = Object.assign({}, DEFAULT_CONFIGURATION);
|
|
|
|
function getConfiguration() {
|
|
return config;
|
|
}
|
|
|
|
function getChunkSize(config) {
|
|
return Math.max(config.chunkSize, MINIMUM_CHUNK_SIZE);
|
|
}
|
|
|
|
function configure(configuration) {
|
|
const {
|
|
baseURL,
|
|
chunkSize,
|
|
maxWorkers,
|
|
terminateWorkerTimeout,
|
|
useCompressionStream,
|
|
useWebWorkers,
|
|
Deflate,
|
|
Inflate,
|
|
CompressionStream,
|
|
DecompressionStream,
|
|
workerScripts
|
|
} = configuration;
|
|
setIfDefined("baseURL", baseURL);
|
|
setIfDefined("chunkSize", chunkSize);
|
|
setIfDefined("maxWorkers", maxWorkers);
|
|
setIfDefined("terminateWorkerTimeout", terminateWorkerTimeout);
|
|
setIfDefined("useCompressionStream", useCompressionStream);
|
|
setIfDefined("useWebWorkers", useWebWorkers);
|
|
if (Deflate) {
|
|
config.CompressionStream = new StreamAdapter(Deflate);
|
|
}
|
|
if (Inflate) {
|
|
config.DecompressionStream = new StreamAdapter(Inflate);
|
|
}
|
|
setIfDefined("CompressionStream", CompressionStream);
|
|
setIfDefined("DecompressionStream", DecompressionStream);
|
|
if (workerScripts !== UNDEFINED_VALUE) {
|
|
const { deflate, inflate } = workerScripts;
|
|
if (deflate || inflate) {
|
|
if (!config.workerScripts) {
|
|
config.workerScripts = {};
|
|
}
|
|
}
|
|
if (deflate) {
|
|
if (!Array.isArray(deflate)) {
|
|
throw new Error("workerScripts.deflate must be an array");
|
|
}
|
|
config.workerScripts.deflate = deflate;
|
|
}
|
|
if (inflate) {
|
|
if (!Array.isArray(inflate)) {
|
|
throw new Error("workerScripts.inflate must be an array");
|
|
}
|
|
config.workerScripts.inflate = inflate;
|
|
}
|
|
}
|
|
}
|
|
|
|
function setIfDefined(propertyName, propertyValue) {
|
|
if (propertyValue !== UNDEFINED_VALUE) {
|
|
config[propertyName] = propertyValue;
|
|
}
|
|
}
|
|
|
|
/*
|
|
Copyright (c) 2022 Gildas Lormeau. All rights reserved.
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
modification, are permitted provided that the following conditions are met:
|
|
|
|
1. Redistributions of source code must retain the above copyright notice,
|
|
this list of conditions and the following disclaimer.
|
|
|
|
2. Redistributions in binary form must reproduce the above copyright
|
|
notice, this list of conditions and the following disclaimer in
|
|
the documentation and/or other materials provided with the distribution.
|
|
|
|
3. The names of the authors may not be used to endorse or promote products
|
|
derived from this software without specific prior written permission.
|
|
|
|
THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
|
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
|
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
|
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
|
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
const table$1 = {
|
|
"application": {
|
|
"andrew-inset": "ez",
|
|
"annodex": "anx",
|
|
"atom+xml": "atom",
|
|
"atomcat+xml": "atomcat",
|
|
"atomserv+xml": "atomsrv",
|
|
"bbolin": "lin",
|
|
"cu-seeme": "cu",
|
|
"davmount+xml": "davmount",
|
|
"dsptype": "tsp",
|
|
"ecmascript": [
|
|
"es",
|
|
"ecma"
|
|
],
|
|
"futuresplash": "spl",
|
|
"hta": "hta",
|
|
"java-archive": "jar",
|
|
"java-serialized-object": "ser",
|
|
"java-vm": "class",
|
|
"m3g": "m3g",
|
|
"mac-binhex40": "hqx",
|
|
"mathematica": [
|
|
"nb",
|
|
"ma",
|
|
"mb"
|
|
],
|
|
"msaccess": "mdb",
|
|
"msword": [
|
|
"doc",
|
|
"dot",
|
|
"wiz"
|
|
],
|
|
"mxf": "mxf",
|
|
"oda": "oda",
|
|
"ogg": "ogx",
|
|
"pdf": "pdf",
|
|
"pgp-keys": "key",
|
|
"pgp-signature": [
|
|
"asc",
|
|
"sig"
|
|
],
|
|
"pics-rules": "prf",
|
|
"postscript": [
|
|
"ps",
|
|
"ai",
|
|
"eps",
|
|
"epsi",
|
|
"epsf",
|
|
"eps2",
|
|
"eps3"
|
|
],
|
|
"rar": "rar",
|
|
"rdf+xml": "rdf",
|
|
"rss+xml": "rss",
|
|
"rtf": "rtf",
|
|
"xhtml+xml": [
|
|
"xhtml",
|
|
"xht"
|
|
],
|
|
"xml": [
|
|
"xml",
|
|
"xsl",
|
|
"xsd",
|
|
"xpdl"
|
|
],
|
|
"xspf+xml": "xspf",
|
|
"zip": "zip",
|
|
"vnd.android.package-archive": "apk",
|
|
"vnd.cinderella": "cdy",
|
|
"vnd.google-earth.kml+xml": "kml",
|
|
"vnd.google-earth.kmz": "kmz",
|
|
"vnd.mozilla.xul+xml": "xul",
|
|
"vnd.ms-excel": [
|
|
"xls",
|
|
"xlb",
|
|
"xlt",
|
|
"xlm",
|
|
"xla",
|
|
"xlc",
|
|
"xlw"
|
|
],
|
|
"vnd.ms-pki.seccat": "cat",
|
|
"vnd.ms-pki.stl": "stl",
|
|
"vnd.ms-powerpoint": [
|
|
"ppt",
|
|
"pps",
|
|
"pot",
|
|
"ppa",
|
|
"pwz"
|
|
],
|
|
"vnd.oasis.opendocument.chart": "odc",
|
|
"vnd.oasis.opendocument.database": "odb",
|
|
"vnd.oasis.opendocument.formula": "odf",
|
|
"vnd.oasis.opendocument.graphics": "odg",
|
|
"vnd.oasis.opendocument.graphics-template": "otg",
|
|
"vnd.oasis.opendocument.image": "odi",
|
|
"vnd.oasis.opendocument.presentation": "odp",
|
|
"vnd.oasis.opendocument.presentation-template": "otp",
|
|
"vnd.oasis.opendocument.spreadsheet": "ods",
|
|
"vnd.oasis.opendocument.spreadsheet-template": "ots",
|
|
"vnd.oasis.opendocument.text": "odt",
|
|
"vnd.oasis.opendocument.text-master": [
|
|
"odm",
|
|
"otm"
|
|
],
|
|
"vnd.oasis.opendocument.text-template": "ott",
|
|
"vnd.oasis.opendocument.text-web": "oth",
|
|
"vnd.openxmlformats-officedocument.spreadsheetml.sheet": "xlsx",
|
|
"vnd.openxmlformats-officedocument.spreadsheetml.template": "xltx",
|
|
"vnd.openxmlformats-officedocument.presentationml.presentation": "pptx",
|
|
"vnd.openxmlformats-officedocument.presentationml.slideshow": "ppsx",
|
|
"vnd.openxmlformats-officedocument.presentationml.template": "potx",
|
|
"vnd.openxmlformats-officedocument.wordprocessingml.document": "docx",
|
|
"vnd.openxmlformats-officedocument.wordprocessingml.template": "dotx",
|
|
"vnd.smaf": "mmf",
|
|
"vnd.stardivision.calc": "sdc",
|
|
"vnd.stardivision.chart": "sds",
|
|
"vnd.stardivision.draw": "sda",
|
|
"vnd.stardivision.impress": "sdd",
|
|
"vnd.stardivision.math": [
|
|
"sdf",
|
|
"smf"
|
|
],
|
|
"vnd.stardivision.writer": [
|
|
"sdw",
|
|
"vor"
|
|
],
|
|
"vnd.stardivision.writer-global": "sgl",
|
|
"vnd.sun.xml.calc": "sxc",
|
|
"vnd.sun.xml.calc.template": "stc",
|
|
"vnd.sun.xml.draw": "sxd",
|
|
"vnd.sun.xml.draw.template": "std",
|
|
"vnd.sun.xml.impress": "sxi",
|
|
"vnd.sun.xml.impress.template": "sti",
|
|
"vnd.sun.xml.math": "sxm",
|
|
"vnd.sun.xml.writer": "sxw",
|
|
"vnd.sun.xml.writer.global": "sxg",
|
|
"vnd.sun.xml.writer.template": "stw",
|
|
"vnd.symbian.install": [
|
|
"sis",
|
|
"sisx"
|
|
],
|
|
"vnd.visio": [
|
|
"vsd",
|
|
"vst",
|
|
"vss",
|
|
"vsw",
|
|
"vsdx",
|
|
"vssx",
|
|
"vstx",
|
|
"vssm",
|
|
"vstm"
|
|
],
|
|
"vnd.wap.wbxml": "wbxml",
|
|
"vnd.wap.wmlc": "wmlc",
|
|
"vnd.wap.wmlscriptc": "wmlsc",
|
|
"vnd.wordperfect": "wpd",
|
|
"vnd.wordperfect5.1": "wp5",
|
|
"x-123": "wk",
|
|
"x-7z-compressed": "7z",
|
|
"x-abiword": "abw",
|
|
"x-apple-diskimage": "dmg",
|
|
"x-bcpio": "bcpio",
|
|
"x-bittorrent": "torrent",
|
|
"x-cbr": [
|
|
"cbr",
|
|
"cba",
|
|
"cbt",
|
|
"cb7"
|
|
],
|
|
"x-cbz": "cbz",
|
|
"x-cdf": [
|
|
"cdf",
|
|
"cda"
|
|
],
|
|
"x-cdlink": "vcd",
|
|
"x-chess-pgn": "pgn",
|
|
"x-cpio": "cpio",
|
|
"x-csh": "csh",
|
|
"x-director": [
|
|
"dir",
|
|
"dxr",
|
|
"cst",
|
|
"cct",
|
|
"cxt",
|
|
"w3d",
|
|
"fgd",
|
|
"swa"
|
|
],
|
|
"x-dms": "dms",
|
|
"x-doom": "wad",
|
|
"x-dvi": "dvi",
|
|
"x-httpd-eruby": "rhtml",
|
|
"x-font": "pcf.Z",
|
|
"x-freemind": "mm",
|
|
"x-gnumeric": "gnumeric",
|
|
"x-go-sgf": "sgf",
|
|
"x-graphing-calculator": "gcf",
|
|
"x-gtar": [
|
|
"gtar",
|
|
"taz"
|
|
],
|
|
"x-hdf": "hdf",
|
|
"x-httpd-php": [
|
|
"phtml",
|
|
"pht",
|
|
"php"
|
|
],
|
|
"x-httpd-php-source": "phps",
|
|
"x-httpd-php3": "php3",
|
|
"x-httpd-php3-preprocessed": "php3p",
|
|
"x-httpd-php4": "php4",
|
|
"x-httpd-php5": "php5",
|
|
"x-ica": "ica",
|
|
"x-info": "info",
|
|
"x-internet-signup": [
|
|
"ins",
|
|
"isp"
|
|
],
|
|
"x-iphone": "iii",
|
|
"x-iso9660-image": "iso",
|
|
"x-java-jnlp-file": "jnlp",
|
|
"x-jmol": "jmz",
|
|
"x-killustrator": "kil",
|
|
"x-latex": "latex",
|
|
"x-lyx": "lyx",
|
|
"x-lzx": "lzx",
|
|
"x-maker": [
|
|
"frm",
|
|
"fb",
|
|
"fbdoc"
|
|
],
|
|
"x-ms-wmd": "wmd",
|
|
"x-msdos-program": [
|
|
"com",
|
|
"exe",
|
|
"bat",
|
|
"dll"
|
|
],
|
|
"x-netcdf": [
|
|
"nc"
|
|
],
|
|
"x-ns-proxy-autoconfig": [
|
|
"pac",
|
|
"dat"
|
|
],
|
|
"x-nwc": "nwc",
|
|
"x-object": "o",
|
|
"x-oz-application": "oza",
|
|
"x-pkcs7-certreqresp": "p7r",
|
|
"x-python-code": [
|
|
"pyc",
|
|
"pyo"
|
|
],
|
|
"x-qgis": [
|
|
"qgs",
|
|
"shp",
|
|
"shx"
|
|
],
|
|
"x-quicktimeplayer": "qtl",
|
|
"x-redhat-package-manager": [
|
|
"rpm",
|
|
"rpa"
|
|
],
|
|
"x-ruby": "rb",
|
|
"x-sh": "sh",
|
|
"x-shar": "shar",
|
|
"x-shockwave-flash": [
|
|
"swf",
|
|
"swfl"
|
|
],
|
|
"x-silverlight": "scr",
|
|
"x-stuffit": "sit",
|
|
"x-sv4cpio": "sv4cpio",
|
|
"x-sv4crc": "sv4crc",
|
|
"x-tar": "tar",
|
|
"x-tex-gf": "gf",
|
|
"x-tex-pk": "pk",
|
|
"x-texinfo": [
|
|
"texinfo",
|
|
"texi"
|
|
],
|
|
"x-trash": [
|
|
"~",
|
|
"%",
|
|
"bak",
|
|
"old",
|
|
"sik"
|
|
],
|
|
"x-ustar": "ustar",
|
|
"x-wais-source": "src",
|
|
"x-wingz": "wz",
|
|
"x-x509-ca-cert": [
|
|
"crt",
|
|
"der",
|
|
"cer"
|
|
],
|
|
"x-xcf": "xcf",
|
|
"x-xfig": "fig",
|
|
"x-xpinstall": "xpi",
|
|
"applixware": "aw",
|
|
"atomsvc+xml": "atomsvc",
|
|
"ccxml+xml": "ccxml",
|
|
"cdmi-capability": "cdmia",
|
|
"cdmi-container": "cdmic",
|
|
"cdmi-domain": "cdmid",
|
|
"cdmi-object": "cdmio",
|
|
"cdmi-queue": "cdmiq",
|
|
"docbook+xml": "dbk",
|
|
"dssc+der": "dssc",
|
|
"dssc+xml": "xdssc",
|
|
"emma+xml": "emma",
|
|
"epub+zip": "epub",
|
|
"exi": "exi",
|
|
"font-tdpfr": "pfr",
|
|
"gml+xml": "gml",
|
|
"gpx+xml": "gpx",
|
|
"gxf": "gxf",
|
|
"hyperstudio": "stk",
|
|
"inkml+xml": [
|
|
"ink",
|
|
"inkml"
|
|
],
|
|
"ipfix": "ipfix",
|
|
"jsonml+json": "jsonml",
|
|
"lost+xml": "lostxml",
|
|
"mads+xml": "mads",
|
|
"marc": "mrc",
|
|
"marcxml+xml": "mrcx",
|
|
"mathml+xml": [
|
|
"mathml",
|
|
"mml"
|
|
],
|
|
"mbox": "mbox",
|
|
"mediaservercontrol+xml": "mscml",
|
|
"metalink+xml": "metalink",
|
|
"metalink4+xml": "meta4",
|
|
"mets+xml": "mets",
|
|
"mods+xml": "mods",
|
|
"mp21": [
|
|
"m21",
|
|
"mp21"
|
|
],
|
|
"mp4": "mp4s",
|
|
"oebps-package+xml": "opf",
|
|
"omdoc+xml": "omdoc",
|
|
"onenote": [
|
|
"onetoc",
|
|
"onetoc2",
|
|
"onetmp",
|
|
"onepkg"
|
|
],
|
|
"oxps": "oxps",
|
|
"patch-ops-error+xml": "xer",
|
|
"pgp-encrypted": "pgp",
|
|
"pkcs10": "p10",
|
|
"pkcs7-mime": [
|
|
"p7m",
|
|
"p7c"
|
|
],
|
|
"pkcs7-signature": "p7s",
|
|
"pkcs8": "p8",
|
|
"pkix-attr-cert": "ac",
|
|
"pkix-crl": "crl",
|
|
"pkix-pkipath": "pkipath",
|
|
"pkixcmp": "pki",
|
|
"pls+xml": "pls",
|
|
"prs.cww": "cww",
|
|
"pskc+xml": "pskcxml",
|
|
"reginfo+xml": "rif",
|
|
"relax-ng-compact-syntax": "rnc",
|
|
"resource-lists+xml": "rl",
|
|
"resource-lists-diff+xml": "rld",
|
|
"rls-services+xml": "rs",
|
|
"rpki-ghostbusters": "gbr",
|
|
"rpki-manifest": "mft",
|
|
"rpki-roa": "roa",
|
|
"rsd+xml": "rsd",
|
|
"sbml+xml": "sbml",
|
|
"scvp-cv-request": "scq",
|
|
"scvp-cv-response": "scs",
|
|
"scvp-vp-request": "spq",
|
|
"scvp-vp-response": "spp",
|
|
"sdp": "sdp",
|
|
"set-payment-initiation": "setpay",
|
|
"set-registration-initiation": "setreg",
|
|
"shf+xml": "shf",
|
|
"sparql-query": "rq",
|
|
"sparql-results+xml": "srx",
|
|
"srgs": "gram",
|
|
"srgs+xml": "grxml",
|
|
"sru+xml": "sru",
|
|
"ssdl+xml": "ssdl",
|
|
"ssml+xml": "ssml",
|
|
"tei+xml": [
|
|
"tei",
|
|
"teicorpus"
|
|
],
|
|
"thraud+xml": "tfi",
|
|
"timestamped-data": "tsd",
|
|
"vnd.3gpp.pic-bw-large": "plb",
|
|
"vnd.3gpp.pic-bw-small": "psb",
|
|
"vnd.3gpp.pic-bw-var": "pvb",
|
|
"vnd.3gpp2.tcap": "tcap",
|
|
"vnd.3m.post-it-notes": "pwn",
|
|
"vnd.accpac.simply.aso": "aso",
|
|
"vnd.accpac.simply.imp": "imp",
|
|
"vnd.acucobol": "acu",
|
|
"vnd.acucorp": [
|
|
"atc",
|
|
"acutc"
|
|
],
|
|
"vnd.adobe.air-application-installer-package+zip": "air",
|
|
"vnd.adobe.formscentral.fcdt": "fcdt",
|
|
"vnd.adobe.fxp": [
|
|
"fxp",
|
|
"fxpl"
|
|
],
|
|
"vnd.adobe.xdp+xml": "xdp",
|
|
"vnd.adobe.xfdf": "xfdf",
|
|
"vnd.ahead.space": "ahead",
|
|
"vnd.airzip.filesecure.azf": "azf",
|
|
"vnd.airzip.filesecure.azs": "azs",
|
|
"vnd.amazon.ebook": "azw",
|
|
"vnd.americandynamics.acc": "acc",
|
|
"vnd.amiga.ami": "ami",
|
|
"vnd.anser-web-certificate-issue-initiation": "cii",
|
|
"vnd.anser-web-funds-transfer-initiation": "fti",
|
|
"vnd.antix.game-component": "atx",
|
|
"vnd.apple.installer+xml": "mpkg",
|
|
"vnd.apple.mpegurl": "m3u8",
|
|
"vnd.aristanetworks.swi": "swi",
|
|
"vnd.astraea-software.iota": "iota",
|
|
"vnd.audiograph": "aep",
|
|
"vnd.blueice.multipass": "mpm",
|
|
"vnd.bmi": "bmi",
|
|
"vnd.businessobjects": "rep",
|
|
"vnd.chemdraw+xml": "cdxml",
|
|
"vnd.chipnuts.karaoke-mmd": "mmd",
|
|
"vnd.claymore": "cla",
|
|
"vnd.cloanto.rp9": "rp9",
|
|
"vnd.clonk.c4group": [
|
|
"c4g",
|
|
"c4d",
|
|
"c4f",
|
|
"c4p",
|
|
"c4u"
|
|
],
|
|
"vnd.cluetrust.cartomobile-config": "c11amc",
|
|
"vnd.cluetrust.cartomobile-config-pkg": "c11amz",
|
|
"vnd.commonspace": "csp",
|
|
"vnd.contact.cmsg": "cdbcmsg",
|
|
"vnd.cosmocaller": "cmc",
|
|
"vnd.crick.clicker": "clkx",
|
|
"vnd.crick.clicker.keyboard": "clkk",
|
|
"vnd.crick.clicker.palette": "clkp",
|
|
"vnd.crick.clicker.template": "clkt",
|
|
"vnd.crick.clicker.wordbank": "clkw",
|
|
"vnd.criticaltools.wbs+xml": "wbs",
|
|
"vnd.ctc-posml": "pml",
|
|
"vnd.cups-ppd": "ppd",
|
|
"vnd.curl.car": "car",
|
|
"vnd.curl.pcurl": "pcurl",
|
|
"vnd.dart": "dart",
|
|
"vnd.data-vision.rdz": "rdz",
|
|
"vnd.dece.data": [
|
|
"uvf",
|
|
"uvvf",
|
|
"uvd",
|
|
"uvvd"
|
|
],
|
|
"vnd.dece.ttml+xml": [
|
|
"uvt",
|
|
"uvvt"
|
|
],
|
|
"vnd.dece.unspecified": [
|
|
"uvx",
|
|
"uvvx"
|
|
],
|
|
"vnd.dece.zip": [
|
|
"uvz",
|
|
"uvvz"
|
|
],
|
|
"vnd.denovo.fcselayout-link": "fe_launch",
|
|
"vnd.dna": "dna",
|
|
"vnd.dolby.mlp": "mlp",
|
|
"vnd.dpgraph": "dpg",
|
|
"vnd.dreamfactory": "dfac",
|
|
"vnd.ds-keypoint": "kpxx",
|
|
"vnd.dvb.ait": "ait",
|
|
"vnd.dvb.service": "svc",
|
|
"vnd.dynageo": "geo",
|
|
"vnd.ecowin.chart": "mag",
|
|
"vnd.enliven": "nml",
|
|
"vnd.epson.esf": "esf",
|
|
"vnd.epson.msf": "msf",
|
|
"vnd.epson.quickanime": "qam",
|
|
"vnd.epson.salt": "slt",
|
|
"vnd.epson.ssf": "ssf",
|
|
"vnd.eszigno3+xml": [
|
|
"es3",
|
|
"et3"
|
|
],
|
|
"vnd.ezpix-album": "ez2",
|
|
"vnd.ezpix-package": "ez3",
|
|
"vnd.fdf": "fdf",
|
|
"vnd.fdsn.mseed": "mseed",
|
|
"vnd.fdsn.seed": [
|
|
"seed",
|
|
"dataless"
|
|
],
|
|
"vnd.flographit": "gph",
|
|
"vnd.fluxtime.clip": "ftc",
|
|
"vnd.framemaker": [
|
|
"fm",
|
|
"frame",
|
|
"maker",
|
|
"book"
|
|
],
|
|
"vnd.frogans.fnc": "fnc",
|
|
"vnd.frogans.ltf": "ltf",
|
|
"vnd.fsc.weblaunch": "fsc",
|
|
"vnd.fujitsu.oasys": "oas",
|
|
"vnd.fujitsu.oasys2": "oa2",
|
|
"vnd.fujitsu.oasys3": "oa3",
|
|
"vnd.fujitsu.oasysgp": "fg5",
|
|
"vnd.fujitsu.oasysprs": "bh2",
|
|
"vnd.fujixerox.ddd": "ddd",
|
|
"vnd.fujixerox.docuworks": "xdw",
|
|
"vnd.fujixerox.docuworks.binder": "xbd",
|
|
"vnd.fuzzysheet": "fzs",
|
|
"vnd.genomatix.tuxedo": "txd",
|
|
"vnd.geogebra.file": "ggb",
|
|
"vnd.geogebra.tool": "ggt",
|
|
"vnd.geometry-explorer": [
|
|
"gex",
|
|
"gre"
|
|
],
|
|
"vnd.geonext": "gxt",
|
|
"vnd.geoplan": "g2w",
|
|
"vnd.geospace": "g3w",
|
|
"vnd.gmx": "gmx",
|
|
"vnd.grafeq": [
|
|
"gqf",
|
|
"gqs"
|
|
],
|
|
"vnd.groove-account": "gac",
|
|
"vnd.groove-help": "ghf",
|
|
"vnd.groove-identity-message": "gim",
|
|
"vnd.groove-injector": "grv",
|
|
"vnd.groove-tool-message": "gtm",
|
|
"vnd.groove-tool-template": "tpl",
|
|
"vnd.groove-vcard": "vcg",
|
|
"vnd.hal+xml": "hal",
|
|
"vnd.handheld-entertainment+xml": "zmm",
|
|
"vnd.hbci": "hbci",
|
|
"vnd.hhe.lesson-player": "les",
|
|
"vnd.hp-hpgl": "hpgl",
|
|
"vnd.hp-hpid": "hpid",
|
|
"vnd.hp-hps": "hps",
|
|
"vnd.hp-jlyt": "jlt",
|
|
"vnd.hp-pcl": "pcl",
|
|
"vnd.hp-pclxl": "pclxl",
|
|
"vnd.hydrostatix.sof-data": "sfd-hdstx",
|
|
"vnd.ibm.minipay": "mpy",
|
|
"vnd.ibm.modcap": [
|
|
"afp",
|
|
"listafp",
|
|
"list3820"
|
|
],
|
|
"vnd.ibm.rights-management": "irm",
|
|
"vnd.ibm.secure-container": "sc",
|
|
"vnd.iccprofile": [
|
|
"icc",
|
|
"icm"
|
|
],
|
|
"vnd.igloader": "igl",
|
|
"vnd.immervision-ivp": "ivp",
|
|
"vnd.immervision-ivu": "ivu",
|
|
"vnd.insors.igm": "igm",
|
|
"vnd.intercon.formnet": [
|
|
"xpw",
|
|
"xpx"
|
|
],
|
|
"vnd.intergeo": "i2g",
|
|
"vnd.intu.qbo": "qbo",
|
|
"vnd.intu.qfx": "qfx",
|
|
"vnd.ipunplugged.rcprofile": "rcprofile",
|
|
"vnd.irepository.package+xml": "irp",
|
|
"vnd.is-xpr": "xpr",
|
|
"vnd.isac.fcs": "fcs",
|
|
"vnd.jam": "jam",
|
|
"vnd.jcp.javame.midlet-rms": "rms",
|
|
"vnd.jisp": "jisp",
|
|
"vnd.joost.joda-archive": "joda",
|
|
"vnd.kahootz": [
|
|
"ktz",
|
|
"ktr"
|
|
],
|
|
"vnd.kde.karbon": "karbon",
|
|
"vnd.kde.kchart": "chrt",
|
|
"vnd.kde.kformula": "kfo",
|
|
"vnd.kde.kivio": "flw",
|
|
"vnd.kde.kontour": "kon",
|
|
"vnd.kde.kpresenter": [
|
|
"kpr",
|
|
"kpt"
|
|
],
|
|
"vnd.kde.kspread": "ksp",
|
|
"vnd.kde.kword": [
|
|
"kwd",
|
|
"kwt"
|
|
],
|
|
"vnd.kenameaapp": "htke",
|
|
"vnd.kidspiration": "kia",
|
|
"vnd.kinar": [
|
|
"kne",
|
|
"knp"
|
|
],
|
|
"vnd.koan": [
|
|
"skp",
|
|
"skd",
|
|
"skt",
|
|
"skm"
|
|
],
|
|
"vnd.kodak-descriptor": "sse",
|
|
"vnd.las.las+xml": "lasxml",
|
|
"vnd.llamagraphics.life-balance.desktop": "lbd",
|
|
"vnd.llamagraphics.life-balance.exchange+xml": "lbe",
|
|
"vnd.lotus-1-2-3": "123",
|
|
"vnd.lotus-approach": "apr",
|
|
"vnd.lotus-freelance": "pre",
|
|
"vnd.lotus-notes": "nsf",
|
|
"vnd.lotus-organizer": "org",
|
|
"vnd.lotus-screencam": "scm",
|
|
"vnd.lotus-wordpro": "lwp",
|
|
"vnd.macports.portpkg": "portpkg",
|
|
"vnd.mcd": "mcd",
|
|
"vnd.medcalcdata": "mc1",
|
|
"vnd.mediastation.cdkey": "cdkey",
|
|
"vnd.mfer": "mwf",
|
|
"vnd.mfmp": "mfm",
|
|
"vnd.micrografx.flo": "flo",
|
|
"vnd.micrografx.igx": "igx",
|
|
"vnd.mif": "mif",
|
|
"vnd.mobius.daf": "daf",
|
|
"vnd.mobius.dis": "dis",
|
|
"vnd.mobius.mbk": "mbk",
|
|
"vnd.mobius.mqy": "mqy",
|
|
"vnd.mobius.msl": "msl",
|
|
"vnd.mobius.plc": "plc",
|
|
"vnd.mobius.txf": "txf",
|
|
"vnd.mophun.application": "mpn",
|
|
"vnd.mophun.certificate": "mpc",
|
|
"vnd.ms-artgalry": "cil",
|
|
"vnd.ms-cab-compressed": "cab",
|
|
"vnd.ms-excel.addin.macroenabled.12": "xlam",
|
|
"vnd.ms-excel.sheet.binary.macroenabled.12": "xlsb",
|
|
"vnd.ms-excel.sheet.macroenabled.12": "xlsm",
|
|
"vnd.ms-excel.template.macroenabled.12": "xltm",
|
|
"vnd.ms-fontobject": "eot",
|
|
"vnd.ms-htmlhelp": "chm",
|
|
"vnd.ms-ims": "ims",
|
|
"vnd.ms-lrm": "lrm",
|
|
"vnd.ms-officetheme": "thmx",
|
|
"vnd.ms-powerpoint.addin.macroenabled.12": "ppam",
|
|
"vnd.ms-powerpoint.presentation.macroenabled.12": "pptm",
|
|
"vnd.ms-powerpoint.slide.macroenabled.12": "sldm",
|
|
"vnd.ms-powerpoint.slideshow.macroenabled.12": "ppsm",
|
|
"vnd.ms-powerpoint.template.macroenabled.12": "potm",
|
|
"vnd.ms-project": [
|
|
"mpp",
|
|
"mpt"
|
|
],
|
|
"vnd.ms-word.document.macroenabled.12": "docm",
|
|
"vnd.ms-word.template.macroenabled.12": "dotm",
|
|
"vnd.ms-works": [
|
|
"wps",
|
|
"wks",
|
|
"wcm",
|
|
"wdb"
|
|
],
|
|
"vnd.ms-wpl": "wpl",
|
|
"vnd.ms-xpsdocument": "xps",
|
|
"vnd.mseq": "mseq",
|
|
"vnd.musician": "mus",
|
|
"vnd.muvee.style": "msty",
|
|
"vnd.mynfc": "taglet",
|
|
"vnd.neurolanguage.nlu": "nlu",
|
|
"vnd.nitf": [
|
|
"ntf",
|
|
"nitf"
|
|
],
|
|
"vnd.noblenet-directory": "nnd",
|
|
"vnd.noblenet-sealer": "nns",
|
|
"vnd.noblenet-web": "nnw",
|
|
"vnd.nokia.n-gage.data": "ngdat",
|
|
"vnd.nokia.n-gage.symbian.install": "n-gage",
|
|
"vnd.nokia.radio-preset": "rpst",
|
|
"vnd.nokia.radio-presets": "rpss",
|
|
"vnd.novadigm.edm": "edm",
|
|
"vnd.novadigm.edx": "edx",
|
|
"vnd.novadigm.ext": "ext",
|
|
"vnd.oasis.opendocument.chart-template": "otc",
|
|
"vnd.oasis.opendocument.formula-template": "odft",
|
|
"vnd.oasis.opendocument.image-template": "oti",
|
|
"vnd.olpc-sugar": "xo",
|
|
"vnd.oma.dd2+xml": "dd2",
|
|
"vnd.openofficeorg.extension": "oxt",
|
|
"vnd.openxmlformats-officedocument.presentationml.slide": "sldx",
|
|
"vnd.osgeo.mapguide.package": "mgp",
|
|
"vnd.osgi.dp": "dp",
|
|
"vnd.osgi.subsystem": "esa",
|
|
"vnd.palm": [
|
|
"pdb",
|
|
"pqa",
|
|
"oprc"
|
|
],
|
|
"vnd.pawaafile": "paw",
|
|
"vnd.pg.format": "str",
|
|
"vnd.pg.osasli": "ei6",
|
|
"vnd.picsel": "efif",
|
|
"vnd.pmi.widget": "wg",
|
|
"vnd.pocketlearn": "plf",
|
|
"vnd.powerbuilder6": "pbd",
|
|
"vnd.previewsystems.box": "box",
|
|
"vnd.proteus.magazine": "mgz",
|
|
"vnd.publishare-delta-tree": "qps",
|
|
"vnd.pvi.ptid1": "ptid",
|
|
"vnd.quark.quarkxpress": [
|
|
"qxd",
|
|
"qxt",
|
|
"qwd",
|
|
"qwt",
|
|
"qxl",
|
|
"qxb"
|
|
],
|
|
"vnd.realvnc.bed": "bed",
|
|
"vnd.recordare.musicxml": "mxl",
|
|
"vnd.recordare.musicxml+xml": "musicxml",
|
|
"vnd.rig.cryptonote": "cryptonote",
|
|
"vnd.rn-realmedia": "rm",
|
|
"vnd.rn-realmedia-vbr": "rmvb",
|
|
"vnd.route66.link66+xml": "link66",
|
|
"vnd.sailingtracker.track": "st",
|
|
"vnd.seemail": "see",
|
|
"vnd.sema": "sema",
|
|
"vnd.semd": "semd",
|
|
"vnd.semf": "semf",
|
|
"vnd.shana.informed.formdata": "ifm",
|
|
"vnd.shana.informed.formtemplate": "itp",
|
|
"vnd.shana.informed.interchange": "iif",
|
|
"vnd.shana.informed.package": "ipk",
|
|
"vnd.simtech-mindmapper": [
|
|
"twd",
|
|
"twds"
|
|
],
|
|
"vnd.smart.teacher": "teacher",
|
|
"vnd.solent.sdkm+xml": [
|
|
"sdkm",
|
|
"sdkd"
|
|
],
|
|
"vnd.spotfire.dxp": "dxp",
|
|
"vnd.spotfire.sfs": "sfs",
|
|
"vnd.stepmania.package": "smzip",
|
|
"vnd.stepmania.stepchart": "sm",
|
|
"vnd.sus-calendar": [
|
|
"sus",
|
|
"susp"
|
|
],
|
|
"vnd.svd": "svd",
|
|
"vnd.syncml+xml": "xsm",
|
|
"vnd.syncml.dm+wbxml": "bdm",
|
|
"vnd.syncml.dm+xml": "xdm",
|
|
"vnd.tao.intent-module-archive": "tao",
|
|
"vnd.tcpdump.pcap": [
|
|
"pcap",
|
|
"cap",
|
|
"dmp"
|
|
],
|
|
"vnd.tmobile-livetv": "tmo",
|
|
"vnd.trid.tpt": "tpt",
|
|
"vnd.triscape.mxs": "mxs",
|
|
"vnd.trueapp": "tra",
|
|
"vnd.ufdl": [
|
|
"ufd",
|
|
"ufdl"
|
|
],
|
|
"vnd.uiq.theme": "utz",
|
|
"vnd.umajin": "umj",
|
|
"vnd.unity": "unityweb",
|
|
"vnd.uoml+xml": "uoml",
|
|
"vnd.vcx": "vcx",
|
|
"vnd.visionary": "vis",
|
|
"vnd.vsf": "vsf",
|
|
"vnd.webturbo": "wtb",
|
|
"vnd.wolfram.player": "nbp",
|
|
"vnd.wqd": "wqd",
|
|
"vnd.wt.stf": "stf",
|
|
"vnd.xara": "xar",
|
|
"vnd.xfdl": "xfdl",
|
|
"vnd.yamaha.hv-dic": "hvd",
|
|
"vnd.yamaha.hv-script": "hvs",
|
|
"vnd.yamaha.hv-voice": "hvp",
|
|
"vnd.yamaha.openscoreformat": "osf",
|
|
"vnd.yamaha.openscoreformat.osfpvg+xml": "osfpvg",
|
|
"vnd.yamaha.smaf-audio": "saf",
|
|
"vnd.yamaha.smaf-phrase": "spf",
|
|
"vnd.yellowriver-custom-menu": "cmp",
|
|
"vnd.zul": [
|
|
"zir",
|
|
"zirz"
|
|
],
|
|
"vnd.zzazz.deck+xml": "zaz",
|
|
"voicexml+xml": "vxml",
|
|
"widget": "wgt",
|
|
"winhlp": "hlp",
|
|
"wsdl+xml": "wsdl",
|
|
"wspolicy+xml": "wspolicy",
|
|
"x-ace-compressed": "ace",
|
|
"x-authorware-bin": [
|
|
"aab",
|
|
"x32",
|
|
"u32",
|
|
"vox"
|
|
],
|
|
"x-authorware-map": "aam",
|
|
"x-authorware-seg": "aas",
|
|
"x-blorb": [
|
|
"blb",
|
|
"blorb"
|
|
],
|
|
"x-bzip": "bz",
|
|
"x-bzip2": [
|
|
"bz2",
|
|
"boz"
|
|
],
|
|
"x-cfs-compressed": "cfs",
|
|
"x-chat": "chat",
|
|
"x-conference": "nsc",
|
|
"x-dgc-compressed": "dgc",
|
|
"x-dtbncx+xml": "ncx",
|
|
"x-dtbook+xml": "dtb",
|
|
"x-dtbresource+xml": "res",
|
|
"x-eva": "eva",
|
|
"x-font-bdf": "bdf",
|
|
"x-font-ghostscript": "gsf",
|
|
"x-font-linux-psf": "psf",
|
|
"x-font-pcf": "pcf",
|
|
"x-font-snf": "snf",
|
|
"x-font-ttf": [
|
|
"ttf",
|
|
"ttc"
|
|
],
|
|
"x-font-type1": [
|
|
"pfa",
|
|
"pfb",
|
|
"pfm",
|
|
"afm"
|
|
],
|
|
"x-freearc": "arc",
|
|
"x-gca-compressed": "gca",
|
|
"x-glulx": "ulx",
|
|
"x-gramps-xml": "gramps",
|
|
"x-install-instructions": "install",
|
|
"x-lzh-compressed": [
|
|
"lzh",
|
|
"lha"
|
|
],
|
|
"x-mie": "mie",
|
|
"x-mobipocket-ebook": [
|
|
"prc",
|
|
"mobi"
|
|
],
|
|
"x-ms-application": "application",
|
|
"x-ms-shortcut": "lnk",
|
|
"x-ms-xbap": "xbap",
|
|
"x-msbinder": "obd",
|
|
"x-mscardfile": "crd",
|
|
"x-msclip": "clp",
|
|
"application/x-ms-installer": "msi",
|
|
"x-msmediaview": [
|
|
"mvb",
|
|
"m13",
|
|
"m14"
|
|
],
|
|
"x-msmetafile": [
|
|
"wmf",
|
|
"wmz",
|
|
"emf",
|
|
"emz"
|
|
],
|
|
"x-msmoney": "mny",
|
|
"x-mspublisher": "pub",
|
|
"x-msschedule": "scd",
|
|
"x-msterminal": "trm",
|
|
"x-mswrite": "wri",
|
|
"x-nzb": "nzb",
|
|
"x-pkcs12": [
|
|
"p12",
|
|
"pfx"
|
|
],
|
|
"x-pkcs7-certificates": [
|
|
"p7b",
|
|
"spc"
|
|
],
|
|
"x-research-info-systems": "ris",
|
|
"x-silverlight-app": "xap",
|
|
"x-sql": "sql",
|
|
"x-stuffitx": "sitx",
|
|
"x-subrip": "srt",
|
|
"x-t3vm-image": "t3",
|
|
"x-tex-tfm": "tfm",
|
|
"x-tgif": "obj",
|
|
"x-xliff+xml": "xlf",
|
|
"x-xz": "xz",
|
|
"x-zmachine": [
|
|
"z1",
|
|
"z2",
|
|
"z3",
|
|
"z4",
|
|
"z5",
|
|
"z6",
|
|
"z7",
|
|
"z8"
|
|
],
|
|
"xaml+xml": "xaml",
|
|
"xcap-diff+xml": "xdf",
|
|
"xenc+xml": "xenc",
|
|
"xml-dtd": "dtd",
|
|
"xop+xml": "xop",
|
|
"xproc+xml": "xpl",
|
|
"xslt+xml": "xslt",
|
|
"xv+xml": [
|
|
"mxml",
|
|
"xhvml",
|
|
"xvml",
|
|
"xvm"
|
|
],
|
|
"yang": "yang",
|
|
"yin+xml": "yin",
|
|
"envoy": "evy",
|
|
"fractals": "fif",
|
|
"internet-property-stream": "acx",
|
|
"olescript": "axs",
|
|
"vnd.ms-outlook": "msg",
|
|
"vnd.ms-pkicertstore": "sst",
|
|
"x-compress": "z",
|
|
"x-perfmon": [
|
|
"pma",
|
|
"pmc",
|
|
"pmr",
|
|
"pmw"
|
|
],
|
|
"ynd.ms-pkipko": "pko",
|
|
"gzip": [
|
|
"gz",
|
|
"tgz"
|
|
],
|
|
"smil+xml": [
|
|
"smi",
|
|
"smil"
|
|
],
|
|
"vnd.debian.binary-package": [
|
|
"deb",
|
|
"udeb"
|
|
],
|
|
"vnd.hzn-3d-crossword": "x3d",
|
|
"vnd.sqlite3": [
|
|
"db",
|
|
"sqlite",
|
|
"sqlite3",
|
|
"db-wal",
|
|
"sqlite-wal",
|
|
"db-shm",
|
|
"sqlite-shm"
|
|
],
|
|
"vnd.wap.sic": "sic",
|
|
"vnd.wap.slc": "slc",
|
|
"x-krita": [
|
|
"kra",
|
|
"krz"
|
|
],
|
|
"x-perl": [
|
|
"pm",
|
|
"pl"
|
|
],
|
|
"yaml": [
|
|
"yaml",
|
|
"yml"
|
|
]
|
|
},
|
|
"audio": {
|
|
"amr": "amr",
|
|
"amr-wb": "awb",
|
|
"annodex": "axa",
|
|
"basic": [
|
|
"au",
|
|
"snd"
|
|
],
|
|
"flac": "flac",
|
|
"midi": [
|
|
"mid",
|
|
"midi",
|
|
"kar",
|
|
"rmi"
|
|
],
|
|
"mpeg": [
|
|
"mpga",
|
|
"mpega",
|
|
"mp3",
|
|
"m4a",
|
|
"mp2a",
|
|
"m2a",
|
|
"m3a"
|
|
],
|
|
"mpegurl": "m3u",
|
|
"ogg": [
|
|
"oga",
|
|
"ogg",
|
|
"spx"
|
|
],
|
|
"prs.sid": "sid",
|
|
"x-aiff": "aifc",
|
|
"x-gsm": "gsm",
|
|
"x-ms-wma": "wma",
|
|
"x-ms-wax": "wax",
|
|
"x-pn-realaudio": "ram",
|
|
"x-realaudio": "ra",
|
|
"x-sd2": "sd2",
|
|
"adpcm": "adp",
|
|
"mp4": "mp4a",
|
|
"s3m": "s3m",
|
|
"silk": "sil",
|
|
"vnd.dece.audio": [
|
|
"uva",
|
|
"uvva"
|
|
],
|
|
"vnd.digital-winds": "eol",
|
|
"vnd.dra": "dra",
|
|
"vnd.dts": "dts",
|
|
"vnd.dts.hd": "dtshd",
|
|
"vnd.lucent.voice": "lvp",
|
|
"vnd.ms-playready.media.pya": "pya",
|
|
"vnd.nuera.ecelp4800": "ecelp4800",
|
|
"vnd.nuera.ecelp7470": "ecelp7470",
|
|
"vnd.nuera.ecelp9600": "ecelp9600",
|
|
"vnd.rip": "rip",
|
|
"webm": "weba",
|
|
"x-caf": "caf",
|
|
"x-matroska": "mka",
|
|
"x-pn-realaudio-plugin": "rmp",
|
|
"xm": "xm",
|
|
"aac": "aac",
|
|
"aiff": [
|
|
"aiff",
|
|
"aif",
|
|
"aff"
|
|
],
|
|
"opus": "opus",
|
|
"wav": "wav"
|
|
},
|
|
"chemical": {
|
|
"x-alchemy": "alc",
|
|
"x-cache": [
|
|
"cac",
|
|
"cache"
|
|
],
|
|
"x-cache-csf": "csf",
|
|
"x-cactvs-binary": [
|
|
"cbin",
|
|
"cascii",
|
|
"ctab"
|
|
],
|
|
"x-cdx": "cdx",
|
|
"x-chem3d": "c3d",
|
|
"x-cif": "cif",
|
|
"x-cmdf": "cmdf",
|
|
"x-cml": "cml",
|
|
"x-compass": "cpa",
|
|
"x-crossfire": "bsd",
|
|
"x-csml": [
|
|
"csml",
|
|
"csm"
|
|
],
|
|
"x-ctx": "ctx",
|
|
"x-cxf": [
|
|
"cxf",
|
|
"cef"
|
|
],
|
|
"x-embl-dl-nucleotide": [
|
|
"emb",
|
|
"embl"
|
|
],
|
|
"x-gamess-input": [
|
|
"inp",
|
|
"gam",
|
|
"gamin"
|
|
],
|
|
"x-gaussian-checkpoint": [
|
|
"fch",
|
|
"fchk"
|
|
],
|
|
"x-gaussian-cube": "cub",
|
|
"x-gaussian-input": [
|
|
"gau",
|
|
"gjc",
|
|
"gjf"
|
|
],
|
|
"x-gaussian-log": "gal",
|
|
"x-gcg8-sequence": "gcg",
|
|
"x-genbank": "gen",
|
|
"x-hin": "hin",
|
|
"x-isostar": [
|
|
"istr",
|
|
"ist"
|
|
],
|
|
"x-jcamp-dx": [
|
|
"jdx",
|
|
"dx"
|
|
],
|
|
"x-kinemage": "kin",
|
|
"x-macmolecule": "mcm",
|
|
"x-macromodel-input": "mmod",
|
|
"x-mdl-molfile": "mol",
|
|
"x-mdl-rdfile": "rd",
|
|
"x-mdl-rxnfile": "rxn",
|
|
"x-mdl-sdfile": "sd",
|
|
"x-mdl-tgf": "tgf",
|
|
"x-mmcif": "mcif",
|
|
"x-mol2": "mol2",
|
|
"x-molconn-Z": "b",
|
|
"x-mopac-graph": "gpt",
|
|
"x-mopac-input": [
|
|
"mop",
|
|
"mopcrt",
|
|
"zmt"
|
|
],
|
|
"x-mopac-out": "moo",
|
|
"x-ncbi-asn1": "asn",
|
|
"x-ncbi-asn1-ascii": [
|
|
"prt",
|
|
"ent"
|
|
],
|
|
"x-ncbi-asn1-binary": "val",
|
|
"x-rosdal": "ros",
|
|
"x-swissprot": "sw",
|
|
"x-vamas-iso14976": "vms",
|
|
"x-vmd": "vmd",
|
|
"x-xtel": "xtel",
|
|
"x-xyz": "xyz"
|
|
},
|
|
"font": {
|
|
"otf": "otf",
|
|
"woff": "woff",
|
|
"woff2": "woff2"
|
|
},
|
|
"image": {
|
|
"gif": "gif",
|
|
"ief": "ief",
|
|
"jpeg": [
|
|
"jpeg",
|
|
"jpg",
|
|
"jpe",
|
|
"jfif",
|
|
"jfif-tbnl",
|
|
"jif"
|
|
],
|
|
"pcx": "pcx",
|
|
"png": "png",
|
|
"svg+xml": [
|
|
"svg",
|
|
"svgz"
|
|
],
|
|
"tiff": [
|
|
"tiff",
|
|
"tif"
|
|
],
|
|
"vnd.djvu": [
|
|
"djvu",
|
|
"djv"
|
|
],
|
|
"vnd.wap.wbmp": "wbmp",
|
|
"x-canon-cr2": "cr2",
|
|
"x-canon-crw": "crw",
|
|
"x-cmu-raster": "ras",
|
|
"x-coreldraw": "cdr",
|
|
"x-coreldrawpattern": "pat",
|
|
"x-coreldrawtemplate": "cdt",
|
|
"x-corelphotopaint": "cpt",
|
|
"x-epson-erf": "erf",
|
|
"x-icon": "ico",
|
|
"x-jg": "art",
|
|
"x-jng": "jng",
|
|
"x-nikon-nef": "nef",
|
|
"x-olympus-orf": "orf",
|
|
"x-portable-anymap": "pnm",
|
|
"x-portable-bitmap": "pbm",
|
|
"x-portable-graymap": "pgm",
|
|
"x-portable-pixmap": "ppm",
|
|
"x-rgb": "rgb",
|
|
"x-xbitmap": "xbm",
|
|
"x-xpixmap": "xpm",
|
|
"x-xwindowdump": "xwd",
|
|
"bmp": "bmp",
|
|
"cgm": "cgm",
|
|
"g3fax": "g3",
|
|
"ktx": "ktx",
|
|
"prs.btif": "btif",
|
|
"sgi": "sgi",
|
|
"vnd.dece.graphic": [
|
|
"uvi",
|
|
"uvvi",
|
|
"uvg",
|
|
"uvvg"
|
|
],
|
|
"vnd.dwg": "dwg",
|
|
"vnd.dxf": "dxf",
|
|
"vnd.fastbidsheet": "fbs",
|
|
"vnd.fpx": "fpx",
|
|
"vnd.fst": "fst",
|
|
"vnd.fujixerox.edmics-mmr": "mmr",
|
|
"vnd.fujixerox.edmics-rlc": "rlc",
|
|
"vnd.ms-modi": "mdi",
|
|
"vnd.ms-photo": "wdp",
|
|
"vnd.net-fpx": "npx",
|
|
"vnd.xiff": "xif",
|
|
"webp": "webp",
|
|
"x-3ds": "3ds",
|
|
"x-cmx": "cmx",
|
|
"x-freehand": [
|
|
"fh",
|
|
"fhc",
|
|
"fh4",
|
|
"fh5",
|
|
"fh7"
|
|
],
|
|
"x-pict": [
|
|
"pic",
|
|
"pct"
|
|
],
|
|
"x-tga": "tga",
|
|
"cis-cod": "cod",
|
|
"avif": "avifs",
|
|
"heic": [
|
|
"heif",
|
|
"heic"
|
|
],
|
|
"pjpeg": [
|
|
"pjpg"
|
|
],
|
|
"vnd.adobe.photoshop": "psd",
|
|
"x-adobe-dng": "dng",
|
|
"x-fuji-raf": "raf",
|
|
"x-icns": "icns",
|
|
"x-kodak-dcr": "dcr",
|
|
"x-kodak-k25": "k25",
|
|
"x-kodak-kdc": "kdc",
|
|
"x-minolta-mrw": "mrw",
|
|
"x-panasonic-raw": [
|
|
"raw",
|
|
"rw2",
|
|
"rwl"
|
|
],
|
|
"x-pentax-pef": [
|
|
"pef",
|
|
"ptx"
|
|
],
|
|
"x-sigma-x3f": "x3f",
|
|
"x-sony-arw": "arw",
|
|
"x-sony-sr2": "sr2",
|
|
"x-sony-srf": "srf"
|
|
},
|
|
"message": {
|
|
"rfc822": [
|
|
"eml",
|
|
"mime",
|
|
"mht",
|
|
"mhtml",
|
|
"nws"
|
|
]
|
|
},
|
|
"model": {
|
|
"iges": [
|
|
"igs",
|
|
"iges"
|
|
],
|
|
"mesh": [
|
|
"msh",
|
|
"mesh",
|
|
"silo"
|
|
],
|
|
"vrml": [
|
|
"wrl",
|
|
"vrml"
|
|
],
|
|
"x3d+vrml": [
|
|
"x3dv",
|
|
"x3dvz"
|
|
],
|
|
"x3d+xml": "x3dz",
|
|
"x3d+binary": [
|
|
"x3db",
|
|
"x3dbz"
|
|
],
|
|
"vnd.collada+xml": "dae",
|
|
"vnd.dwf": "dwf",
|
|
"vnd.gdl": "gdl",
|
|
"vnd.gtw": "gtw",
|
|
"vnd.mts": "mts",
|
|
"vnd.usdz+zip": "usdz",
|
|
"vnd.vtu": "vtu"
|
|
},
|
|
"text": {
|
|
"cache-manifest": [
|
|
"manifest",
|
|
"appcache"
|
|
],
|
|
"calendar": [
|
|
"ics",
|
|
"icz",
|
|
"ifb"
|
|
],
|
|
"css": "css",
|
|
"csv": "csv",
|
|
"h323": "323",
|
|
"html": [
|
|
"html",
|
|
"htm",
|
|
"shtml",
|
|
"stm"
|
|
],
|
|
"iuls": "uls",
|
|
"plain": [
|
|
"txt",
|
|
"text",
|
|
"brf",
|
|
"conf",
|
|
"def",
|
|
"list",
|
|
"log",
|
|
"in",
|
|
"bas",
|
|
"diff",
|
|
"ksh"
|
|
],
|
|
"richtext": "rtx",
|
|
"scriptlet": [
|
|
"sct",
|
|
"wsc"
|
|
],
|
|
"texmacs": "tm",
|
|
"tab-separated-values": "tsv",
|
|
"vnd.sun.j2me.app-descriptor": "jad",
|
|
"vnd.wap.wml": "wml",
|
|
"vnd.wap.wmlscript": "wmls",
|
|
"x-bibtex": "bib",
|
|
"x-boo": "boo",
|
|
"x-c++hdr": [
|
|
"h++",
|
|
"hpp",
|
|
"hxx",
|
|
"hh"
|
|
],
|
|
"x-c++src": [
|
|
"c++",
|
|
"cpp",
|
|
"cxx",
|
|
"cc"
|
|
],
|
|
"x-component": "htc",
|
|
"x-dsrc": "d",
|
|
"x-diff": "patch",
|
|
"x-haskell": "hs",
|
|
"x-java": "java",
|
|
"x-literate-haskell": "lhs",
|
|
"x-moc": "moc",
|
|
"x-pascal": [
|
|
"p",
|
|
"pas",
|
|
"pp",
|
|
"inc"
|
|
],
|
|
"x-pcs-gcd": "gcd",
|
|
"x-python": "py",
|
|
"x-scala": "scala",
|
|
"x-setext": "etx",
|
|
"x-tcl": [
|
|
"tcl",
|
|
"tk"
|
|
],
|
|
"x-tex": [
|
|
"tex",
|
|
"ltx",
|
|
"sty",
|
|
"cls"
|
|
],
|
|
"x-vcalendar": "vcs",
|
|
"x-vcard": "vcf",
|
|
"n3": "n3",
|
|
"prs.lines.tag": "dsc",
|
|
"sgml": [
|
|
"sgml",
|
|
"sgm"
|
|
],
|
|
"troff": [
|
|
"t",
|
|
"tr",
|
|
"roff",
|
|
"man",
|
|
"me",
|
|
"ms"
|
|
],
|
|
"turtle": "ttl",
|
|
"uri-list": [
|
|
"uri",
|
|
"uris",
|
|
"urls"
|
|
],
|
|
"vcard": "vcard",
|
|
"vnd.curl": "curl",
|
|
"vnd.curl.dcurl": "dcurl",
|
|
"vnd.curl.scurl": "scurl",
|
|
"vnd.curl.mcurl": "mcurl",
|
|
"vnd.dvb.subtitle": "sub",
|
|
"vnd.fly": "fly",
|
|
"vnd.fmi.flexstor": "flx",
|
|
"vnd.graphviz": "gv",
|
|
"vnd.in3d.3dml": "3dml",
|
|
"vnd.in3d.spot": "spot",
|
|
"x-asm": [
|
|
"s",
|
|
"asm"
|
|
],
|
|
"x-c": [
|
|
"c",
|
|
"h",
|
|
"dic"
|
|
],
|
|
"x-fortran": [
|
|
"f",
|
|
"for",
|
|
"f77",
|
|
"f90"
|
|
],
|
|
"x-opml": "opml",
|
|
"x-nfo": "nfo",
|
|
"x-sfv": "sfv",
|
|
"x-uuencode": "uu",
|
|
"webviewhtml": "htt",
|
|
"javascript": "js",
|
|
"json": "json",
|
|
"markdown": [
|
|
"md",
|
|
"markdown",
|
|
"mdown",
|
|
"markdn"
|
|
],
|
|
"vnd.wap.si": "si",
|
|
"vnd.wap.sl": "sl"
|
|
},
|
|
"video": {
|
|
"avif": "avif",
|
|
"3gpp": "3gp",
|
|
"annodex": "axv",
|
|
"dl": "dl",
|
|
"dv": [
|
|
"dif",
|
|
"dv"
|
|
],
|
|
"fli": "fli",
|
|
"gl": "gl",
|
|
"mpeg": [
|
|
"mpeg",
|
|
"mpg",
|
|
"mpe",
|
|
"m1v",
|
|
"m2v",
|
|
"mp2",
|
|
"mpa",
|
|
"mpv2"
|
|
],
|
|
"mp4": [
|
|
"mp4",
|
|
"mp4v",
|
|
"mpg4"
|
|
],
|
|
"quicktime": [
|
|
"qt",
|
|
"mov"
|
|
],
|
|
"ogg": "ogv",
|
|
"vnd.mpegurl": [
|
|
"mxu",
|
|
"m4u"
|
|
],
|
|
"x-flv": "flv",
|
|
"x-la-asf": [
|
|
"lsf",
|
|
"lsx"
|
|
],
|
|
"x-mng": "mng",
|
|
"x-ms-asf": [
|
|
"asf",
|
|
"asx",
|
|
"asr"
|
|
],
|
|
"x-ms-wm": "wm",
|
|
"x-ms-wmv": "wmv",
|
|
"x-ms-wmx": "wmx",
|
|
"x-ms-wvx": "wvx",
|
|
"x-msvideo": "avi",
|
|
"x-sgi-movie": "movie",
|
|
"x-matroska": [
|
|
"mpv",
|
|
"mkv",
|
|
"mk3d",
|
|
"mks"
|
|
],
|
|
"3gpp2": "3g2",
|
|
"h261": "h261",
|
|
"h263": "h263",
|
|
"h264": "h264",
|
|
"jpeg": "jpgv",
|
|
"jpm": [
|
|
"jpm",
|
|
"jpgm"
|
|
],
|
|
"mj2": [
|
|
"mj2",
|
|
"mjp2"
|
|
],
|
|
"vnd.dece.hd": [
|
|
"uvh",
|
|
"uvvh"
|
|
],
|
|
"vnd.dece.mobile": [
|
|
"uvm",
|
|
"uvvm"
|
|
],
|
|
"vnd.dece.pd": [
|
|
"uvp",
|
|
"uvvp"
|
|
],
|
|
"vnd.dece.sd": [
|
|
"uvs",
|
|
"uvvs"
|
|
],
|
|
"vnd.dece.video": [
|
|
"uvv",
|
|
"uvvv"
|
|
],
|
|
"vnd.dvb.file": "dvb",
|
|
"vnd.fvt": "fvt",
|
|
"vnd.ms-playready.media.pyv": "pyv",
|
|
"vnd.uvvu.mp4": [
|
|
"uvu",
|
|
"uvvu"
|
|
],
|
|
"vnd.vivo": "viv",
|
|
"webm": "webm",
|
|
"x-f4v": "f4v",
|
|
"x-m4v": "m4v",
|
|
"x-ms-vob": "vob",
|
|
"x-smv": "smv",
|
|
"mp2t": "ts"
|
|
},
|
|
"x-conference": {
|
|
"x-cooltalk": "ice"
|
|
},
|
|
"x-world": {
|
|
"x-vrml": [
|
|
"vrm",
|
|
"flr",
|
|
"wrz",
|
|
"xaf",
|
|
"xof"
|
|
]
|
|
}
|
|
};
|
|
|
|
(() => {
|
|
const mimeTypes = {};
|
|
for (const type of Object.keys(table$1)) {
|
|
for (const subtype of Object.keys(table$1[type])) {
|
|
const value = table$1[type][subtype];
|
|
if (typeof value == "string") {
|
|
mimeTypes[value] = type + "/" + subtype;
|
|
} else {
|
|
for (let indexMimeType = 0; indexMimeType < value.length; indexMimeType++) {
|
|
mimeTypes[value[indexMimeType]] = type + "/" + subtype;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return mimeTypes;
|
|
})();
|
|
|
|
/*
|
|
Copyright (c) 2022 Gildas Lormeau. All rights reserved.
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
modification, are permitted provided that the following conditions are met:
|
|
|
|
1. Redistributions of source code must retain the above copyright notice,
|
|
this list of conditions and the following disclaimer.
|
|
|
|
2. Redistributions in binary form must reproduce the above copyright
|
|
notice, this list of conditions and the following disclaimer in
|
|
the documentation and/or other materials provided with the distribution.
|
|
|
|
3. The names of the authors may not be used to endorse or promote products
|
|
derived from this software without specific prior written permission.
|
|
|
|
THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
|
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
|
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
|
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
|
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
const table = [];
|
|
for (let i = 0; i < 256; i++) {
|
|
let t = i;
|
|
for (let j = 0; j < 8; j++) {
|
|
if (t & 1) {
|
|
t = (t >>> 1) ^ 0xEDB88320;
|
|
} else {
|
|
t = t >>> 1;
|
|
}
|
|
}
|
|
table[i] = t;
|
|
}
|
|
|
|
class Crc32 {
|
|
|
|
constructor(crc) {
|
|
this.crc = crc || -1;
|
|
}
|
|
|
|
append(data) {
|
|
let crc = this.crc | 0;
|
|
for (let offset = 0, length = data.length | 0; offset < length; offset++) {
|
|
crc = (crc >>> 8) ^ table[(crc ^ data[offset]) & 0xFF];
|
|
}
|
|
this.crc = crc;
|
|
}
|
|
|
|
get() {
|
|
return ~this.crc;
|
|
}
|
|
}
|
|
|
|
/*
|
|
Copyright (c) 2022 Gildas Lormeau. All rights reserved.
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
modification, are permitted provided that the following conditions are met:
|
|
|
|
1. Redistributions of source code must retain the above copyright notice,
|
|
this list of conditions and the following disclaimer.
|
|
|
|
2. Redistributions in binary form must reproduce the above copyright
|
|
notice, this list of conditions and the following disclaimer in
|
|
the documentation and/or other materials provided with the distribution.
|
|
|
|
3. The names of the authors may not be used to endorse or promote products
|
|
derived from this software without specific prior written permission.
|
|
|
|
THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
|
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
|
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
|
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
|
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
class Crc32Stream extends TransformStream {
|
|
|
|
constructor() {
|
|
// deno-lint-ignore prefer-const
|
|
let stream;
|
|
const crc32 = new Crc32();
|
|
super({
|
|
transform(chunk, controller) {
|
|
crc32.append(chunk);
|
|
controller.enqueue(chunk);
|
|
},
|
|
flush() {
|
|
const value = new Uint8Array(4);
|
|
const dataView = new DataView(value.buffer);
|
|
dataView.setUint32(0, crc32.get());
|
|
stream.value = value;
|
|
}
|
|
});
|
|
stream = this;
|
|
}
|
|
}
|
|
|
|
/*
|
|
Copyright (c) 2022 Gildas Lormeau. All rights reserved.
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
modification, are permitted provided that the following conditions are met:
|
|
|
|
1. Redistributions of source code must retain the above copyright notice,
|
|
this list of conditions and the following disclaimer.
|
|
|
|
2. Redistributions in binary form must reproduce the above copyright
|
|
notice, this list of conditions and the following disclaimer in
|
|
the documentation and/or other materials provided with the distribution.
|
|
|
|
3. The names of the authors may not be used to endorse or promote products
|
|
derived from this software without specific prior written permission.
|
|
|
|
THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
|
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
|
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
|
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
|
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
function encodeText(value) {
|
|
// deno-lint-ignore valid-typeof
|
|
if (typeof TextEncoder == UNDEFINED_TYPE) {
|
|
value = unescape(encodeURIComponent(value));
|
|
const result = new Uint8Array(value.length);
|
|
for (let i = 0; i < result.length; i++) {
|
|
result[i] = value.charCodeAt(i);
|
|
}
|
|
return result;
|
|
} else {
|
|
return new TextEncoder().encode(value);
|
|
}
|
|
}
|
|
|
|
// Derived from https://github.com/xqdoo00o/jszip/blob/master/lib/sjcl.js and https://github.com/bitwiseshiftleft/sjcl
|
|
|
|
// deno-lint-ignore-file no-this-alias
|
|
|
|
/*
|
|
* SJCL is open. You can use, modify and redistribute it under a BSD
|
|
* license or under the GNU GPL, version 2.0.
|
|
*/
|
|
|
|
/** @fileOverview Javascript cryptography implementation.
|
|
*
|
|
* Crush to remove comments, shorten variable names and
|
|
* generally reduce transmission size.
|
|
*
|
|
* @author Emily Stark
|
|
* @author Mike Hamburg
|
|
* @author Dan Boneh
|
|
*/
|
|
|
|
/*jslint indent: 2, bitwise: false, nomen: false, plusplus: false, white: false, regexp: false */
|
|
|
|
/** @fileOverview Arrays of bits, encoded as arrays of Numbers.
|
|
*
|
|
* @author Emily Stark
|
|
* @author Mike Hamburg
|
|
* @author Dan Boneh
|
|
*/
|
|
|
|
/**
|
|
* Arrays of bits, encoded as arrays of Numbers.
|
|
* @namespace
|
|
* @description
|
|
* <p>
|
|
* These objects are the currency accepted by SJCL's crypto functions.
|
|
* </p>
|
|
*
|
|
* <p>
|
|
* Most of our crypto primitives operate on arrays of 4-byte words internally,
|
|
* but many of them can take arguments that are not a multiple of 4 bytes.
|
|
* This library encodes arrays of bits (whose size need not be a multiple of 8
|
|
* bits) as arrays of 32-bit words. The bits are packed, big-endian, into an
|
|
* array of words, 32 bits at a time. Since the words are double-precision
|
|
* floating point numbers, they fit some extra data. We use this (in a private,
|
|
* possibly-changing manner) to encode the number of bits actually present
|
|
* in the last word of the array.
|
|
* </p>
|
|
*
|
|
* <p>
|
|
* Because bitwise ops clear this out-of-band data, these arrays can be passed
|
|
* to ciphers like AES which want arrays of words.
|
|
* </p>
|
|
*/
|
|
const bitArray = {
|
|
/**
|
|
* Concatenate two bit arrays.
|
|
* @param {bitArray} a1 The first array.
|
|
* @param {bitArray} a2 The second array.
|
|
* @return {bitArray} The concatenation of a1 and a2.
|
|
*/
|
|
concat(a1, a2) {
|
|
if (a1.length === 0 || a2.length === 0) {
|
|
return a1.concat(a2);
|
|
}
|
|
|
|
const last = a1[a1.length - 1], shift = bitArray.getPartial(last);
|
|
if (shift === 32) {
|
|
return a1.concat(a2);
|
|
} else {
|
|
return bitArray._shiftRight(a2, shift, last | 0, a1.slice(0, a1.length - 1));
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Find the length of an array of bits.
|
|
* @param {bitArray} a The array.
|
|
* @return {Number} The length of a, in bits.
|
|
*/
|
|
bitLength(a) {
|
|
const l = a.length;
|
|
if (l === 0) {
|
|
return 0;
|
|
}
|
|
const x = a[l - 1];
|
|
return (l - 1) * 32 + bitArray.getPartial(x);
|
|
},
|
|
|
|
/**
|
|
* Truncate an array.
|
|
* @param {bitArray} a The array.
|
|
* @param {Number} len The length to truncate to, in bits.
|
|
* @return {bitArray} A new array, truncated to len bits.
|
|
*/
|
|
clamp(a, len) {
|
|
if (a.length * 32 < len) {
|
|
return a;
|
|
}
|
|
a = a.slice(0, Math.ceil(len / 32));
|
|
const l = a.length;
|
|
len = len & 31;
|
|
if (l > 0 && len) {
|
|
a[l - 1] = bitArray.partial(len, a[l - 1] & 0x80000000 >> (len - 1), 1);
|
|
}
|
|
return a;
|
|
},
|
|
|
|
/**
|
|
* Make a partial word for a bit array.
|
|
* @param {Number} len The number of bits in the word.
|
|
* @param {Number} x The bits.
|
|
* @param {Number} [_end=0] Pass 1 if x has already been shifted to the high side.
|
|
* @return {Number} The partial word.
|
|
*/
|
|
partial(len, x, _end) {
|
|
if (len === 32) {
|
|
return x;
|
|
}
|
|
return (_end ? x | 0 : x << (32 - len)) + len * 0x10000000000;
|
|
},
|
|
|
|
/**
|
|
* Get the number of bits used by a partial word.
|
|
* @param {Number} x The partial word.
|
|
* @return {Number} The number of bits used by the partial word.
|
|
*/
|
|
getPartial(x) {
|
|
return Math.round(x / 0x10000000000) || 32;
|
|
},
|
|
|
|
/** Shift an array right.
|
|
* @param {bitArray} a The array to shift.
|
|
* @param {Number} shift The number of bits to shift.
|
|
* @param {Number} [carry=0] A byte to carry in
|
|
* @param {bitArray} [out=[]] An array to prepend to the output.
|
|
* @private
|
|
*/
|
|
_shiftRight(a, shift, carry, out) {
|
|
if (out === undefined) {
|
|
out = [];
|
|
}
|
|
|
|
for (; shift >= 32; shift -= 32) {
|
|
out.push(carry);
|
|
carry = 0;
|
|
}
|
|
if (shift === 0) {
|
|
return out.concat(a);
|
|
}
|
|
|
|
for (let i = 0; i < a.length; i++) {
|
|
out.push(carry | a[i] >>> shift);
|
|
carry = a[i] << (32 - shift);
|
|
}
|
|
const last2 = a.length ? a[a.length - 1] : 0;
|
|
const shift2 = bitArray.getPartial(last2);
|
|
out.push(bitArray.partial(shift + shift2 & 31, (shift + shift2 > 32) ? carry : out.pop(), 1));
|
|
return out;
|
|
}
|
|
};
|
|
|
|
/** @fileOverview Bit array codec implementations.
|
|
*
|
|
* @author Emily Stark
|
|
* @author Mike Hamburg
|
|
* @author Dan Boneh
|
|
*/
|
|
|
|
/**
|
|
* Arrays of bytes
|
|
* @namespace
|
|
*/
|
|
const codec = {
|
|
bytes: {
|
|
/** Convert from a bitArray to an array of bytes. */
|
|
fromBits(arr) {
|
|
const bl = bitArray.bitLength(arr);
|
|
const byteLength = bl / 8;
|
|
const out = new Uint8Array(byteLength);
|
|
let tmp;
|
|
for (let i = 0; i < byteLength; i++) {
|
|
if ((i & 3) === 0) {
|
|
tmp = arr[i / 4];
|
|
}
|
|
out[i] = tmp >>> 24;
|
|
tmp <<= 8;
|
|
}
|
|
return out;
|
|
},
|
|
/** Convert from an array of bytes to a bitArray. */
|
|
toBits(bytes) {
|
|
const out = [];
|
|
let i;
|
|
let tmp = 0;
|
|
for (i = 0; i < bytes.length; i++) {
|
|
tmp = tmp << 8 | bytes[i];
|
|
if ((i & 3) === 3) {
|
|
out.push(tmp);
|
|
tmp = 0;
|
|
}
|
|
}
|
|
if (i & 3) {
|
|
out.push(bitArray.partial(8 * (i & 3), tmp));
|
|
}
|
|
return out;
|
|
}
|
|
}
|
|
};
|
|
|
|
const hash = {};
|
|
|
|
/**
|
|
* Context for a SHA-1 operation in progress.
|
|
* @constructor
|
|
*/
|
|
hash.sha1 = class {
|
|
constructor(hash) {
|
|
const sha1 = this;
|
|
/**
|
|
* The hash's block size, in bits.
|
|
* @constant
|
|
*/
|
|
sha1.blockSize = 512;
|
|
/**
|
|
* The SHA-1 initialization vector.
|
|
* @private
|
|
*/
|
|
sha1._init = [0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0];
|
|
/**
|
|
* The SHA-1 hash key.
|
|
* @private
|
|
*/
|
|
sha1._key = [0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6];
|
|
if (hash) {
|
|
sha1._h = hash._h.slice(0);
|
|
sha1._buffer = hash._buffer.slice(0);
|
|
sha1._length = hash._length;
|
|
} else {
|
|
sha1.reset();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Reset the hash state.
|
|
* @return this
|
|
*/
|
|
reset() {
|
|
const sha1 = this;
|
|
sha1._h = sha1._init.slice(0);
|
|
sha1._buffer = [];
|
|
sha1._length = 0;
|
|
return sha1;
|
|
}
|
|
|
|
/**
|
|
* Input several words to the hash.
|
|
* @param {bitArray|String} data the data to hash.
|
|
* @return this
|
|
*/
|
|
update(data) {
|
|
const sha1 = this;
|
|
if (typeof data === "string") {
|
|
data = codec.utf8String.toBits(data);
|
|
}
|
|
const b = sha1._buffer = bitArray.concat(sha1._buffer, data);
|
|
const ol = sha1._length;
|
|
const nl = sha1._length = ol + bitArray.bitLength(data);
|
|
if (nl > 9007199254740991) {
|
|
throw new Error("Cannot hash more than 2^53 - 1 bits");
|
|
}
|
|
const c = new Uint32Array(b);
|
|
let j = 0;
|
|
for (let i = sha1.blockSize + ol - ((sha1.blockSize + ol) & (sha1.blockSize - 1)); i <= nl;
|
|
i += sha1.blockSize) {
|
|
sha1._block(c.subarray(16 * j, 16 * (j + 1)));
|
|
j += 1;
|
|
}
|
|
b.splice(0, 16 * j);
|
|
return sha1;
|
|
}
|
|
|
|
/**
|
|
* Complete hashing and output the hash value.
|
|
* @return {bitArray} The hash value, an array of 5 big-endian words. TODO
|
|
*/
|
|
finalize() {
|
|
const sha1 = this;
|
|
let b = sha1._buffer;
|
|
const h = sha1._h;
|
|
|
|
// Round out and push the buffer
|
|
b = bitArray.concat(b, [bitArray.partial(1, 1)]);
|
|
// Round out the buffer to a multiple of 16 words, less the 2 length words.
|
|
for (let i = b.length + 2; i & 15; i++) {
|
|
b.push(0);
|
|
}
|
|
|
|
// append the length
|
|
b.push(Math.floor(sha1._length / 0x100000000));
|
|
b.push(sha1._length | 0);
|
|
|
|
while (b.length) {
|
|
sha1._block(b.splice(0, 16));
|
|
}
|
|
|
|
sha1.reset();
|
|
return h;
|
|
}
|
|
|
|
/**
|
|
* The SHA-1 logical functions f(0), f(1), ..., f(79).
|
|
* @private
|
|
*/
|
|
_f(t, b, c, d) {
|
|
if (t <= 19) {
|
|
return (b & c) | (~b & d);
|
|
} else if (t <= 39) {
|
|
return b ^ c ^ d;
|
|
} else if (t <= 59) {
|
|
return (b & c) | (b & d) | (c & d);
|
|
} else if (t <= 79) {
|
|
return b ^ c ^ d;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Circular left-shift operator.
|
|
* @private
|
|
*/
|
|
_S(n, x) {
|
|
return (x << n) | (x >>> 32 - n);
|
|
}
|
|
|
|
/**
|
|
* Perform one cycle of SHA-1.
|
|
* @param {Uint32Array|bitArray} words one block of words.
|
|
* @private
|
|
*/
|
|
_block(words) {
|
|
const sha1 = this;
|
|
const h = sha1._h;
|
|
// When words is passed to _block, it has 16 elements. SHA1 _block
|
|
// function extends words with new elements (at the end there are 80 elements).
|
|
// The problem is that if we use Uint32Array instead of Array,
|
|
// the length of Uint32Array cannot be changed. Thus, we replace words with a
|
|
// normal Array here.
|
|
const w = Array(80); // do not use Uint32Array here as the instantiation is slower
|
|
for (let j = 0; j < 16; j++) {
|
|
w[j] = words[j];
|
|
}
|
|
|
|
let a = h[0];
|
|
let b = h[1];
|
|
let c = h[2];
|
|
let d = h[3];
|
|
let e = h[4];
|
|
|
|
for (let t = 0; t <= 79; t++) {
|
|
if (t >= 16) {
|
|
w[t] = sha1._S(1, w[t - 3] ^ w[t - 8] ^ w[t - 14] ^ w[t - 16]);
|
|
}
|
|
const tmp = (sha1._S(5, a) + sha1._f(t, b, c, d) + e + w[t] +
|
|
sha1._key[Math.floor(t / 20)]) | 0;
|
|
e = d;
|
|
d = c;
|
|
c = sha1._S(30, b);
|
|
b = a;
|
|
a = tmp;
|
|
}
|
|
|
|
h[0] = (h[0] + a) | 0;
|
|
h[1] = (h[1] + b) | 0;
|
|
h[2] = (h[2] + c) | 0;
|
|
h[3] = (h[3] + d) | 0;
|
|
h[4] = (h[4] + e) | 0;
|
|
}
|
|
};
|
|
|
|
/** @fileOverview Low-level AES implementation.
|
|
*
|
|
* This file contains a low-level implementation of AES, optimized for
|
|
* size and for efficiency on several browsers. It is based on
|
|
* OpenSSL's aes_core.c, a public-domain implementation by Vincent
|
|
* Rijmen, Antoon Bosselaers and Paulo Barreto.
|
|
*
|
|
* An older version of this implementation is available in the public
|
|
* domain, but this one is (c) Emily Stark, Mike Hamburg, Dan Boneh,
|
|
* Stanford University 2008-2010 and BSD-licensed for liability
|
|
* reasons.
|
|
*
|
|
* @author Emily Stark
|
|
* @author Mike Hamburg
|
|
* @author Dan Boneh
|
|
*/
|
|
|
|
const cipher = {};
|
|
|
|
/**
|
|
* Schedule out an AES key for both encryption and decryption. This
|
|
* is a low-level class. Use a cipher mode to do bulk encryption.
|
|
*
|
|
* @constructor
|
|
* @param {Array} key The key as an array of 4, 6 or 8 words.
|
|
*/
|
|
cipher.aes = class {
|
|
constructor(key) {
|
|
/**
|
|
* The expanded S-box and inverse S-box tables. These will be computed
|
|
* on the client so that we don't have to send them down the wire.
|
|
*
|
|
* There are two tables, _tables[0] is for encryption and
|
|
* _tables[1] is for decryption.
|
|
*
|
|
* The first 4 sub-tables are the expanded S-box with MixColumns. The
|
|
* last (_tables[01][4]) is the S-box itself.
|
|
*
|
|
* @private
|
|
*/
|
|
const aes = this;
|
|
aes._tables = [[[], [], [], [], []], [[], [], [], [], []]];
|
|
|
|
if (!aes._tables[0][0][0]) {
|
|
aes._precompute();
|
|
}
|
|
|
|
const sbox = aes._tables[0][4];
|
|
const decTable = aes._tables[1];
|
|
const keyLen = key.length;
|
|
|
|
let i, encKey, decKey, rcon = 1;
|
|
|
|
if (keyLen !== 4 && keyLen !== 6 && keyLen !== 8) {
|
|
throw new Error("invalid aes key size");
|
|
}
|
|
|
|
aes._key = [encKey = key.slice(0), decKey = []];
|
|
|
|
// schedule encryption keys
|
|
for (i = keyLen; i < 4 * keyLen + 28; i++) {
|
|
let tmp = encKey[i - 1];
|
|
|
|
// apply sbox
|
|
if (i % keyLen === 0 || (keyLen === 8 && i % keyLen === 4)) {
|
|
tmp = sbox[tmp >>> 24] << 24 ^ sbox[tmp >> 16 & 255] << 16 ^ sbox[tmp >> 8 & 255] << 8 ^ sbox[tmp & 255];
|
|
|
|
// shift rows and add rcon
|
|
if (i % keyLen === 0) {
|
|
tmp = tmp << 8 ^ tmp >>> 24 ^ rcon << 24;
|
|
rcon = rcon << 1 ^ (rcon >> 7) * 283;
|
|
}
|
|
}
|
|
|
|
encKey[i] = encKey[i - keyLen] ^ tmp;
|
|
}
|
|
|
|
// schedule decryption keys
|
|
for (let j = 0; i; j++, i--) {
|
|
const tmp = encKey[j & 3 ? i : i - 4];
|
|
if (i <= 4 || j < 4) {
|
|
decKey[j] = tmp;
|
|
} else {
|
|
decKey[j] = decTable[0][sbox[tmp >>> 24]] ^
|
|
decTable[1][sbox[tmp >> 16 & 255]] ^
|
|
decTable[2][sbox[tmp >> 8 & 255]] ^
|
|
decTable[3][sbox[tmp & 255]];
|
|
}
|
|
}
|
|
}
|
|
// public
|
|
/* Something like this might appear here eventually
|
|
name: "AES",
|
|
blockSize: 4,
|
|
keySizes: [4,6,8],
|
|
*/
|
|
|
|
/**
|
|
* Encrypt an array of 4 big-endian words.
|
|
* @param {Array} data The plaintext.
|
|
* @return {Array} The ciphertext.
|
|
*/
|
|
encrypt(data) {
|
|
return this._crypt(data, 0);
|
|
}
|
|
|
|
/**
|
|
* Decrypt an array of 4 big-endian words.
|
|
* @param {Array} data The ciphertext.
|
|
* @return {Array} The plaintext.
|
|
*/
|
|
decrypt(data) {
|
|
return this._crypt(data, 1);
|
|
}
|
|
|
|
/**
|
|
* Expand the S-box tables.
|
|
*
|
|
* @private
|
|
*/
|
|
_precompute() {
|
|
const encTable = this._tables[0];
|
|
const decTable = this._tables[1];
|
|
const sbox = encTable[4];
|
|
const sboxInv = decTable[4];
|
|
const d = [];
|
|
const th = [];
|
|
let xInv, x2, x4, x8;
|
|
|
|
// Compute double and third tables
|
|
for (let i = 0; i < 256; i++) {
|
|
th[(d[i] = i << 1 ^ (i >> 7) * 283) ^ i] = i;
|
|
}
|
|
|
|
for (let x = xInv = 0; !sbox[x]; x ^= x2 || 1, xInv = th[xInv] || 1) {
|
|
// Compute sbox
|
|
let s = xInv ^ xInv << 1 ^ xInv << 2 ^ xInv << 3 ^ xInv << 4;
|
|
s = s >> 8 ^ s & 255 ^ 99;
|
|
sbox[x] = s;
|
|
sboxInv[s] = x;
|
|
|
|
// Compute MixColumns
|
|
x8 = d[x4 = d[x2 = d[x]]];
|
|
let tDec = x8 * 0x1010101 ^ x4 * 0x10001 ^ x2 * 0x101 ^ x * 0x1010100;
|
|
let tEnc = d[s] * 0x101 ^ s * 0x1010100;
|
|
|
|
for (let i = 0; i < 4; i++) {
|
|
encTable[i][x] = tEnc = tEnc << 24 ^ tEnc >>> 8;
|
|
decTable[i][s] = tDec = tDec << 24 ^ tDec >>> 8;
|
|
}
|
|
}
|
|
|
|
// Compactify. Considerable speedup on Firefox.
|
|
for (let i = 0; i < 5; i++) {
|
|
encTable[i] = encTable[i].slice(0);
|
|
decTable[i] = decTable[i].slice(0);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Encryption and decryption core.
|
|
* @param {Array} input Four words to be encrypted or decrypted.
|
|
* @param dir The direction, 0 for encrypt and 1 for decrypt.
|
|
* @return {Array} The four encrypted or decrypted words.
|
|
* @private
|
|
*/
|
|
_crypt(input, dir) {
|
|
if (input.length !== 4) {
|
|
throw new Error("invalid aes block size");
|
|
}
|
|
|
|
const key = this._key[dir];
|
|
|
|
const nInnerRounds = key.length / 4 - 2;
|
|
const out = [0, 0, 0, 0];
|
|
const table = this._tables[dir];
|
|
|
|
// load up the tables
|
|
const t0 = table[0];
|
|
const t1 = table[1];
|
|
const t2 = table[2];
|
|
const t3 = table[3];
|
|
const sbox = table[4];
|
|
|
|
// state variables a,b,c,d are loaded with pre-whitened data
|
|
let a = input[0] ^ key[0];
|
|
let b = input[dir ? 3 : 1] ^ key[1];
|
|
let c = input[2] ^ key[2];
|
|
let d = input[dir ? 1 : 3] ^ key[3];
|
|
let kIndex = 4;
|
|
let a2, b2, c2;
|
|
|
|
// Inner rounds. Cribbed from OpenSSL.
|
|
for (let i = 0; i < nInnerRounds; i++) {
|
|
a2 = t0[a >>> 24] ^ t1[b >> 16 & 255] ^ t2[c >> 8 & 255] ^ t3[d & 255] ^ key[kIndex];
|
|
b2 = t0[b >>> 24] ^ t1[c >> 16 & 255] ^ t2[d >> 8 & 255] ^ t3[a & 255] ^ key[kIndex + 1];
|
|
c2 = t0[c >>> 24] ^ t1[d >> 16 & 255] ^ t2[a >> 8 & 255] ^ t3[b & 255] ^ key[kIndex + 2];
|
|
d = t0[d >>> 24] ^ t1[a >> 16 & 255] ^ t2[b >> 8 & 255] ^ t3[c & 255] ^ key[kIndex + 3];
|
|
kIndex += 4;
|
|
a = a2; b = b2; c = c2;
|
|
}
|
|
|
|
// Last round.
|
|
for (let i = 0; i < 4; i++) {
|
|
out[dir ? 3 & -i : i] =
|
|
sbox[a >>> 24] << 24 ^
|
|
sbox[b >> 16 & 255] << 16 ^
|
|
sbox[c >> 8 & 255] << 8 ^
|
|
sbox[d & 255] ^
|
|
key[kIndex++];
|
|
a2 = a; a = b; b = c; c = d; d = a2;
|
|
}
|
|
|
|
return out;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Random values
|
|
* @namespace
|
|
*/
|
|
const random = {
|
|
/**
|
|
* Generate random words with pure js, cryptographically not as strong & safe as native implementation.
|
|
* @param {TypedArray} typedArray The array to fill.
|
|
* @return {TypedArray} The random values.
|
|
*/
|
|
getRandomValues(typedArray) {
|
|
const words = new Uint32Array(typedArray.buffer);
|
|
const r = (m_w) => {
|
|
let m_z = 0x3ade68b1;
|
|
const mask = 0xffffffff;
|
|
return function () {
|
|
m_z = (0x9069 * (m_z & 0xFFFF) + (m_z >> 0x10)) & mask;
|
|
m_w = (0x4650 * (m_w & 0xFFFF) + (m_w >> 0x10)) & mask;
|
|
const result = ((((m_z << 0x10) + m_w) & mask) / 0x100000000) + .5;
|
|
return result * (Math.random() > .5 ? 1 : -1);
|
|
};
|
|
};
|
|
for (let i = 0, rcache; i < typedArray.length; i += 4) {
|
|
const _r = r((rcache || Math.random()) * 0x100000000);
|
|
rcache = _r() * 0x3ade67b7;
|
|
words[i / 4] = (_r() * 0x100000000) | 0;
|
|
}
|
|
return typedArray;
|
|
}
|
|
};
|
|
|
|
/** @fileOverview CTR mode implementation.
|
|
*
|
|
* Special thanks to Roy Nicholson for pointing out a bug in our
|
|
* implementation.
|
|
*
|
|
* @author Emily Stark
|
|
* @author Mike Hamburg
|
|
* @author Dan Boneh
|
|
*/
|
|
|
|
/** Brian Gladman's CTR Mode.
|
|
* @constructor
|
|
* @param {Object} _prf The aes instance to generate key.
|
|
* @param {bitArray} _iv The iv for ctr mode, it must be 128 bits.
|
|
*/
|
|
|
|
const mode = {};
|
|
|
|
/**
|
|
* Brian Gladman's CTR Mode.
|
|
* @namespace
|
|
*/
|
|
mode.ctrGladman = class {
|
|
constructor(prf, iv) {
|
|
this._prf = prf;
|
|
this._initIv = iv;
|
|
this._iv = iv;
|
|
}
|
|
|
|
reset() {
|
|
this._iv = this._initIv;
|
|
}
|
|
|
|
/** Input some data to calculate.
|
|
* @param {bitArray} data the data to process, it must be intergral multiple of 128 bits unless it's the last.
|
|
*/
|
|
update(data) {
|
|
return this.calculate(this._prf, data, this._iv);
|
|
}
|
|
|
|
incWord(word) {
|
|
if (((word >> 24) & 0xff) === 0xff) { //overflow
|
|
let b1 = (word >> 16) & 0xff;
|
|
let b2 = (word >> 8) & 0xff;
|
|
let b3 = word & 0xff;
|
|
|
|
if (b1 === 0xff) { // overflow b1
|
|
b1 = 0;
|
|
if (b2 === 0xff) {
|
|
b2 = 0;
|
|
if (b3 === 0xff) {
|
|
b3 = 0;
|
|
} else {
|
|
++b3;
|
|
}
|
|
} else {
|
|
++b2;
|
|
}
|
|
} else {
|
|
++b1;
|
|
}
|
|
|
|
word = 0;
|
|
word += (b1 << 16);
|
|
word += (b2 << 8);
|
|
word += b3;
|
|
} else {
|
|
word += (0x01 << 24);
|
|
}
|
|
return word;
|
|
}
|
|
|
|
incCounter(counter) {
|
|
if ((counter[0] = this.incWord(counter[0])) === 0) {
|
|
// encr_data in fileenc.c from Dr Brian Gladman's counts only with DWORD j < 8
|
|
counter[1] = this.incWord(counter[1]);
|
|
}
|
|
}
|
|
|
|
calculate(prf, data, iv) {
|
|
let l;
|
|
if (!(l = data.length)) {
|
|
return [];
|
|
}
|
|
const bl = bitArray.bitLength(data);
|
|
for (let i = 0; i < l; i += 4) {
|
|
this.incCounter(iv);
|
|
const e = prf.encrypt(iv);
|
|
data[i] ^= e[0];
|
|
data[i + 1] ^= e[1];
|
|
data[i + 2] ^= e[2];
|
|
data[i + 3] ^= e[3];
|
|
}
|
|
return bitArray.clamp(data, bl);
|
|
}
|
|
};
|
|
|
|
const misc = {
|
|
importKey(password) {
|
|
return new misc.hmacSha1(codec.bytes.toBits(password));
|
|
},
|
|
pbkdf2(prf, salt, count, length) {
|
|
count = count || 10000;
|
|
if (length < 0 || count < 0) {
|
|
throw new Error("invalid params to pbkdf2");
|
|
}
|
|
const byteLength = ((length >> 5) + 1) << 2;
|
|
let u, ui, i, j, k;
|
|
const arrayBuffer = new ArrayBuffer(byteLength);
|
|
const out = new DataView(arrayBuffer);
|
|
let outLength = 0;
|
|
const b = bitArray;
|
|
salt = codec.bytes.toBits(salt);
|
|
for (k = 1; outLength < (byteLength || 1); k++) {
|
|
u = ui = prf.encrypt(b.concat(salt, [k]));
|
|
for (i = 1; i < count; i++) {
|
|
ui = prf.encrypt(ui);
|
|
for (j = 0; j < ui.length; j++) {
|
|
u[j] ^= ui[j];
|
|
}
|
|
}
|
|
for (i = 0; outLength < (byteLength || 1) && i < u.length; i++) {
|
|
out.setInt32(outLength, u[i]);
|
|
outLength += 4;
|
|
}
|
|
}
|
|
return arrayBuffer.slice(0, length / 8);
|
|
}
|
|
};
|
|
|
|
/** @fileOverview HMAC implementation.
|
|
*
|
|
* @author Emily Stark
|
|
* @author Mike Hamburg
|
|
* @author Dan Boneh
|
|
*/
|
|
|
|
/** HMAC with the specified hash function.
|
|
* @constructor
|
|
* @param {bitArray} key the key for HMAC.
|
|
* @param {Object} [Hash=hash.sha1] The hash function to use.
|
|
*/
|
|
misc.hmacSha1 = class {
|
|
|
|
constructor(key) {
|
|
const hmac = this;
|
|
const Hash = hmac._hash = hash.sha1;
|
|
const exKey = [[], []];
|
|
hmac._baseHash = [new Hash(), new Hash()];
|
|
const bs = hmac._baseHash[0].blockSize / 32;
|
|
|
|
if (key.length > bs) {
|
|
key = new Hash().update(key).finalize();
|
|
}
|
|
|
|
for (let i = 0; i < bs; i++) {
|
|
exKey[0][i] = key[i] ^ 0x36363636;
|
|
exKey[1][i] = key[i] ^ 0x5C5C5C5C;
|
|
}
|
|
|
|
hmac._baseHash[0].update(exKey[0]);
|
|
hmac._baseHash[1].update(exKey[1]);
|
|
hmac._resultHash = new Hash(hmac._baseHash[0]);
|
|
}
|
|
reset() {
|
|
const hmac = this;
|
|
hmac._resultHash = new hmac._hash(hmac._baseHash[0]);
|
|
hmac._updated = false;
|
|
}
|
|
|
|
update(data) {
|
|
const hmac = this;
|
|
hmac._updated = true;
|
|
hmac._resultHash.update(data);
|
|
}
|
|
|
|
digest() {
|
|
const hmac = this;
|
|
const w = hmac._resultHash.finalize();
|
|
const result = new (hmac._hash)(hmac._baseHash[1]).update(w).finalize();
|
|
|
|
hmac.reset();
|
|
|
|
return result;
|
|
}
|
|
|
|
encrypt(data) {
|
|
if (!this._updated) {
|
|
this.update(data);
|
|
return this.digest(data);
|
|
} else {
|
|
throw new Error("encrypt on already updated hmac called!");
|
|
}
|
|
}
|
|
};
|
|
|
|
/*
|
|
Copyright (c) 2022 Gildas Lormeau. All rights reserved.
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
modification, are permitted provided that the following conditions are met:
|
|
|
|
1. Redistributions of source code must retain the above copyright notice,
|
|
this list of conditions and the following disclaimer.
|
|
|
|
2. Redistributions in binary form must reproduce the above copyright
|
|
notice, this list of conditions and the following disclaimer in
|
|
the documentation and/or other materials provided with the distribution.
|
|
|
|
3. The names of the authors may not be used to endorse or promote products
|
|
derived from this software without specific prior written permission.
|
|
|
|
THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
|
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
|
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
|
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
|
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
const GET_RANDOM_VALUES_SUPPORTED = typeof crypto != UNDEFINED_TYPE && typeof crypto.getRandomValues == FUNCTION_TYPE;
|
|
|
|
const ERR_INVALID_PASSWORD = "Invalid password";
|
|
const ERR_INVALID_SIGNATURE = "Invalid signature";
|
|
const ERR_ABORT_CHECK_PASSWORD = "zipjs-abort-check-password";
|
|
|
|
function getRandomValues(array) {
|
|
if (GET_RANDOM_VALUES_SUPPORTED) {
|
|
return crypto.getRandomValues(array);
|
|
} else {
|
|
return random.getRandomValues(array);
|
|
}
|
|
}
|
|
|
|
/*
|
|
Copyright (c) 2022 Gildas Lormeau. All rights reserved.
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
modification, are permitted provided that the following conditions are met:
|
|
|
|
1. Redistributions of source code must retain the above copyright notice,
|
|
this list of conditions and the following disclaimer.
|
|
|
|
2. Redistributions in binary form must reproduce the above copyright
|
|
notice, this list of conditions and the following disclaimer in
|
|
the documentation and/or other materials provided with the distribution.
|
|
|
|
3. The names of the authors may not be used to endorse or promote products
|
|
derived from this software without specific prior written permission.
|
|
|
|
THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
|
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
|
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
|
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
|
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
const BLOCK_LENGTH = 16;
|
|
const RAW_FORMAT = "raw";
|
|
const PBKDF2_ALGORITHM = { name: "PBKDF2" };
|
|
const HASH_ALGORITHM = { name: "HMAC" };
|
|
const HASH_FUNCTION = "SHA-1";
|
|
const BASE_KEY_ALGORITHM = Object.assign({ hash: HASH_ALGORITHM }, PBKDF2_ALGORITHM);
|
|
const DERIVED_BITS_ALGORITHM = Object.assign({ iterations: 1000, hash: { name: HASH_FUNCTION } }, PBKDF2_ALGORITHM);
|
|
const DERIVED_BITS_USAGE = ["deriveBits"];
|
|
const SALT_LENGTH = [8, 12, 16];
|
|
const KEY_LENGTH = [16, 24, 32];
|
|
const SIGNATURE_LENGTH = 10;
|
|
const COUNTER_DEFAULT_VALUE = [0, 0, 0, 0];
|
|
// deno-lint-ignore valid-typeof
|
|
const CRYPTO_API_SUPPORTED = typeof crypto != UNDEFINED_TYPE;
|
|
const subtle = CRYPTO_API_SUPPORTED && crypto.subtle;
|
|
const SUBTLE_API_SUPPORTED = CRYPTO_API_SUPPORTED && typeof subtle != UNDEFINED_TYPE;
|
|
const codecBytes = codec.bytes;
|
|
const Aes = cipher.aes;
|
|
const CtrGladman = mode.ctrGladman;
|
|
const HmacSha1 = misc.hmacSha1;
|
|
|
|
let IMPORT_KEY_SUPPORTED = CRYPTO_API_SUPPORTED && SUBTLE_API_SUPPORTED && typeof subtle.importKey == FUNCTION_TYPE;
|
|
let DERIVE_BITS_SUPPORTED = CRYPTO_API_SUPPORTED && SUBTLE_API_SUPPORTED && typeof subtle.deriveBits == FUNCTION_TYPE;
|
|
|
|
class AESDecryptionStream extends TransformStream {
|
|
|
|
constructor({ password, rawPassword, signed, encryptionStrength, checkPasswordOnly }) {
|
|
super({
|
|
start() {
|
|
Object.assign(this, {
|
|
ready: new Promise(resolve => this.resolveReady = resolve),
|
|
password: encodePassword(password, rawPassword),
|
|
signed,
|
|
strength: encryptionStrength - 1,
|
|
pending: new Uint8Array()
|
|
});
|
|
},
|
|
async transform(chunk, controller) {
|
|
const aesCrypto = this;
|
|
const {
|
|
password,
|
|
strength,
|
|
resolveReady,
|
|
ready
|
|
} = aesCrypto;
|
|
if (password) {
|
|
await createDecryptionKeys(aesCrypto, strength, password, subarray(chunk, 0, SALT_LENGTH[strength] + 2));
|
|
chunk = subarray(chunk, SALT_LENGTH[strength] + 2);
|
|
if (checkPasswordOnly) {
|
|
controller.error(new Error(ERR_ABORT_CHECK_PASSWORD));
|
|
} else {
|
|
resolveReady();
|
|
}
|
|
} else {
|
|
await ready;
|
|
}
|
|
const output = new Uint8Array(chunk.length - SIGNATURE_LENGTH - ((chunk.length - SIGNATURE_LENGTH) % BLOCK_LENGTH));
|
|
controller.enqueue(append(aesCrypto, chunk, output, 0, SIGNATURE_LENGTH, true));
|
|
},
|
|
async flush(controller) {
|
|
const {
|
|
signed,
|
|
ctr,
|
|
hmac,
|
|
pending,
|
|
ready
|
|
} = this;
|
|
if (hmac && ctr) {
|
|
await ready;
|
|
const chunkToDecrypt = subarray(pending, 0, pending.length - SIGNATURE_LENGTH);
|
|
const originalSignature = subarray(pending, pending.length - SIGNATURE_LENGTH);
|
|
let decryptedChunkArray = new Uint8Array();
|
|
if (chunkToDecrypt.length) {
|
|
const encryptedChunk = toBits(codecBytes, chunkToDecrypt);
|
|
hmac.update(encryptedChunk);
|
|
const decryptedChunk = ctr.update(encryptedChunk);
|
|
decryptedChunkArray = fromBits(codecBytes, decryptedChunk);
|
|
}
|
|
if (signed) {
|
|
const signature = subarray(fromBits(codecBytes, hmac.digest()), 0, SIGNATURE_LENGTH);
|
|
for (let indexSignature = 0; indexSignature < SIGNATURE_LENGTH; indexSignature++) {
|
|
if (signature[indexSignature] != originalSignature[indexSignature]) {
|
|
throw new Error(ERR_INVALID_SIGNATURE);
|
|
}
|
|
}
|
|
}
|
|
controller.enqueue(decryptedChunkArray);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
class AESEncryptionStream extends TransformStream {
|
|
|
|
constructor({ password, rawPassword, encryptionStrength }) {
|
|
// deno-lint-ignore prefer-const
|
|
let stream;
|
|
super({
|
|
start() {
|
|
Object.assign(this, {
|
|
ready: new Promise(resolve => this.resolveReady = resolve),
|
|
password: encodePassword(password, rawPassword),
|
|
strength: encryptionStrength - 1,
|
|
pending: new Uint8Array()
|
|
});
|
|
},
|
|
async transform(chunk, controller) {
|
|
const aesCrypto = this;
|
|
const {
|
|
password,
|
|
strength,
|
|
resolveReady,
|
|
ready
|
|
} = aesCrypto;
|
|
let preamble = new Uint8Array();
|
|
if (password) {
|
|
preamble = await createEncryptionKeys(aesCrypto, strength, password);
|
|
resolveReady();
|
|
} else {
|
|
await ready;
|
|
}
|
|
const output = new Uint8Array(preamble.length + chunk.length - (chunk.length % BLOCK_LENGTH));
|
|
output.set(preamble, 0);
|
|
controller.enqueue(append(aesCrypto, chunk, output, preamble.length, 0));
|
|
},
|
|
async flush(controller) {
|
|
const {
|
|
ctr,
|
|
hmac,
|
|
pending,
|
|
ready
|
|
} = this;
|
|
if (hmac && ctr) {
|
|
await ready;
|
|
let encryptedChunkArray = new Uint8Array();
|
|
if (pending.length) {
|
|
const encryptedChunk = ctr.update(toBits(codecBytes, pending));
|
|
hmac.update(encryptedChunk);
|
|
encryptedChunkArray = fromBits(codecBytes, encryptedChunk);
|
|
}
|
|
stream.signature = fromBits(codecBytes, hmac.digest()).slice(0, SIGNATURE_LENGTH);
|
|
controller.enqueue(concat(encryptedChunkArray, stream.signature));
|
|
}
|
|
}
|
|
});
|
|
stream = this;
|
|
}
|
|
}
|
|
|
|
function append(aesCrypto, input, output, paddingStart, paddingEnd, verifySignature) {
|
|
const {
|
|
ctr,
|
|
hmac,
|
|
pending
|
|
} = aesCrypto;
|
|
const inputLength = input.length - paddingEnd;
|
|
if (pending.length) {
|
|
input = concat(pending, input);
|
|
output = expand(output, inputLength - (inputLength % BLOCK_LENGTH));
|
|
}
|
|
let offset;
|
|
for (offset = 0; offset <= inputLength - BLOCK_LENGTH; offset += BLOCK_LENGTH) {
|
|
const inputChunk = toBits(codecBytes, subarray(input, offset, offset + BLOCK_LENGTH));
|
|
if (verifySignature) {
|
|
hmac.update(inputChunk);
|
|
}
|
|
const outputChunk = ctr.update(inputChunk);
|
|
if (!verifySignature) {
|
|
hmac.update(outputChunk);
|
|
}
|
|
output.set(fromBits(codecBytes, outputChunk), offset + paddingStart);
|
|
}
|
|
aesCrypto.pending = subarray(input, offset);
|
|
return output;
|
|
}
|
|
|
|
async function createDecryptionKeys(decrypt, strength, password, preamble) {
|
|
const passwordVerificationKey = await createKeys$1(decrypt, strength, password, subarray(preamble, 0, SALT_LENGTH[strength]));
|
|
const passwordVerification = subarray(preamble, SALT_LENGTH[strength]);
|
|
if (passwordVerificationKey[0] != passwordVerification[0] || passwordVerificationKey[1] != passwordVerification[1]) {
|
|
throw new Error(ERR_INVALID_PASSWORD);
|
|
}
|
|
}
|
|
|
|
async function createEncryptionKeys(encrypt, strength, password) {
|
|
const salt = getRandomValues(new Uint8Array(SALT_LENGTH[strength]));
|
|
const passwordVerification = await createKeys$1(encrypt, strength, password, salt);
|
|
return concat(salt, passwordVerification);
|
|
}
|
|
|
|
async function createKeys$1(aesCrypto, strength, password, salt) {
|
|
aesCrypto.password = null;
|
|
const baseKey = await importKey(RAW_FORMAT, password, BASE_KEY_ALGORITHM, false, DERIVED_BITS_USAGE);
|
|
const derivedBits = await deriveBits(Object.assign({ salt }, DERIVED_BITS_ALGORITHM), baseKey, 8 * ((KEY_LENGTH[strength] * 2) + 2));
|
|
const compositeKey = new Uint8Array(derivedBits);
|
|
const key = toBits(codecBytes, subarray(compositeKey, 0, KEY_LENGTH[strength]));
|
|
const authentication = toBits(codecBytes, subarray(compositeKey, KEY_LENGTH[strength], KEY_LENGTH[strength] * 2));
|
|
const passwordVerification = subarray(compositeKey, KEY_LENGTH[strength] * 2);
|
|
Object.assign(aesCrypto, {
|
|
keys: {
|
|
key,
|
|
authentication,
|
|
passwordVerification
|
|
},
|
|
ctr: new CtrGladman(new Aes(key), Array.from(COUNTER_DEFAULT_VALUE)),
|
|
hmac: new HmacSha1(authentication)
|
|
});
|
|
return passwordVerification;
|
|
}
|
|
|
|
async function importKey(format, password, algorithm, extractable, keyUsages) {
|
|
if (IMPORT_KEY_SUPPORTED) {
|
|
try {
|
|
return await subtle.importKey(format, password, algorithm, extractable, keyUsages);
|
|
} catch (_error) {
|
|
IMPORT_KEY_SUPPORTED = false;
|
|
return misc.importKey(password);
|
|
}
|
|
} else {
|
|
return misc.importKey(password);
|
|
}
|
|
}
|
|
|
|
async function deriveBits(algorithm, baseKey, length) {
|
|
if (DERIVE_BITS_SUPPORTED) {
|
|
try {
|
|
return await subtle.deriveBits(algorithm, baseKey, length);
|
|
} catch (_error) {
|
|
DERIVE_BITS_SUPPORTED = false;
|
|
return misc.pbkdf2(baseKey, algorithm.salt, DERIVED_BITS_ALGORITHM.iterations, length);
|
|
}
|
|
} else {
|
|
return misc.pbkdf2(baseKey, algorithm.salt, DERIVED_BITS_ALGORITHM.iterations, length);
|
|
}
|
|
}
|
|
|
|
function encodePassword(password, rawPassword) {
|
|
if (rawPassword === UNDEFINED_VALUE) {
|
|
return encodeText(password);
|
|
} else {
|
|
return rawPassword;
|
|
}
|
|
}
|
|
|
|
function concat(leftArray, rightArray) {
|
|
let array = leftArray;
|
|
if (leftArray.length + rightArray.length) {
|
|
array = new Uint8Array(leftArray.length + rightArray.length);
|
|
array.set(leftArray, 0);
|
|
array.set(rightArray, leftArray.length);
|
|
}
|
|
return array;
|
|
}
|
|
|
|
function expand(inputArray, length) {
|
|
if (length && length > inputArray.length) {
|
|
const array = inputArray;
|
|
inputArray = new Uint8Array(length);
|
|
inputArray.set(array, 0);
|
|
}
|
|
return inputArray;
|
|
}
|
|
|
|
function subarray(array, begin, end) {
|
|
return array.subarray(begin, end);
|
|
}
|
|
|
|
function fromBits(codecBytes, chunk) {
|
|
return codecBytes.fromBits(chunk);
|
|
}
|
|
function toBits(codecBytes, chunk) {
|
|
return codecBytes.toBits(chunk);
|
|
}
|
|
|
|
/*
|
|
Copyright (c) 2022 Gildas Lormeau. All rights reserved.
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
modification, are permitted provided that the following conditions are met:
|
|
|
|
1. Redistributions of source code must retain the above copyright notice,
|
|
this list of conditions and the following disclaimer.
|
|
|
|
2. Redistributions in binary form must reproduce the above copyright
|
|
notice, this list of conditions and the following disclaimer in
|
|
the documentation and/or other materials provided with the distribution.
|
|
|
|
3. The names of the authors may not be used to endorse or promote products
|
|
derived from this software without specific prior written permission.
|
|
|
|
THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
|
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
|
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
|
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
|
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
const HEADER_LENGTH = 12;
|
|
|
|
class ZipCryptoDecryptionStream extends TransformStream {
|
|
|
|
constructor({ password, passwordVerification, checkPasswordOnly }) {
|
|
super({
|
|
start() {
|
|
Object.assign(this, {
|
|
password,
|
|
passwordVerification
|
|
});
|
|
createKeys(this, password);
|
|
},
|
|
transform(chunk, controller) {
|
|
const zipCrypto = this;
|
|
if (zipCrypto.password) {
|
|
const decryptedHeader = decrypt(zipCrypto, chunk.subarray(0, HEADER_LENGTH));
|
|
zipCrypto.password = null;
|
|
if (decryptedHeader[HEADER_LENGTH - 1] != zipCrypto.passwordVerification) {
|
|
throw new Error(ERR_INVALID_PASSWORD);
|
|
}
|
|
chunk = chunk.subarray(HEADER_LENGTH);
|
|
}
|
|
if (checkPasswordOnly) {
|
|
controller.error(new Error(ERR_ABORT_CHECK_PASSWORD));
|
|
} else {
|
|
controller.enqueue(decrypt(zipCrypto, chunk));
|
|
}
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
class ZipCryptoEncryptionStream extends TransformStream {
|
|
|
|
constructor({ password, passwordVerification }) {
|
|
super({
|
|
start() {
|
|
Object.assign(this, {
|
|
password,
|
|
passwordVerification
|
|
});
|
|
createKeys(this, password);
|
|
},
|
|
transform(chunk, controller) {
|
|
const zipCrypto = this;
|
|
let output;
|
|
let offset;
|
|
if (zipCrypto.password) {
|
|
zipCrypto.password = null;
|
|
const header = getRandomValues(new Uint8Array(HEADER_LENGTH));
|
|
header[HEADER_LENGTH - 1] = zipCrypto.passwordVerification;
|
|
output = new Uint8Array(chunk.length + header.length);
|
|
output.set(encrypt(zipCrypto, header), 0);
|
|
offset = HEADER_LENGTH;
|
|
} else {
|
|
output = new Uint8Array(chunk.length);
|
|
offset = 0;
|
|
}
|
|
output.set(encrypt(zipCrypto, chunk), offset);
|
|
controller.enqueue(output);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
function decrypt(target, input) {
|
|
const output = new Uint8Array(input.length);
|
|
for (let index = 0; index < input.length; index++) {
|
|
output[index] = getByte(target) ^ input[index];
|
|
updateKeys(target, output[index]);
|
|
}
|
|
return output;
|
|
}
|
|
|
|
function encrypt(target, input) {
|
|
const output = new Uint8Array(input.length);
|
|
for (let index = 0; index < input.length; index++) {
|
|
output[index] = getByte(target) ^ input[index];
|
|
updateKeys(target, input[index]);
|
|
}
|
|
return output;
|
|
}
|
|
|
|
function createKeys(target, password) {
|
|
const keys = [0x12345678, 0x23456789, 0x34567890];
|
|
Object.assign(target, {
|
|
keys,
|
|
crcKey0: new Crc32(keys[0]),
|
|
crcKey2: new Crc32(keys[2]),
|
|
});
|
|
for (let index = 0; index < password.length; index++) {
|
|
updateKeys(target, password.charCodeAt(index));
|
|
}
|
|
}
|
|
|
|
function updateKeys(target, byte) {
|
|
let [key0, key1, key2] = target.keys;
|
|
target.crcKey0.append([byte]);
|
|
key0 = ~target.crcKey0.get();
|
|
key1 = getInt32(Math.imul(getInt32(key1 + getInt8(key0)), 134775813) + 1);
|
|
target.crcKey2.append([key1 >>> 24]);
|
|
key2 = ~target.crcKey2.get();
|
|
target.keys = [key0, key1, key2];
|
|
}
|
|
|
|
function getByte(target) {
|
|
const temp = target.keys[2] | 2;
|
|
return getInt8(Math.imul(temp, (temp ^ 1)) >>> 8);
|
|
}
|
|
|
|
function getInt8(number) {
|
|
return number & 0xFF;
|
|
}
|
|
|
|
function getInt32(number) {
|
|
return number & 0xFFFFFFFF;
|
|
}
|
|
|
|
/*
|
|
Copyright (c) 2022 Gildas Lormeau. All rights reserved.
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
modification, are permitted provided that the following conditions are met:
|
|
|
|
1. Redistributions of source code must retain the above copyright notice,
|
|
this list of conditions and the following disclaimer.
|
|
|
|
2. Redistributions in binary form must reproduce the above copyright
|
|
notice, this list of conditions and the following disclaimer in
|
|
the documentation and/or other materials provided with the distribution.
|
|
|
|
3. The names of the authors may not be used to endorse or promote products
|
|
derived from this software without specific prior written permission.
|
|
|
|
THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
|
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
|
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
|
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
|
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
const COMPRESSION_FORMAT = "deflate-raw";
|
|
|
|
class DeflateStream extends TransformStream {
|
|
|
|
constructor(options, { chunkSize, CompressionStream, CompressionStreamNative }) {
|
|
super({});
|
|
const { compressed, encrypted, useCompressionStream, zipCrypto, signed, level } = options;
|
|
const stream = this;
|
|
let crc32Stream, encryptionStream;
|
|
let readable = filterEmptyChunks(super.readable);
|
|
if ((!encrypted || zipCrypto) && signed) {
|
|
crc32Stream = new Crc32Stream();
|
|
readable = pipeThrough(readable, crc32Stream);
|
|
}
|
|
if (compressed) {
|
|
readable = pipeThroughCommpressionStream(readable, useCompressionStream, { level, chunkSize }, CompressionStreamNative, CompressionStream);
|
|
}
|
|
if (encrypted) {
|
|
if (zipCrypto) {
|
|
readable = pipeThrough(readable, new ZipCryptoEncryptionStream(options));
|
|
} else {
|
|
encryptionStream = new AESEncryptionStream(options);
|
|
readable = pipeThrough(readable, encryptionStream);
|
|
}
|
|
}
|
|
setReadable(stream, readable, () => {
|
|
let signature;
|
|
if (encrypted && !zipCrypto) {
|
|
signature = encryptionStream.signature;
|
|
}
|
|
if ((!encrypted || zipCrypto) && signed) {
|
|
signature = new DataView(crc32Stream.value.buffer).getUint32(0);
|
|
}
|
|
stream.signature = signature;
|
|
});
|
|
}
|
|
}
|
|
|
|
class InflateStream extends TransformStream {
|
|
|
|
constructor(options, { chunkSize, DecompressionStream, DecompressionStreamNative }) {
|
|
super({});
|
|
const { zipCrypto, encrypted, signed, signature, compressed, useCompressionStream } = options;
|
|
let crc32Stream, decryptionStream;
|
|
let readable = filterEmptyChunks(super.readable);
|
|
if (encrypted) {
|
|
if (zipCrypto) {
|
|
readable = pipeThrough(readable, new ZipCryptoDecryptionStream(options));
|
|
} else {
|
|
decryptionStream = new AESDecryptionStream(options);
|
|
readable = pipeThrough(readable, decryptionStream);
|
|
}
|
|
}
|
|
if (compressed) {
|
|
readable = pipeThroughCommpressionStream(readable, useCompressionStream, { chunkSize }, DecompressionStreamNative, DecompressionStream);
|
|
}
|
|
if ((!encrypted || zipCrypto) && signed) {
|
|
crc32Stream = new Crc32Stream();
|
|
readable = pipeThrough(readable, crc32Stream);
|
|
}
|
|
setReadable(this, readable, () => {
|
|
if ((!encrypted || zipCrypto) && signed) {
|
|
const dataViewSignature = new DataView(crc32Stream.value.buffer);
|
|
if (signature != dataViewSignature.getUint32(0, false)) {
|
|
throw new Error(ERR_INVALID_SIGNATURE);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
function filterEmptyChunks(readable) {
|
|
return pipeThrough(readable, new TransformStream({
|
|
transform(chunk, controller) {
|
|
if (chunk && chunk.length) {
|
|
controller.enqueue(chunk);
|
|
}
|
|
}
|
|
}));
|
|
}
|
|
|
|
function setReadable(stream, readable, flush) {
|
|
readable = pipeThrough(readable, new TransformStream({ flush }));
|
|
Object.defineProperty(stream, "readable", {
|
|
get() {
|
|
return readable;
|
|
}
|
|
});
|
|
}
|
|
|
|
function pipeThroughCommpressionStream(readable, useCompressionStream, options, CodecStreamNative, CodecStream) {
|
|
try {
|
|
const CompressionStream = useCompressionStream && CodecStreamNative ? CodecStreamNative : CodecStream;
|
|
readable = pipeThrough(readable, new CompressionStream(COMPRESSION_FORMAT, options));
|
|
} catch (_error) {
|
|
if (useCompressionStream) {
|
|
try {
|
|
readable = pipeThrough(readable, new CodecStream(COMPRESSION_FORMAT, options));
|
|
} catch (_error) {
|
|
return readable;
|
|
}
|
|
} else {
|
|
return readable;
|
|
}
|
|
}
|
|
return readable;
|
|
}
|
|
|
|
function pipeThrough(readable, transformStream) {
|
|
return readable.pipeThrough(transformStream);
|
|
}
|
|
|
|
/*
|
|
Copyright (c) 2022 Gildas Lormeau. All rights reserved.
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
modification, are permitted provided that the following conditions are met:
|
|
|
|
1. Redistributions of source code must retain the above copyright notice,
|
|
this list of conditions and the following disclaimer.
|
|
|
|
2. Redistributions in binary form must reproduce the above copyright
|
|
notice, this list of conditions and the following disclaimer in
|
|
the documentation and/or other materials provided with the distribution.
|
|
|
|
3. The names of the authors may not be used to endorse or promote products
|
|
derived from this software without specific prior written permission.
|
|
|
|
THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
|
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
|
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
|
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
|
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
const MESSAGE_EVENT_TYPE = "message";
|
|
const MESSAGE_START = "start";
|
|
const MESSAGE_PULL = "pull";
|
|
const MESSAGE_DATA = "data";
|
|
const MESSAGE_ACK_DATA = "ack";
|
|
const MESSAGE_CLOSE = "close";
|
|
const CODEC_DEFLATE = "deflate";
|
|
const CODEC_INFLATE = "inflate";
|
|
|
|
class CodecStream extends TransformStream {
|
|
|
|
constructor(options, config) {
|
|
super({});
|
|
const codec = this;
|
|
const { codecType } = options;
|
|
let Stream;
|
|
if (codecType.startsWith(CODEC_DEFLATE)) {
|
|
Stream = DeflateStream;
|
|
} else if (codecType.startsWith(CODEC_INFLATE)) {
|
|
Stream = InflateStream;
|
|
}
|
|
let outputSize = 0;
|
|
let inputSize = 0;
|
|
const stream = new Stream(options, config);
|
|
const readable = super.readable;
|
|
const inputSizeStream = new TransformStream({
|
|
transform(chunk, controller) {
|
|
if (chunk && chunk.length) {
|
|
inputSize += chunk.length;
|
|
controller.enqueue(chunk);
|
|
}
|
|
},
|
|
flush() {
|
|
Object.assign(codec, {
|
|
inputSize
|
|
});
|
|
}
|
|
});
|
|
const outputSizeStream = new TransformStream({
|
|
transform(chunk, controller) {
|
|
if (chunk && chunk.length) {
|
|
outputSize += chunk.length;
|
|
controller.enqueue(chunk);
|
|
}
|
|
},
|
|
flush() {
|
|
const { signature } = stream;
|
|
Object.assign(codec, {
|
|
signature,
|
|
outputSize,
|
|
inputSize
|
|
});
|
|
}
|
|
});
|
|
Object.defineProperty(codec, "readable", {
|
|
get() {
|
|
return readable.pipeThrough(inputSizeStream).pipeThrough(stream).pipeThrough(outputSizeStream);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
class ChunkStream extends TransformStream {
|
|
|
|
constructor(chunkSize) {
|
|
let pendingChunk;
|
|
super({
|
|
transform,
|
|
flush(controller) {
|
|
if (pendingChunk && pendingChunk.length) {
|
|
controller.enqueue(pendingChunk);
|
|
}
|
|
}
|
|
});
|
|
|
|
function transform(chunk, controller) {
|
|
if (pendingChunk) {
|
|
const newChunk = new Uint8Array(pendingChunk.length + chunk.length);
|
|
newChunk.set(pendingChunk);
|
|
newChunk.set(chunk, pendingChunk.length);
|
|
chunk = newChunk;
|
|
pendingChunk = null;
|
|
}
|
|
if (chunk.length > chunkSize) {
|
|
controller.enqueue(chunk.slice(0, chunkSize));
|
|
transform(chunk.slice(chunkSize), controller);
|
|
} else {
|
|
pendingChunk = chunk;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
Copyright (c) 2022 Gildas Lormeau. All rights reserved.
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
modification, are permitted provided that the following conditions are met:
|
|
|
|
1. Redistributions of source code must retain the above copyright notice,
|
|
this list of conditions and the following disclaimer.
|
|
|
|
2. Redistributions in binary form must reproduce the above copyright
|
|
notice, this list of conditions and the following disclaimer in
|
|
the documentation and/or other materials provided with the distribution.
|
|
|
|
3. The names of the authors may not be used to endorse or promote products
|
|
derived from this software without specific prior written permission.
|
|
|
|
THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
|
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
|
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
|
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
|
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
// deno-lint-ignore valid-typeof
|
|
let WEB_WORKERS_SUPPORTED = typeof Worker != UNDEFINED_TYPE;
|
|
|
|
class CodecWorker {
|
|
|
|
constructor(workerData, { readable, writable }, { options, config, streamOptions, useWebWorkers, transferStreams, scripts }, onTaskFinished) {
|
|
const { signal } = streamOptions;
|
|
Object.assign(workerData, {
|
|
busy: true,
|
|
readable: readable
|
|
.pipeThrough(new ChunkStream(config.chunkSize))
|
|
.pipeThrough(new ProgressWatcherStream(readable, streamOptions), { signal }),
|
|
writable,
|
|
options: Object.assign({}, options),
|
|
scripts,
|
|
transferStreams,
|
|
terminate() {
|
|
return new Promise(resolve => {
|
|
const { worker, busy } = workerData;
|
|
if (worker) {
|
|
if (busy) {
|
|
workerData.resolveTerminated = resolve;
|
|
} else {
|
|
worker.terminate();
|
|
resolve();
|
|
}
|
|
workerData.interface = null;
|
|
} else {
|
|
resolve();
|
|
}
|
|
});
|
|
},
|
|
onTaskFinished() {
|
|
const { resolveTerminated } = workerData;
|
|
if (resolveTerminated) {
|
|
workerData.resolveTerminated = null;
|
|
workerData.terminated = true;
|
|
workerData.worker.terminate();
|
|
resolveTerminated();
|
|
}
|
|
workerData.busy = false;
|
|
onTaskFinished(workerData);
|
|
}
|
|
});
|
|
return (useWebWorkers && WEB_WORKERS_SUPPORTED ? createWebWorkerInterface : createWorkerInterface)(workerData, config);
|
|
}
|
|
}
|
|
|
|
class ProgressWatcherStream extends TransformStream {
|
|
|
|
constructor(readableSource, { onstart, onprogress, size, onend }) {
|
|
let chunkOffset = 0;
|
|
super({
|
|
async start() {
|
|
if (onstart) {
|
|
await callHandler(onstart, size);
|
|
}
|
|
},
|
|
async transform(chunk, controller) {
|
|
chunkOffset += chunk.length;
|
|
if (onprogress) {
|
|
await callHandler(onprogress, chunkOffset, size);
|
|
}
|
|
controller.enqueue(chunk);
|
|
},
|
|
async flush() {
|
|
readableSource.size = chunkOffset;
|
|
if (onend) {
|
|
await callHandler(onend, chunkOffset);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
async function callHandler(handler, ...parameters) {
|
|
try {
|
|
await handler(...parameters);
|
|
} catch (_error) {
|
|
// ignored
|
|
}
|
|
}
|
|
|
|
function createWorkerInterface(workerData, config) {
|
|
return {
|
|
run: () => runWorker$1(workerData, config)
|
|
};
|
|
}
|
|
|
|
function createWebWorkerInterface(workerData, config) {
|
|
const { baseURL, chunkSize } = config;
|
|
if (!workerData.interface) {
|
|
let worker;
|
|
try {
|
|
worker = getWebWorker(workerData.scripts[0], baseURL, workerData);
|
|
} catch (_error) {
|
|
WEB_WORKERS_SUPPORTED = false;
|
|
return createWorkerInterface(workerData, config);
|
|
}
|
|
Object.assign(workerData, {
|
|
worker,
|
|
interface: {
|
|
run: () => runWebWorker(workerData, { chunkSize })
|
|
}
|
|
});
|
|
}
|
|
return workerData.interface;
|
|
}
|
|
|
|
async function runWorker$1({ options, readable, writable, onTaskFinished }, config) {
|
|
try {
|
|
const codecStream = new CodecStream(options, config);
|
|
await readable.pipeThrough(codecStream).pipeTo(writable, { preventClose: true, preventAbort: true });
|
|
const {
|
|
signature,
|
|
inputSize,
|
|
outputSize
|
|
} = codecStream;
|
|
return {
|
|
signature,
|
|
inputSize,
|
|
outputSize
|
|
};
|
|
} finally {
|
|
onTaskFinished();
|
|
}
|
|
}
|
|
|
|
async function runWebWorker(workerData, config) {
|
|
let resolveResult, rejectResult;
|
|
const result = new Promise((resolve, reject) => {
|
|
resolveResult = resolve;
|
|
rejectResult = reject;
|
|
});
|
|
Object.assign(workerData, {
|
|
reader: null,
|
|
writer: null,
|
|
resolveResult,
|
|
rejectResult,
|
|
result
|
|
});
|
|
const { readable, options, scripts } = workerData;
|
|
const { writable, closed } = watchClosedStream(workerData.writable);
|
|
const streamsTransferred = sendMessage({
|
|
type: MESSAGE_START,
|
|
scripts: scripts.slice(1),
|
|
options,
|
|
config,
|
|
readable,
|
|
writable
|
|
}, workerData);
|
|
if (!streamsTransferred) {
|
|
Object.assign(workerData, {
|
|
reader: readable.getReader(),
|
|
writer: writable.getWriter()
|
|
});
|
|
}
|
|
const resultValue = await result;
|
|
if (!streamsTransferred) {
|
|
await writable.getWriter().close();
|
|
}
|
|
await closed;
|
|
return resultValue;
|
|
}
|
|
|
|
function watchClosedStream(writableSource) {
|
|
let resolveStreamClosed;
|
|
const closed = new Promise(resolve => resolveStreamClosed = resolve);
|
|
const writable = new WritableStream({
|
|
async write(chunk) {
|
|
const writer = writableSource.getWriter();
|
|
await writer.ready;
|
|
await writer.write(chunk);
|
|
writer.releaseLock();
|
|
},
|
|
close() {
|
|
resolveStreamClosed();
|
|
},
|
|
abort(reason) {
|
|
const writer = writableSource.getWriter();
|
|
return writer.abort(reason);
|
|
}
|
|
});
|
|
return { writable, closed };
|
|
}
|
|
|
|
let classicWorkersSupported = true;
|
|
let transferStreamsSupported = true;
|
|
|
|
function getWebWorker(url, baseURL, workerData) {
|
|
const workerOptions = { type: "module" };
|
|
let scriptUrl, worker;
|
|
// deno-lint-ignore valid-typeof
|
|
if (typeof url == FUNCTION_TYPE) {
|
|
url = url();
|
|
}
|
|
try {
|
|
scriptUrl = new URL(url, baseURL);
|
|
} catch (_error) {
|
|
scriptUrl = url;
|
|
}
|
|
if (classicWorkersSupported) {
|
|
try {
|
|
worker = new Worker(scriptUrl);
|
|
} catch (_error) {
|
|
classicWorkersSupported = false;
|
|
worker = new Worker(scriptUrl, workerOptions);
|
|
}
|
|
} else {
|
|
worker = new Worker(scriptUrl, workerOptions);
|
|
}
|
|
worker.addEventListener(MESSAGE_EVENT_TYPE, event => onMessage(event, workerData));
|
|
return worker;
|
|
}
|
|
|
|
function sendMessage(message, { worker, writer, onTaskFinished, transferStreams }) {
|
|
try {
|
|
const { value, readable, writable } = message;
|
|
const transferables = [];
|
|
if (value) {
|
|
if (value.byteLength < value.buffer.byteLength) {
|
|
message.value = value.buffer.slice(0, value.byteLength);
|
|
}
|
|
else {
|
|
message.value = value.buffer;
|
|
}
|
|
transferables.push(message.value);
|
|
}
|
|
if (transferStreams && transferStreamsSupported) {
|
|
if (readable) {
|
|
transferables.push(readable);
|
|
}
|
|
if (writable) {
|
|
transferables.push(writable);
|
|
}
|
|
} else {
|
|
message.readable = message.writable = null;
|
|
}
|
|
if (transferables.length) {
|
|
try {
|
|
worker.postMessage(message, transferables);
|
|
return true;
|
|
} catch (_error) {
|
|
transferStreamsSupported = false;
|
|
message.readable = message.writable = null;
|
|
worker.postMessage(message);
|
|
}
|
|
} else {
|
|
worker.postMessage(message);
|
|
}
|
|
} catch (error) {
|
|
if (writer) {
|
|
writer.releaseLock();
|
|
}
|
|
onTaskFinished();
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async function onMessage({ data }, workerData) {
|
|
const { type, value, messageId, result, error } = data;
|
|
const { reader, writer, resolveResult, rejectResult, onTaskFinished } = workerData;
|
|
try {
|
|
if (error) {
|
|
const { message, stack, code, name } = error;
|
|
const responseError = new Error(message);
|
|
Object.assign(responseError, { stack, code, name });
|
|
close(responseError);
|
|
} else {
|
|
if (type == MESSAGE_PULL) {
|
|
const { value, done } = await reader.read();
|
|
sendMessage({ type: MESSAGE_DATA, value, done, messageId }, workerData);
|
|
}
|
|
if (type == MESSAGE_DATA) {
|
|
await writer.ready;
|
|
await writer.write(new Uint8Array(value));
|
|
sendMessage({ type: MESSAGE_ACK_DATA, messageId }, workerData);
|
|
}
|
|
if (type == MESSAGE_CLOSE) {
|
|
close(null, result);
|
|
}
|
|
}
|
|
} catch (error) {
|
|
sendMessage({ type: MESSAGE_CLOSE, messageId }, workerData);
|
|
close(error);
|
|
}
|
|
|
|
function close(error, result) {
|
|
if (error) {
|
|
rejectResult(error);
|
|
} else {
|
|
resolveResult(result);
|
|
}
|
|
if (writer) {
|
|
writer.releaseLock();
|
|
}
|
|
onTaskFinished();
|
|
}
|
|
}
|
|
|
|
/*
|
|
Copyright (c) 2022 Gildas Lormeau. All rights reserved.
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
modification, are permitted provided that the following conditions are met:
|
|
|
|
1. Redistributions of source code must retain the above copyright notice,
|
|
this list of conditions and the following disclaimer.
|
|
|
|
2. Redistributions in binary form must reproduce the above copyright
|
|
notice, this list of conditions and the following disclaimer in
|
|
the documentation and/or other materials provided with the distribution.
|
|
|
|
3. The names of the authors may not be used to endorse or promote products
|
|
derived from this software without specific prior written permission.
|
|
|
|
THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
|
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
|
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
|
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
|
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
let pool = [];
|
|
const pendingRequests = [];
|
|
|
|
let indexWorker = 0;
|
|
|
|
async function runWorker(stream, workerOptions) {
|
|
const { options, config } = workerOptions;
|
|
const { transferStreams, useWebWorkers, useCompressionStream, codecType, compressed, signed, encrypted } = options;
|
|
const { workerScripts, maxWorkers } = config;
|
|
workerOptions.transferStreams = transferStreams || transferStreams === UNDEFINED_VALUE;
|
|
const streamCopy = !compressed && !signed && !encrypted && !workerOptions.transferStreams;
|
|
workerOptions.useWebWorkers = !streamCopy && (useWebWorkers || (useWebWorkers === UNDEFINED_VALUE && config.useWebWorkers));
|
|
workerOptions.scripts = workerOptions.useWebWorkers && workerScripts ? workerScripts[codecType] : [];
|
|
options.useCompressionStream = useCompressionStream || (useCompressionStream === UNDEFINED_VALUE && config.useCompressionStream);
|
|
return (await getWorker()).run();
|
|
|
|
// deno-lint-ignore require-await
|
|
async function getWorker() {
|
|
const workerData = pool.find(workerData => !workerData.busy);
|
|
if (workerData) {
|
|
clearTerminateTimeout(workerData);
|
|
return new CodecWorker(workerData, stream, workerOptions, onTaskFinished);
|
|
} else if (pool.length < maxWorkers) {
|
|
const workerData = { indexWorker };
|
|
indexWorker++;
|
|
pool.push(workerData);
|
|
return new CodecWorker(workerData, stream, workerOptions, onTaskFinished);
|
|
} else {
|
|
return new Promise(resolve => pendingRequests.push({ resolve, stream, workerOptions }));
|
|
}
|
|
}
|
|
|
|
function onTaskFinished(workerData) {
|
|
if (pendingRequests.length) {
|
|
const [{ resolve, stream, workerOptions }] = pendingRequests.splice(0, 1);
|
|
resolve(new CodecWorker(workerData, stream, workerOptions, onTaskFinished));
|
|
} else if (workerData.worker) {
|
|
clearTerminateTimeout(workerData);
|
|
terminateWorker(workerData, workerOptions);
|
|
} else {
|
|
pool = pool.filter(data => data != workerData);
|
|
}
|
|
}
|
|
}
|
|
|
|
function terminateWorker(workerData, workerOptions) {
|
|
const { config } = workerOptions;
|
|
const { terminateWorkerTimeout } = config;
|
|
if (Number.isFinite(terminateWorkerTimeout) && terminateWorkerTimeout >= 0) {
|
|
if (workerData.terminated) {
|
|
workerData.terminated = false;
|
|
} else {
|
|
workerData.terminateTimeout = setTimeout(async () => {
|
|
pool = pool.filter(data => data != workerData);
|
|
try {
|
|
await workerData.terminate();
|
|
} catch (_error) {
|
|
// ignored
|
|
}
|
|
}, terminateWorkerTimeout);
|
|
}
|
|
}
|
|
}
|
|
|
|
function clearTerminateTimeout(workerData) {
|
|
const { terminateTimeout } = workerData;
|
|
if (terminateTimeout) {
|
|
clearTimeout(terminateTimeout);
|
|
workerData.terminateTimeout = null;
|
|
}
|
|
}
|
|
|
|
function e(e,t={}){const n='const{Array:e,Object:t,Number:n,Math:r,Error:s,Uint8Array:i,Uint16Array:o,Uint32Array:c,Int32Array:f,Map:a,DataView:l,Promise:u,TextEncoder:w,crypto:h,postMessage:d,TransformStream:p,ReadableStream:y,WritableStream:m,CompressionStream:b,DecompressionStream:g}=self,k=void 0,v="undefined",S="function";class z{constructor(e){return class extends p{constructor(t,n){const r=new e(n);super({transform(e,t){t.enqueue(r.append(e))},flush(e){const t=r.flush();t&&e.enqueue(t)}})}}}}const C=[];for(let e=0;256>e;e++){let t=e;for(let e=0;8>e;e++)1&t?t=t>>>1^3988292384:t>>>=1;C[e]=t}class x{constructor(e){this.t=e||-1}append(e){let t=0|this.t;for(let n=0,r=0|e.length;r>n;n++)t=t>>>8^C[255&(t^e[n])];this.t=t}get(){return~this.t}}class A extends p{constructor(){let e;const t=new x;super({transform(e,n){t.append(e),n.enqueue(e)},flush(){const n=new i(4);new l(n.buffer).setUint32(0,t.get()),e.value=n}}),e=this}}const _={concat(e,t){if(0===e.length||0===t.length)return e.concat(t);const n=e[e.length-1],r=_.i(n);return 32===r?e.concat(t):_.o(t,r,0|n,e.slice(0,e.length-1))},l(e){const t=e.length;if(0===t)return 0;const n=e[t-1];return 32*(t-1)+_.i(n)},u(e,t){if(32*e.length<t)return e;const n=(e=e.slice(0,r.ceil(t/32))).length;return t&=31,n>0&&t&&(e[n-1]=_.h(t,e[n-1]&2147483648>>t-1,1)),e},h:(e,t,n)=>32===e?t:(n?0|t:t<<32-e)+1099511627776*e,i:e=>r.round(e/1099511627776)||32,o(e,t,n,r){for(void 0===r&&(r=[]);t>=32;t-=32)r.push(n),n=0;if(0===t)return r.concat(e);for(let s=0;s<e.length;s++)r.push(n|e[s]>>>t),n=e[s]<<32-t;const s=e.length?e[e.length-1]:0,i=_.i(s);return r.push(_.h(t+i&31,t+i>32?n:r.pop(),1)),r}},I={bytes:{p(e){const t=_.l(e)/8,n=new i(t);let r;for(let s=0;t>s;s++)3&s||(r=e[s/4]),n[s]=r>>>24,r<<=8;return n},m(e){const t=[];let n,r=0;for(n=0;n<e.length;n++)r=r<<8|e[n],3&~n||(t.push(r),r=0);return 3&n&&t.push(_.h(8*(3&n),r)),t}}},P=class{constructor(e){const t=this;t.blockSize=512,t.k=[1732584193,4023233417,2562383102,271733878,3285377520],t.v=[1518500249,1859775393,2400959708,3395469782],e?(t.S=e.S.slice(0),t.C=e.C.slice(0),t.A=e.A):t.reset()}reset(){const e=this;return e.S=e.k.slice(0),e.C=[],e.A=0,e}update(e){const t=this;"string"==typeof e&&(e=I._.m(e));const n=t.C=_.concat(t.C,e),r=t.A,i=t.A=r+_.l(e);if(i>9007199254740991)throw new s("Cannot hash more than 2^53 - 1 bits");const o=new c(n);let f=0;for(let e=t.blockSize+r-(t.blockSize+r&t.blockSize-1);i>=e;e+=t.blockSize)t.I(o.subarray(16*f,16*(f+1))),f+=1;return n.splice(0,16*f),t}P(){const e=this;let t=e.C;const n=e.S;t=_.concat(t,[_.h(1,1)]);for(let e=t.length+2;15&e;e++)t.push(0);for(t.push(r.floor(e.A/4294967296)),t.push(0|e.A);t.length;)e.I(t.splice(0,16));return e.reset(),n}D(e,t,n,r){return e>19?e>39?e>59?e>79?void 0:t^n^r:t&n|t&r|n&r:t^n^r:t&n|~t&r}V(e,t){return t<<e|t>>>32-e}I(t){const n=this,s=n.S,i=e(80);for(let e=0;16>e;e++)i[e]=t[e];let o=s[0],c=s[1],f=s[2],a=s[3],l=s[4];for(let e=0;79>=e;e++){16>e||(i[e]=n.V(1,i[e-3]^i[e-8]^i[e-14]^i[e-16]));const t=n.V(5,o)+n.D(e,c,f,a)+l+i[e]+n.v[r.floor(e/20)]|0;l=a,a=f,f=n.V(30,c),c=o,o=t}s[0]=s[0]+o|0,s[1]=s[1]+c|0,s[2]=s[2]+f|0,s[3]=s[3]+a|0,s[4]=s[4]+l|0}},D={getRandomValues(e){const t=new c(e.buffer),n=e=>{let t=987654321;const n=4294967295;return()=>(t=36969*(65535&t)+(t>>16)&n,(((t<<16)+(e=18e3*(65535&e)+(e>>16)&n)&n)/4294967296+.5)*(r.random()>.5?1:-1))};for(let s,i=0;i<e.length;i+=4){const e=n(4294967296*(s||r.random()));s=987654071*e(),t[i/4]=4294967296*e()|0}return e}},V={importKey:e=>new V.R(I.bytes.m(e)),B(e,t,n,r){if(n=n||1e4,0>r||0>n)throw new s("invalid params to pbkdf2");const i=1+(r>>5)<<2;let o,c,f,a,u;const w=new ArrayBuffer(i),h=new l(w);let d=0;const p=_;for(t=I.bytes.m(t),u=1;(i||1)>d;u++){for(o=c=e.encrypt(p.concat(t,[u])),f=1;n>f;f++)for(c=e.encrypt(c),a=0;a<c.length;a++)o[a]^=c[a];for(f=0;(i||1)>d&&f<o.length;f++)h.setInt32(d,o[f]),d+=4}return w.slice(0,r/8)},R:class{constructor(e){const t=this,n=t.M=P,r=[[],[]];t.U=[new n,new n];const s=t.U[0].blockSize/32;e.length>s&&(e=(new n).update(e).P());for(let t=0;s>t;t++)r[0][t]=909522486^e[t],r[1][t]=1549556828^e[t];t.U[0].update(r[0]),t.U[1].update(r[1]),t.K=new n(t.U[0])}reset(){const e=this;e.K=new e.M(e.U[0]),e.N=!1}update(e){this.N=!0,this.K.update(e)}digest(){const e=this,t=e.K.P(),n=new e.M(e.U[1]).update(t).P();return e.reset(),n}encrypt(e){if(this.N)throw new s("encrypt on already updated hmac called!");return this.update(e),this.digest(e)}}},R=typeof h!=v&&typeof h.getRandomValues==S,B="Invalid password",E="Invalid signature",M="zipjs-abort-check-password";function U(e){return R?h.getRandomValues(e):D.getRandomValues(e)}const K=16,N={name:"PBKDF2"},O=t.assign({hash:{name:"HMAC"}},N),T=t.assign({iterations:1e3,hash:{name:"SHA-1"}},N),W=["deriveBits"],j=[8,12,16],H=[16,24,32],L=10,F=[0,0,0,0],q=typeof h!=v,G=q&&h.subtle,J=q&&typeof G!=v,Q=I.bytes,X=class{constructor(e){const t=this;t.O=[[[],[],[],[],[]],[[],[],[],[],[]]],t.O[0][0][0]||t.T();const n=t.O[0][4],r=t.O[1],i=e.length;let o,c,f,a=1;if(4!==i&&6!==i&&8!==i)throw new s("invalid aes key size");for(t.v=[c=e.slice(0),f=[]],o=i;4*i+28>o;o++){let e=c[o-1];(o%i==0||8===i&&o%i==4)&&(e=n[e>>>24]<<24^n[e>>16&255]<<16^n[e>>8&255]<<8^n[255&e],o%i==0&&(e=e<<8^e>>>24^a<<24,a=a<<1^283*(a>>7))),c[o]=c[o-i]^e}for(let e=0;o;e++,o--){const t=c[3&e?o:o-4];f[e]=4>=o||4>e?t:r[0][n[t>>>24]]^r[1][n[t>>16&255]]^r[2][n[t>>8&255]]^r[3][n[255&t]]}}encrypt(e){return this.W(e,0)}decrypt(e){return this.W(e,1)}T(){const e=this.O[0],t=this.O[1],n=e[4],r=t[4],s=[],i=[];let o,c,f,a;for(let e=0;256>e;e++)i[(s[e]=e<<1^283*(e>>7))^e]=e;for(let l=o=0;!n[l];l^=c||1,o=i[o]||1){let i=o^o<<1^o<<2^o<<3^o<<4;i=i>>8^255&i^99,n[l]=i,r[i]=l,a=s[f=s[c=s[l]]];let u=16843009*a^65537*f^257*c^16843008*l,w=257*s[i]^16843008*i;for(let n=0;4>n;n++)e[n][l]=w=w<<24^w>>>8,t[n][i]=u=u<<24^u>>>8}for(let n=0;5>n;n++)e[n]=e[n].slice(0),t[n]=t[n].slice(0)}W(e,t){if(4!==e.length)throw new s("invalid aes block size");const n=this.v[t],r=n.length/4-2,i=[0,0,0,0],o=this.O[t],c=o[0],f=o[1],a=o[2],l=o[3],u=o[4];let w,h,d,p=e[0]^n[0],y=e[t?3:1]^n[1],m=e[2]^n[2],b=e[t?1:3]^n[3],g=4;for(let e=0;r>e;e++)w=c[p>>>24]^f[y>>16&255]^a[m>>8&255]^l[255&b]^n[g],h=c[y>>>24]^f[m>>16&255]^a[b>>8&255]^l[255&p]^n[g+1],d=c[m>>>24]^f[b>>16&255]^a[p>>8&255]^l[255&y]^n[g+2],b=c[b>>>24]^f[p>>16&255]^a[y>>8&255]^l[255&m]^n[g+3],g+=4,p=w,y=h,m=d;for(let e=0;4>e;e++)i[t?3&-e:e]=u[p>>>24]<<24^u[y>>16&255]<<16^u[m>>8&255]<<8^u[255&b]^n[g++],w=p,p=y,y=m,m=b,b=w;return i}},Y=class{constructor(e,t){this.j=e,this.H=t,this.L=t}reset(){this.L=this.H}update(e){return this.F(this.j,e,this.L)}q(e){if(255&~(e>>24))e+=1<<24;else{let t=e>>16&255,n=e>>8&255,r=255&e;255===t?(t=0,255===n?(n=0,255===r?r=0:++r):++n):++t,e=0,e+=t<<16,e+=n<<8,e+=r}return e}G(e){0===(e[0]=this.q(e[0]))&&(e[1]=this.q(e[1]))}F(e,t,n){let r;if(!(r=t.length))return[];const s=_.l(t);for(let s=0;r>s;s+=4){this.G(n);const r=e.encrypt(n);t[s]^=r[0],t[s+1]^=r[1],t[s+2]^=r[2],t[s+3]^=r[3]}return _.u(t,s)}},Z=V.R;let $=q&&J&&typeof G.importKey==S,ee=q&&J&&typeof G.deriveBits==S;class te extends p{constructor({password:e,rawPassword:n,signed:r,encryptionStrength:o,checkPasswordOnly:c}){super({start(){t.assign(this,{ready:new u((e=>this.J=e)),password:ie(e,n),signed:r,X:o-1,pending:new i})},async transform(e,t){const n=this,{password:r,X:o,J:f,ready:a}=n;r?(await(async(e,t,n,r)=>{const i=await se(e,t,n,ce(r,0,j[t])),o=ce(r,j[t]);if(i[0]!=o[0]||i[1]!=o[1])throw new s(B)})(n,o,r,ce(e,0,j[o]+2)),e=ce(e,j[o]+2),c?t.error(new s(M)):f()):await a;const l=new i(e.length-L-(e.length-L)%K);t.enqueue(re(n,e,l,0,L,!0))},async flush(e){const{signed:t,Y:n,Z:r,pending:o,ready:c}=this;if(r&&n){await c;const f=ce(o,0,o.length-L),a=ce(o,o.length-L);let l=new i;if(f.length){const e=ae(Q,f);r.update(e);const t=n.update(e);l=fe(Q,t)}if(t){const e=ce(fe(Q,r.digest()),0,L);for(let t=0;L>t;t++)if(e[t]!=a[t])throw new s(E)}e.enqueue(l)}}})}}class ne extends p{constructor({password:e,rawPassword:n,encryptionStrength:r}){let s;super({start(){t.assign(this,{ready:new u((e=>this.J=e)),password:ie(e,n),X:r-1,pending:new i})},async transform(e,t){const n=this,{password:r,X:s,J:o,ready:c}=n;let f=new i;r?(f=await(async(e,t,n)=>{const r=U(new i(j[t]));return oe(r,await se(e,t,n,r))})(n,s,r),o()):await c;const a=new i(f.length+e.length-e.length%K);a.set(f,0),t.enqueue(re(n,e,a,f.length,0))},async flush(e){const{Y:t,Z:n,pending:r,ready:o}=this;if(n&&t){await o;let c=new i;if(r.length){const e=t.update(ae(Q,r));n.update(e),c=fe(Q,e)}s.signature=fe(Q,n.digest()).slice(0,L),e.enqueue(oe(c,s.signature))}}}),s=this}}function re(e,t,n,r,s,o){const{Y:c,Z:f,pending:a}=e,l=t.length-s;let u;for(a.length&&(t=oe(a,t),n=((e,t)=>{if(t&&t>e.length){const n=e;(e=new i(t)).set(n,0)}return e})(n,l-l%K)),u=0;l-K>=u;u+=K){const e=ae(Q,ce(t,u,u+K));o&&f.update(e);const s=c.update(e);o||f.update(s),n.set(fe(Q,s),u+r)}return e.pending=ce(t,u),n}async function se(n,r,s,o){n.password=null;const c=await(async(e,t,n,r,s)=>{if(!$)return V.importKey(t);try{return await G.importKey("raw",t,n,!1,s)}catch(e){return $=!1,V.importKey(t)}})(0,s,O,0,W),f=await(async(e,t,n)=>{if(!ee)return V.B(t,e.salt,T.iterations,n);try{return await G.deriveBits(e,t,n)}catch(r){return ee=!1,V.B(t,e.salt,T.iterations,n)}})(t.assign({salt:o},T),c,8*(2*H[r]+2)),a=new i(f),l=ae(Q,ce(a,0,H[r])),u=ae(Q,ce(a,H[r],2*H[r])),w=ce(a,2*H[r]);return t.assign(n,{keys:{key:l,$:u,passwordVerification:w},Y:new Y(new X(l),e.from(F)),Z:new Z(u)}),w}function ie(e,t){return t===k?(e=>{if(typeof w==v){const t=new i((e=unescape(encodeURIComponent(e))).length);for(let n=0;n<t.length;n++)t[n]=e.charCodeAt(n);return t}return(new w).encode(e)})(e):t}function oe(e,t){let n=e;return e.length+t.length&&(n=new i(e.length+t.length),n.set(e,0),n.set(t,e.length)),n}function ce(e,t,n){return e.subarray(t,n)}function fe(e,t){return e.p(t)}function ae(e,t){return e.m(t)}class le extends p{constructor({password:e,passwordVerification:n,checkPasswordOnly:r}){super({start(){t.assign(this,{password:e,passwordVerification:n}),de(this,e)},transform(e,t){const n=this;if(n.password){const t=we(n,e.subarray(0,12));if(n.password=null,t[11]!=n.passwordVerification)throw new s(B);e=e.subarray(12)}r?t.error(new s(M)):t.enqueue(we(n,e))}})}}class ue extends p{constructor({password:e,passwordVerification:n}){super({start(){t.assign(this,{password:e,passwordVerification:n}),de(this,e)},transform(e,t){const n=this;let r,s;if(n.password){n.password=null;const t=U(new i(12));t[11]=n.passwordVerification,r=new i(e.length+t.length),r.set(he(n,t),0),s=12}else r=new i(e.length),s=0;r.set(he(n,e),s),t.enqueue(r)}})}}function we(e,t){const n=new i(t.length);for(let r=0;r<t.length;r++)n[r]=ye(e)^t[r],pe(e,n[r]);return n}function he(e,t){const n=new i(t.length);for(let r=0;r<t.length;r++)n[r]=ye(e)^t[r],pe(e,t[r]);return n}function de(e,n){const r=[305419896,591751049,878082192];t.assign(e,{keys:r,ee:new x(r[0]),te:new x(r[2])});for(let t=0;t<n.length;t++)pe(e,n.charCodeAt(t))}function pe(e,t){let[n,s,i]=e.keys;e.ee.append([t]),n=~e.ee.get(),s=be(r.imul(be(s+me(n)),134775813)+1),e.te.append([s>>>24]),i=~e.te.get(),e.keys=[n,s,i]}function ye(e){const t=2|e.keys[2];return me(r.imul(t,1^t)>>>8)}function me(e){return 255&e}function be(e){return 4294967295&e}const ge="deflate-raw";class ke extends p{constructor(e,{chunkSize:t,CompressionStream:n,CompressionStreamNative:r}){super({});const{compressed:s,encrypted:i,useCompressionStream:o,zipCrypto:c,signed:f,level:a}=e,u=this;let w,h,d=Se(super.readable);i&&!c||!f||(w=new A,d=xe(d,w)),s&&(d=Ce(d,o,{level:a,chunkSize:t},r,n)),i&&(c?d=xe(d,new ue(e)):(h=new ne(e),d=xe(d,h))),ze(u,d,(()=>{let e;i&&!c&&(e=h.signature),i&&!c||!f||(e=new l(w.value.buffer).getUint32(0)),u.signature=e}))}}class ve extends p{constructor(e,{chunkSize:t,DecompressionStream:n,DecompressionStreamNative:r}){super({});const{zipCrypto:i,encrypted:o,signed:c,signature:f,compressed:a,useCompressionStream:u}=e;let w,h,d=Se(super.readable);o&&(i?d=xe(d,new le(e)):(h=new te(e),d=xe(d,h))),a&&(d=Ce(d,u,{chunkSize:t},r,n)),o&&!i||!c||(w=new A,d=xe(d,w)),ze(this,d,(()=>{if((!o||i)&&c){const e=new l(w.value.buffer);if(f!=e.getUint32(0,!1))throw new s(E)}}))}}function Se(e){return xe(e,new p({transform(e,t){e&&e.length&&t.enqueue(e)}}))}function ze(e,n,r){n=xe(n,new p({flush:r})),t.defineProperty(e,"readable",{get:()=>n})}function Ce(e,t,n,r,s){try{e=xe(e,new(t&&r?r:s)(ge,n))}catch(r){if(!t)return e;try{e=xe(e,new s(ge,n))}catch(t){return e}}return e}function xe(e,t){return e.pipeThrough(t)}const Ae="data",_e="close";class Ie extends p{constructor(e,n){super({});const r=this,{codecType:s}=e;let i;s.startsWith("deflate")?i=ke:s.startsWith("inflate")&&(i=ve);let o=0,c=0;const f=new i(e,n),a=super.readable,l=new p({transform(e,t){e&&e.length&&(c+=e.length,t.enqueue(e))},flush(){t.assign(r,{inputSize:c})}}),u=new p({transform(e,t){e&&e.length&&(o+=e.length,t.enqueue(e))},flush(){const{signature:e}=f;t.assign(r,{signature:e,outputSize:o,inputSize:c})}});t.defineProperty(r,"readable",{get:()=>a.pipeThrough(l).pipeThrough(f).pipeThrough(u)})}}class Pe extends p{constructor(e){let t;super({transform:function n(r,s){if(t){const e=new i(t.length+r.length);e.set(t),e.set(r,t.length),r=e,t=null}r.length>e?(s.enqueue(r.slice(0,e)),n(r.slice(e),s)):t=r},flush(e){t&&t.length&&e.enqueue(t)}})}}const De=new a,Ve=new a;let Re,Be=0,Ee=!0;async function Me(e){try{const{options:t,scripts:r,config:s}=e;if(r&&r.length)try{Ee?importScripts.apply(k,r):await Ue(r)}catch(e){Ee=!1,await Ue(r)}self.initCodec&&self.initCodec(),s.CompressionStreamNative=self.CompressionStream,s.DecompressionStreamNative=self.DecompressionStream,self.Deflate&&(s.CompressionStream=new z(self.Deflate)),self.Inflate&&(s.DecompressionStream=new z(self.Inflate));const i={highWaterMark:1},o=e.readable||new y({async pull(e){const t=new u((e=>De.set(Be,e)));Ke({type:"pull",messageId:Be}),Be=(Be+1)%n.MAX_SAFE_INTEGER;const{value:r,done:s}=await t;e.enqueue(r),s&&e.close()}},i),c=e.writable||new m({async write(e){let t;const r=new u((e=>t=e));Ve.set(Be,t),Ke({type:Ae,value:e,messageId:Be}),Be=(Be+1)%n.MAX_SAFE_INTEGER,await r}},i),f=new Ie(t,s);Re=new AbortController;const{signal:a}=Re;await o.pipeThrough(f).pipeThrough(new Pe(s.chunkSize)).pipeTo(c,{signal:a,preventClose:!0,preventAbort:!0}),await c.getWriter().close();const{signature:l,inputSize:w,outputSize:h}=f;Ke({type:_e,result:{signature:l,inputSize:w,outputSize:h}})}catch(e){Ne(e)}}async function Ue(e){for(const t of e)await import(t)}function Ke(e){let{value:t}=e;if(t)if(t.length)try{t=new i(t),e.value=t.buffer,d(e,[e.value])}catch(t){d(e)}else d(e);else d(e)}function Ne(e=new s("Unknown error")){const{message:t,stack:n,code:r,name:i}=e;d({error:{message:t,stack:n,code:r,name:i}})}addEventListener("message",(({data:e})=>{const{type:t,messageId:n,value:r,done:s}=e;try{if("start"==t&&Me(e),t==Ae){const e=De.get(n);De.delete(n),e({value:new i(r),done:s})}if("ack"==t){const e=Ve.get(n);Ve.delete(n),e()}t==_e&&Re.abort()}catch(e){Ne(e)}}));const Oe=-2;function Te(t){return We(t.map((([t,n])=>new e(t).fill(n,0,t))))}function We(t){return t.reduce(((t,n)=>t.concat(e.isArray(n)?We(n):n)),[])}const je=[0,1,2,3].concat(...Te([[2,4],[2,5],[4,6],[4,7],[8,8],[8,9],[16,10],[16,11],[32,12],[32,13],[64,14],[64,15],[2,0],[1,16],[1,17],[2,18],[2,19],[4,20],[4,21],[8,22],[8,23],[16,24],[16,25],[32,26],[32,27],[64,28],[64,29]]));function He(){const e=this;function t(e,t){let n=0;do{n|=1&e,e>>>=1,n<<=1}while(--t>0);return n>>>1}e.ne=n=>{const s=e.re,i=e.ie.se,o=e.ie.oe;let c,f,a,l=-1;for(n.ce=0,n.fe=573,c=0;o>c;c++)0!==s[2*c]?(n.ae[++n.ce]=l=c,n.le[c]=0):s[2*c+1]=0;for(;2>n.ce;)a=n.ae[++n.ce]=2>l?++l:0,s[2*a]=1,n.le[a]=0,n.ue--,i&&(n.we-=i[2*a+1]);for(e.he=l,c=r.floor(n.ce/2);c>=1;c--)n.de(s,c);a=o;do{c=n.ae[1],n.ae[1]=n.ae[n.ce--],n.de(s,1),f=n.ae[1],n.ae[--n.fe]=c,n.ae[--n.fe]=f,s[2*a]=s[2*c]+s[2*f],n.le[a]=r.max(n.le[c],n.le[f])+1,s[2*c+1]=s[2*f+1]=a,n.ae[1]=a++,n.de(s,1)}while(n.ce>=2);n.ae[--n.fe]=n.ae[1],(t=>{const n=e.re,r=e.ie.se,s=e.ie.pe,i=e.ie.ye,o=e.ie.me;let c,f,a,l,u,w,h=0;for(l=0;15>=l;l++)t.be[l]=0;for(n[2*t.ae[t.fe]+1]=0,c=t.fe+1;573>c;c++)f=t.ae[c],l=n[2*n[2*f+1]+1]+1,l>o&&(l=o,h++),n[2*f+1]=l,f>e.he||(t.be[l]++,u=0,i>f||(u=s[f-i]),w=n[2*f],t.ue+=w*(l+u),r&&(t.we+=w*(r[2*f+1]+u)));if(0!==h){do{for(l=o-1;0===t.be[l];)l--;t.be[l]--,t.be[l+1]+=2,t.be[o]--,h-=2}while(h>0);for(l=o;0!==l;l--)for(f=t.be[l];0!==f;)a=t.ae[--c],a>e.he||(n[2*a+1]!=l&&(t.ue+=(l-n[2*a+1])*n[2*a],n[2*a+1]=l),f--)}})(n),((e,n,r)=>{const s=[];let i,o,c,f=0;for(i=1;15>=i;i++)s[i]=f=f+r[i-1]<<1;for(o=0;n>=o;o++)c=e[2*o+1],0!==c&&(e[2*o]=t(s[c]++,c))})(s,e.he,n.be)}}function Le(e,t,n,r,s){const i=this;i.se=e,i.pe=t,i.ye=n,i.oe=r,i.me=s}He.ge=[0,1,2,3,4,5,6,7].concat(...Te([[2,8],[2,9],[2,10],[2,11],[4,12],[4,13],[4,14],[4,15],[8,16],[8,17],[8,18],[8,19],[16,20],[16,21],[16,22],[16,23],[32,24],[32,25],[32,26],[31,27],[1,28]])),He.ke=[0,1,2,3,4,5,6,7,8,10,12,14,16,20,24,28,32,40,48,56,64,80,96,112,128,160,192,224,0],He.ve=[0,1,2,3,4,6,8,12,16,24,32,48,64,96,128,192,256,384,512,768,1024,1536,2048,3072,4096,6144,8192,12288,16384,24576],He.Se=e=>256>e?je[e]:je[256+(e>>>7)],He.ze=[0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0],He.Ce=[0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13],He.xe=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7],He.Ae=[16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15];const Fe=Te([[144,8],[112,9],[24,7],[8,8]]);Le._e=We([12,140,76,204,44,172,108,236,28,156,92,220,60,188,124,252,2,130,66,194,34,162,98,226,18,146,82,210,50,178,114,242,10,138,74,202,42,170,106,234,26,154,90,218,58,186,122,250,6,134,70,198,38,166,102,230,22,150,86,214,54,182,118,246,14,142,78,206,46,174,110,238,30,158,94,222,62,190,126,254,1,129,65,193,33,161,97,225,17,145,81,209,49,177,113,241,9,137,73,201,41,169,105,233,25,153,89,217,57,185,121,249,5,133,69,197,37,165,101,229,21,149,85,213,53,181,117,245,13,141,77,205,45,173,109,237,29,157,93,221,61,189,125,253,19,275,147,403,83,339,211,467,51,307,179,435,115,371,243,499,11,267,139,395,75,331,203,459,43,299,171,427,107,363,235,491,27,283,155,411,91,347,219,475,59,315,187,443,123,379,251,507,7,263,135,391,71,327,199,455,39,295,167,423,103,359,231,487,23,279,151,407,87,343,215,471,55,311,183,439,119,375,247,503,15,271,143,399,79,335,207,463,47,303,175,431,111,367,239,495,31,287,159,415,95,351,223,479,63,319,191,447,127,383,255,511,0,64,32,96,16,80,48,112,8,72,40,104,24,88,56,120,4,68,36,100,20,84,52,116,3,131,67,195,35,163,99,227].map(((e,t)=>[e,Fe[t]])));const qe=Te([[30,5]]);function Ge(e,t,n,r,s){const i=this;i.Ie=e,i.Pe=t,i.De=n,i.Ve=r,i.Re=s}Le.Be=We([0,16,8,24,4,20,12,28,2,18,10,26,6,22,14,30,1,17,9,25,5,21,13,29,3,19,11,27,7,23].map(((e,t)=>[e,qe[t]]))),Le.Ee=new Le(Le._e,He.ze,257,286,15),Le.Me=new Le(Le.Be,He.Ce,0,30,15),Le.Ue=new Le(null,He.xe,0,19,7);const Je=[new Ge(0,0,0,0,0),new Ge(4,4,8,4,1),new Ge(4,5,16,8,1),new Ge(4,6,32,32,1),new Ge(4,4,16,16,2),new Ge(8,16,32,32,2),new Ge(8,16,128,128,2),new Ge(8,32,128,256,2),new Ge(32,128,258,1024,2),new Ge(32,258,258,4096,2)],Qe=["need dictionary","stream end","","","stream error","data error","","buffer error","",""],Xe=113,Ye=666,Ze=262;function $e(e,t,n,r){const s=e[2*t],i=e[2*n];return i>s||s==i&&r[t]<=r[n]}function et(){const e=this;let t,n,s,c,f,a,l,u,w,h,d,p,y,m,b,g,k,v,S,z,C,x,A,_,I,P,D,V,R,B,E,M,U;const K=new He,N=new He,O=new He;let T,W,j,H,L,F;function q(){let t;for(t=0;286>t;t++)E[2*t]=0;for(t=0;30>t;t++)M[2*t]=0;for(t=0;19>t;t++)U[2*t]=0;E[512]=1,e.ue=e.we=0,W=j=0}function G(e,t){let n,r=-1,s=e[1],i=0,o=7,c=4;0===s&&(o=138,c=3),e[2*(t+1)+1]=65535;for(let f=0;t>=f;f++)n=s,s=e[2*(f+1)+1],++i<o&&n==s||(c>i?U[2*n]+=i:0!==n?(n!=r&&U[2*n]++,U[32]++):i>10?U[36]++:U[34]++,i=0,r=n,0===s?(o=138,c=3):n==s?(o=6,c=3):(o=7,c=4))}function J(t){e.Ke[e.pending++]=t}function Q(e){J(255&e),J(e>>>8&255)}function X(e,t){let n;const r=t;F>16-r?(n=e,L|=n<<F&65535,Q(L),L=n>>>16-F,F+=r-16):(L|=e<<F&65535,F+=r)}function Y(e,t){const n=2*e;X(65535&t[n],65535&t[n+1])}function Z(e,t){let n,r,s=-1,i=e[1],o=0,c=7,f=4;for(0===i&&(c=138,f=3),n=0;t>=n;n++)if(r=i,i=e[2*(n+1)+1],++o>=c||r!=i){if(f>o)do{Y(r,U)}while(0!=--o);else 0!==r?(r!=s&&(Y(r,U),o--),Y(16,U),X(o-3,2)):o>10?(Y(18,U),X(o-11,7)):(Y(17,U),X(o-3,3));o=0,s=r,0===i?(c=138,f=3):r==i?(c=6,f=3):(c=7,f=4)}}function $(){16==F?(Q(L),L=0,F=0):8>F||(J(255&L),L>>>=8,F-=8)}function ee(t,n){let s,i,o;if(e.Ne[W]=t,e.Oe[W]=255&n,W++,0===t?E[2*n]++:(j++,t--,E[2*(He.ge[n]+256+1)]++,M[2*He.Se(t)]++),!(8191&W)&&D>2){for(s=8*W,i=C-k,o=0;30>o;o++)s+=M[2*o]*(5+He.Ce[o]);if(s>>>=3,j<r.floor(W/2)&&s<r.floor(i/2))return!0}return W==T-1}function te(t,n){let r,s,i,o,c=0;if(0!==W)do{r=e.Ne[c],s=e.Oe[c],c++,0===r?Y(s,t):(i=He.ge[s],Y(i+256+1,t),o=He.ze[i],0!==o&&(s-=He.ke[i],X(s,o)),r--,i=He.Se(r),Y(i,n),o=He.Ce[i],0!==o&&(r-=He.ve[i],X(r,o)))}while(W>c);Y(256,t),H=t[513]}function ne(){F>8?Q(L):F>0&&J(255&L),L=0,F=0}function re(t,n,r){X(0+(r?1:0),3),((t,n)=>{ne(),H=8,Q(n),Q(~n),e.Ke.set(u.subarray(t,t+n),e.pending),e.pending+=n})(t,n)}function se(n){((t,n,r)=>{let s,i,o=0;D>0?(K.ne(e),N.ne(e),o=(()=>{let t;for(G(E,K.he),G(M,N.he),O.ne(e),t=18;t>=3&&0===U[2*He.Ae[t]+1];t--);return e.ue+=14+3*(t+1),t})(),s=e.ue+3+7>>>3,i=e.we+3+7>>>3,i>s||(s=i)):s=i=n+5,n+4>s||-1==t?i==s?(X(2+(r?1:0),3),te(Le._e,Le.Be)):(X(4+(r?1:0),3),((e,t,n)=>{let r;for(X(e-257,5),X(t-1,5),X(n-4,4),r=0;n>r;r++)X(U[2*He.Ae[r]+1],3);Z(E,e-1),Z(M,t-1)})(K.he+1,N.he+1,o+1),te(E,M)):re(t,n,r),q(),r&&ne()})(0>k?-1:k,C-k,n),k=C,t.Te()}function ie(){let e,n,r,s;do{if(s=w-A-C,0===s&&0===C&&0===A)s=f;else if(-1==s)s--;else if(C>=f+f-Ze){u.set(u.subarray(f,f+f),0),x-=f,C-=f,k-=f,e=y,r=e;do{n=65535&d[--r],d[r]=f>n?0:n-f}while(0!=--e);e=f,r=e;do{n=65535&h[--r],h[r]=f>n?0:n-f}while(0!=--e);s+=f}if(0===t.We)return;e=t.je(u,C+A,s),A+=e,3>A||(p=255&u[C],p=(p<<g^255&u[C+1])&b)}while(Ze>A&&0!==t.We)}function oe(e){let t,n,r=I,s=C,i=_;const o=C>f-Ze?C-(f-Ze):0;let c=B;const a=l,w=C+258;let d=u[s+i-1],p=u[s+i];R>_||(r>>=2),c>A&&(c=A);do{if(t=e,u[t+i]==p&&u[t+i-1]==d&&u[t]==u[s]&&u[++t]==u[s+1]){s+=2,t++;do{}while(u[++s]==u[++t]&&u[++s]==u[++t]&&u[++s]==u[++t]&&u[++s]==u[++t]&&u[++s]==u[++t]&&u[++s]==u[++t]&&u[++s]==u[++t]&&u[++s]==u[++t]&&w>s);if(n=258-(w-s),s=w-258,n>i){if(x=e,i=n,n>=c)break;d=u[s+i-1],p=u[s+i]}}}while((e=65535&h[e&a])>o&&0!=--r);return i>A?A:i}e.le=[],e.be=[],e.ae=[],E=[],M=[],U=[],e.de=(t,n)=>{const r=e.ae,s=r[n];let i=n<<1;for(;i<=e.ce&&(i<e.ce&&$e(t,r[i+1],r[i],e.le)&&i++,!$e(t,s,r[i],e.le));)r[n]=r[i],n=i,i<<=1;r[n]=s},e.He=(t,S,x,W,j,G)=>(W||(W=8),j||(j=8),G||(G=0),t.Le=null,-1==S&&(S=6),1>j||j>9||8!=W||9>x||x>15||0>S||S>9||0>G||G>2?Oe:(t.Fe=e,a=x,f=1<<a,l=f-1,m=j+7,y=1<<m,b=y-1,g=r.floor((m+3-1)/3),u=new i(2*f),h=[],d=[],T=1<<j+6,e.Ke=new i(4*T),s=4*T,e.Ne=new o(T),e.Oe=new i(T),D=S,V=G,(t=>(t.qe=t.Ge=0,t.Le=null,e.pending=0,e.Je=0,n=Xe,c=0,K.re=E,K.ie=Le.Ee,N.re=M,N.ie=Le.Me,O.re=U,O.ie=Le.Ue,L=0,F=0,H=8,q(),(()=>{w=2*f,d[y-1]=0;for(let e=0;y-1>e;e++)d[e]=0;P=Je[D].Pe,R=Je[D].Ie,B=Je[D].De,I=Je[D].Ve,C=0,k=0,A=0,v=_=2,z=0,p=0})(),0))(t))),e.Qe=()=>42!=n&&n!=Xe&&n!=Ye?Oe:(e.Oe=null,e.Ne=null,e.Ke=null,d=null,h=null,u=null,e.Fe=null,n==Xe?-3:0),e.Xe=(e,t,n)=>{let r=0;return-1==t&&(t=6),0>t||t>9||0>n||n>2?Oe:(Je[D].Re!=Je[t].Re&&0!==e.qe&&(r=e.Ye(1)),D!=t&&(D=t,P=Je[D].Pe,R=Je[D].Ie,B=Je[D].De,I=Je[D].Ve),V=n,r)},e.Ze=(e,t,r)=>{let s,i=r,o=0;if(!t||42!=n)return Oe;if(3>i)return 0;for(i>f-Ze&&(i=f-Ze,o=r-i),u.set(t.subarray(o,o+i),0),C=i,k=i,p=255&u[0],p=(p<<g^255&u[1])&b,s=0;i-3>=s;s++)p=(p<<g^255&u[s+2])&b,h[s&l]=d[p],d[p]=s;return 0},e.Ye=(r,i)=>{let o,w,m,I,R;if(i>4||0>i)return Oe;if(!r.$e||!r.et&&0!==r.We||n==Ye&&4!=i)return r.Le=Qe[4],Oe;if(0===r.tt)return r.Le=Qe[7],-5;var B;if(t=r,I=c,c=i,42==n&&(w=8+(a-8<<4)<<8,m=(D-1&255)>>1,m>3&&(m=3),w|=m<<6,0!==C&&(w|=32),w+=31-w%31,n=Xe,J((B=w)>>8&255),J(255&B)),0!==e.pending){if(t.Te(),0===t.tt)return c=-1,0}else if(0===t.We&&I>=i&&4!=i)return t.Le=Qe[7],-5;if(n==Ye&&0!==t.We)return r.Le=Qe[7],-5;if(0!==t.We||0!==A||0!=i&&n!=Ye){switch(R=-1,Je[D].Re){case 0:R=(e=>{let n,r=65535;for(r>s-5&&(r=s-5);;){if(1>=A){if(ie(),0===A&&0==e)return 0;if(0===A)break}if(C+=A,A=0,n=k+r,(0===C||C>=n)&&(A=C-n,C=n,se(!1),0===t.tt))return 0;if(C-k>=f-Ze&&(se(!1),0===t.tt))return 0}return se(4==e),0===t.tt?4==e?2:0:4==e?3:1})(i);break;case 1:R=(e=>{let n,r=0;for(;;){if(Ze>A){if(ie(),Ze>A&&0==e)return 0;if(0===A)break}if(3>A||(p=(p<<g^255&u[C+2])&b,r=65535&d[p],h[C&l]=d[p],d[p]=C),0===r||(C-r&65535)>f-Ze||2!=V&&(v=oe(r)),3>v)n=ee(0,255&u[C]),A--,C++;else if(n=ee(C-x,v-3),A-=v,v>P||3>A)C+=v,v=0,p=255&u[C],p=(p<<g^255&u[C+1])&b;else{v--;do{C++,p=(p<<g^255&u[C+2])&b,r=65535&d[p],h[C&l]=d[p],d[p]=C}while(0!=--v);C++}if(n&&(se(!1),0===t.tt))return 0}return se(4==e),0===t.tt?4==e?2:0:4==e?3:1})(i);break;case 2:R=(e=>{let n,r,s=0;for(;;){if(Ze>A){if(ie(),Ze>A&&0==e)return 0;if(0===A)break}if(3>A||(p=(p<<g^255&u[C+2])&b,s=65535&d[p],h[C&l]=d[p],d[p]=C),_=v,S=x,v=2,0!==s&&P>_&&f-Ze>=(C-s&65535)&&(2!=V&&(v=oe(s)),5>=v&&(1==V||3==v&&C-x>4096)&&(v=2)),3>_||v>_)if(0!==z){if(n=ee(0,255&u[C-1]),n&&se(!1),C++,A--,0===t.tt)return 0}else z=1,C++,A--;else{r=C+A-3,n=ee(C-1-S,_-3),A-=_-1,_-=2;do{++C>r||(p=(p<<g^255&u[C+2])&b,s=65535&d[p],h[C&l]=d[p],d[p]=C)}while(0!=--_);if(z=0,v=2,C++,n&&(se(!1),0===t.tt))return 0}}return 0!==z&&(n=ee(0,255&u[C-1]),z=0),se(4==e),0===t.tt?4==e?2:0:4==e?3:1})(i)}if(2!=R&&3!=R||(n=Ye),0==R||2==R)return 0===t.tt&&(c=-1),0;if(1==R){if(1==i)X(2,3),Y(256,Le._e),$(),9>1+H+10-F&&(X(2,3),Y(256,Le._e),$()),H=7;else if(re(0,0,!1),3==i)for(o=0;y>o;o++)d[o]=0;if(t.Te(),0===t.tt)return c=-1,0}}return 4!=i?0:1}}function tt(){const e=this;e.nt=0,e.rt=0,e.We=0,e.qe=0,e.tt=0,e.Ge=0}function nt(e){const t=new tt,n=(o=e&&e.chunkSize?e.chunkSize:65536)+5*(r.floor(o/16383)+1);var o;const c=new i(n);let f=e?e.level:-1;void 0===f&&(f=-1),t.He(f),t.$e=c,this.append=(e,r)=>{let o,f,a=0,l=0,u=0;const w=[];if(e.length){t.nt=0,t.et=e,t.We=e.length;do{if(t.rt=0,t.tt=n,o=t.Ye(0),0!=o)throw new s("deflating: "+t.Le);t.rt&&(t.rt==n?w.push(new i(c)):w.push(c.subarray(0,t.rt))),u+=t.rt,r&&t.nt>0&&t.nt!=a&&(r(t.nt),a=t.nt)}while(t.We>0||0===t.tt);return w.length>1?(f=new i(u),w.forEach((e=>{f.set(e,l),l+=e.length}))):f=w[0]?new i(w[0]):new i,f}},this.flush=()=>{let e,r,o=0,f=0;const a=[];do{if(t.rt=0,t.tt=n,e=t.Ye(4),1!=e&&0!=e)throw new s("deflating: "+t.Le);n-t.tt>0&&a.push(c.slice(0,t.rt)),f+=t.rt}while(t.We>0||0===t.tt);return t.Qe(),r=new i(f),a.forEach((e=>{r.set(e,o),o+=e.length})),r}}tt.prototype={He(e,t){const n=this;return n.Fe=new et,t||(t=15),n.Fe.He(n,e,t)},Ye(e){const t=this;return t.Fe?t.Fe.Ye(t,e):Oe},Qe(){const e=this;if(!e.Fe)return Oe;const t=e.Fe.Qe();return e.Fe=null,t},Xe(e,t){const n=this;return n.Fe?n.Fe.Xe(n,e,t):Oe},Ze(e,t){const n=this;return n.Fe?n.Fe.Ze(n,e,t):Oe},je(e,t,n){const r=this;let s=r.We;return s>n&&(s=n),0===s?0:(r.We-=s,e.set(r.et.subarray(r.nt,r.nt+s),t),r.nt+=s,r.qe+=s,s)},Te(){const e=this;let t=e.Fe.pending;t>e.tt&&(t=e.tt),0!==t&&(e.$e.set(e.Fe.Ke.subarray(e.Fe.Je,e.Fe.Je+t),e.rt),e.rt+=t,e.Fe.Je+=t,e.Ge+=t,e.tt-=t,e.Fe.pending-=t,0===e.Fe.pending&&(e.Fe.Je=0))}};const rt=-2,st=-3,it=-5,ot=[0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535],ct=[96,7,256,0,8,80,0,8,16,84,8,115,82,7,31,0,8,112,0,8,48,0,9,192,80,7,10,0,8,96,0,8,32,0,9,160,0,8,0,0,8,128,0,8,64,0,9,224,80,7,6,0,8,88,0,8,24,0,9,144,83,7,59,0,8,120,0,8,56,0,9,208,81,7,17,0,8,104,0,8,40,0,9,176,0,8,8,0,8,136,0,8,72,0,9,240,80,7,4,0,8,84,0,8,20,85,8,227,83,7,43,0,8,116,0,8,52,0,9,200,81,7,13,0,8,100,0,8,36,0,9,168,0,8,4,0,8,132,0,8,68,0,9,232,80,7,8,0,8,92,0,8,28,0,9,152,84,7,83,0,8,124,0,8,60,0,9,216,82,7,23,0,8,108,0,8,44,0,9,184,0,8,12,0,8,140,0,8,76,0,9,248,80,7,3,0,8,82,0,8,18,85,8,163,83,7,35,0,8,114,0,8,50,0,9,196,81,7,11,0,8,98,0,8,34,0,9,164,0,8,2,0,8,130,0,8,66,0,9,228,80,7,7,0,8,90,0,8,26,0,9,148,84,7,67,0,8,122,0,8,58,0,9,212,82,7,19,0,8,106,0,8,42,0,9,180,0,8,10,0,8,138,0,8,74,0,9,244,80,7,5,0,8,86,0,8,22,192,8,0,83,7,51,0,8,118,0,8,54,0,9,204,81,7,15,0,8,102,0,8,38,0,9,172,0,8,6,0,8,134,0,8,70,0,9,236,80,7,9,0,8,94,0,8,30,0,9,156,84,7,99,0,8,126,0,8,62,0,9,220,82,7,27,0,8,110,0,8,46,0,9,188,0,8,14,0,8,142,0,8,78,0,9,252,96,7,256,0,8,81,0,8,17,85,8,131,82,7,31,0,8,113,0,8,49,0,9,194,80,7,10,0,8,97,0,8,33,0,9,162,0,8,1,0,8,129,0,8,65,0,9,226,80,7,6,0,8,89,0,8,25,0,9,146,83,7,59,0,8,121,0,8,57,0,9,210,81,7,17,0,8,105,0,8,41,0,9,178,0,8,9,0,8,137,0,8,73,0,9,242,80,7,4,0,8,85,0,8,21,80,8,258,83,7,43,0,8,117,0,8,53,0,9,202,81,7,13,0,8,101,0,8,37,0,9,170,0,8,5,0,8,133,0,8,69,0,9,234,80,7,8,0,8,93,0,8,29,0,9,154,84,7,83,0,8,125,0,8,61,0,9,218,82,7,23,0,8,109,0,8,45,0,9,186,0,8,13,0,8,141,0,8,77,0,9,250,80,7,3,0,8,83,0,8,19,85,8,195,83,7,35,0,8,115,0,8,51,0,9,198,81,7,11,0,8,99,0,8,35,0,9,166,0,8,3,0,8,131,0,8,67,0,9,230,80,7,7,0,8,91,0,8,27,0,9,150,84,7,67,0,8,123,0,8,59,0,9,214,82,7,19,0,8,107,0,8,43,0,9,182,0,8,11,0,8,139,0,8,75,0,9,246,80,7,5,0,8,87,0,8,23,192,8,0,83,7,51,0,8,119,0,8,55,0,9,206,81,7,15,0,8,103,0,8,39,0,9,174,0,8,7,0,8,135,0,8,71,0,9,238,80,7,9,0,8,95,0,8,31,0,9,158,84,7,99,0,8,127,0,8,63,0,9,222,82,7,27,0,8,111,0,8,47,0,9,190,0,8,15,0,8,143,0,8,79,0,9,254,96,7,256,0,8,80,0,8,16,84,8,115,82,7,31,0,8,112,0,8,48,0,9,193,80,7,10,0,8,96,0,8,32,0,9,161,0,8,0,0,8,128,0,8,64,0,9,225,80,7,6,0,8,88,0,8,24,0,9,145,83,7,59,0,8,120,0,8,56,0,9,209,81,7,17,0,8,104,0,8,40,0,9,177,0,8,8,0,8,136,0,8,72,0,9,241,80,7,4,0,8,84,0,8,20,85,8,227,83,7,43,0,8,116,0,8,52,0,9,201,81,7,13,0,8,100,0,8,36,0,9,169,0,8,4,0,8,132,0,8,68,0,9,233,80,7,8,0,8,92,0,8,28,0,9,153,84,7,83,0,8,124,0,8,60,0,9,217,82,7,23,0,8,108,0,8,44,0,9,185,0,8,12,0,8,140,0,8,76,0,9,249,80,7,3,0,8,82,0,8,18,85,8,163,83,7,35,0,8,114,0,8,50,0,9,197,81,7,11,0,8,98,0,8,34,0,9,165,0,8,2,0,8,130,0,8,66,0,9,229,80,7,7,0,8,90,0,8,26,0,9,149,84,7,67,0,8,122,0,8,58,0,9,213,82,7,19,0,8,106,0,8,42,0,9,181,0,8,10,0,8,138,0,8,74,0,9,245,80,7,5,0,8,86,0,8,22,192,8,0,83,7,51,0,8,118,0,8,54,0,9,205,81,7,15,0,8,102,0,8,38,0,9,173,0,8,6,0,8,134,0,8,70,0,9,237,80,7,9,0,8,94,0,8,30,0,9,157,84,7,99,0,8,126,0,8,62,0,9,221,82,7,27,0,8,110,0,8,46,0,9,189,0,8,14,0,8,142,0,8,78,0,9,253,96,7,256,0,8,81,0,8,17,85,8,131,82,7,31,0,8,113,0,8,49,0,9,195,80,7,10,0,8,97,0,8,33,0,9,163,0,8,1,0,8,129,0,8,65,0,9,227,80,7,6,0,8,89,0,8,25,0,9,147,83,7,59,0,8,121,0,8,57,0,9,211,81,7,17,0,8,105,0,8,41,0,9,179,0,8,9,0,8,137,0,8,73,0,9,243,80,7,4,0,8,85,0,8,21,80,8,258,83,7,43,0,8,117,0,8,53,0,9,203,81,7,13,0,8,101,0,8,37,0,9,171,0,8,5,0,8,133,0,8,69,0,9,235,80,7,8,0,8,93,0,8,29,0,9,155,84,7,83,0,8,125,0,8,61,0,9,219,82,7,23,0,8,109,0,8,45,0,9,187,0,8,13,0,8,141,0,8,77,0,9,251,80,7,3,0,8,83,0,8,19,85,8,195,83,7,35,0,8,115,0,8,51,0,9,199,81,7,11,0,8,99,0,8,35,0,9,167,0,8,3,0,8,131,0,8,67,0,9,231,80,7,7,0,8,91,0,8,27,0,9,151,84,7,67,0,8,123,0,8,59,0,9,215,82,7,19,0,8,107,0,8,43,0,9,183,0,8,11,0,8,139,0,8,75,0,9,247,80,7,5,0,8,87,0,8,23,192,8,0,83,7,51,0,8,119,0,8,55,0,9,207,81,7,15,0,8,103,0,8,39,0,9,175,0,8,7,0,8,135,0,8,71,0,9,239,80,7,9,0,8,95,0,8,31,0,9,159,84,7,99,0,8,127,0,8,63,0,9,223,82,7,27,0,8,111,0,8,47,0,9,191,0,8,15,0,8,143,0,8,79,0,9,255],ft=[80,5,1,87,5,257,83,5,17,91,5,4097,81,5,5,89,5,1025,85,5,65,93,5,16385,80,5,3,88,5,513,84,5,33,92,5,8193,82,5,9,90,5,2049,86,5,129,192,5,24577,80,5,2,87,5,385,83,5,25,91,5,6145,81,5,7,89,5,1537,85,5,97,93,5,24577,80,5,4,88,5,769,84,5,49,92,5,12289,82,5,13,90,5,3073,86,5,193,192,5,24577],at=[3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258,0,0],lt=[0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,112,112],ut=[1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577],wt=[0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13];function ht(){let e,t,n,r,s,i;function o(e,t,o,c,f,a,l,u,w,h,d){let p,y,m,b,g,k,v,S,z,C,x,A,_,I,P;C=0,g=o;do{n[e[t+C]]++,C++,g--}while(0!==g);if(n[0]==o)return l[0]=-1,u[0]=0,0;for(S=u[0],k=1;15>=k&&0===n[k];k++);for(v=k,k>S&&(S=k),g=15;0!==g&&0===n[g];g--);for(m=g,S>g&&(S=g),u[0]=S,I=1<<k;g>k;k++,I<<=1)if(0>(I-=n[k]))return st;if(0>(I-=n[g]))return st;for(n[g]+=I,i[1]=k=0,C=1,_=2;0!=--g;)i[_]=k+=n[C],_++,C++;g=0,C=0;do{0!==(k=e[t+C])&&(d[i[k]++]=g),C++}while(++g<o);for(o=i[m],i[0]=g=0,C=0,b=-1,A=-S,s[0]=0,x=0,P=0;m>=v;v++)for(p=n[v];0!=p--;){for(;v>A+S;){if(b++,A+=S,P=m-A,P=P>S?S:P,(y=1<<(k=v-A))>p+1&&(y-=p+1,_=v,P>k))for(;++k<P&&(y<<=1)>n[++_];)y-=n[_];if(P=1<<k,h[0]+P>1440)return st;s[b]=x=h[0],h[0]+=P,0!==b?(i[b]=g,r[0]=k,r[1]=S,k=g>>>A-S,r[2]=x-s[b-1]-k,w.set(r,3*(s[b-1]+k))):l[0]=x}for(r[1]=v-A,o>C?d[C]<c?(r[0]=256>d[C]?0:96,r[2]=d[C++]):(r[0]=a[d[C]-c]+16+64,r[2]=f[d[C++]-c]):r[0]=192,y=1<<v-A,k=g>>>A;P>k;k+=y)w.set(r,3*(x+k));for(k=1<<v-1;g&k;k>>>=1)g^=k;for(g^=k,z=(1<<A)-1;(g&z)!=i[b];)b--,A-=S,z=(1<<A)-1}return 0!==I&&1!=m?it:0}function c(o){let c;for(e||(e=[],t=[],n=new f(16),r=[],s=new f(15),i=new f(16)),t.length<o&&(t=[]),c=0;o>c;c++)t[c]=0;for(c=0;16>c;c++)n[c]=0;for(c=0;3>c;c++)r[c]=0;s.set(n.subarray(0,15),0),i.set(n.subarray(0,16),0)}this.st=(n,r,s,i,f)=>{let a;return c(19),e[0]=0,a=o(n,0,19,19,null,null,s,r,i,e,t),a==st?f.Le="oversubscribed dynamic bit lengths tree":a!=it&&0!==r[0]||(f.Le="incomplete dynamic bit lengths tree",a=st),a},this.it=(n,r,s,i,f,a,l,u,w)=>{let h;return c(288),e[0]=0,h=o(s,0,n,257,at,lt,a,i,u,e,t),0!=h||0===i[0]?(h==st?w.Le="oversubscribed literal/length tree":-4!=h&&(w.Le="incomplete literal/length tree",h=st),h):(c(288),h=o(s,n,r,0,ut,wt,l,f,u,e,t),0!=h||0===f[0]&&n>257?(h==st?w.Le="oversubscribed distance tree":h==it?(w.Le="incomplete distance tree",h=st):-4!=h&&(w.Le="empty distance tree with lengths",h=st),h):0)}}function dt(){const e=this;let t,n,r,s,i=0,o=0,c=0,f=0,a=0,l=0,u=0,w=0,h=0,d=0;function p(e,t,n,r,s,i,o,c){let f,a,l,u,w,h,d,p,y,m,b,g,k,v,S,z;d=c.nt,p=c.We,w=o.ot,h=o.ct,y=o.write,m=y<o.read?o.read-y-1:o.end-y,b=ot[e],g=ot[t];do{for(;20>h;)p--,w|=(255&c.ft(d++))<<h,h+=8;if(f=w&b,a=n,l=r,z=3*(l+f),0!==(u=a[z]))for(;;){if(w>>=a[z+1],h-=a[z+1],16&u){for(u&=15,k=a[z+2]+(w&ot[u]),w>>=u,h-=u;15>h;)p--,w|=(255&c.ft(d++))<<h,h+=8;for(f=w&g,a=s,l=i,z=3*(l+f),u=a[z];;){if(w>>=a[z+1],h-=a[z+1],16&u){for(u&=15;u>h;)p--,w|=(255&c.ft(d++))<<h,h+=8;if(v=a[z+2]+(w&ot[u]),w>>=u,h-=u,m-=k,v>y){S=y-v;do{S+=o.end}while(0>S);if(u=o.end-S,k>u){if(k-=u,y-S>0&&u>y-S)do{o.lt[y++]=o.lt[S++]}while(0!=--u);else o.lt.set(o.lt.subarray(S,S+u),y),y+=u,S+=u,u=0;S=0}}else S=y-v,y-S>0&&2>y-S?(o.lt[y++]=o.lt[S++],o.lt[y++]=o.lt[S++],k-=2):(o.lt.set(o.lt.subarray(S,S+2),y),y+=2,S+=2,k-=2);if(y-S>0&&k>y-S)do{o.lt[y++]=o.lt[S++]}while(0!=--k);else o.lt.set(o.lt.subarray(S,S+k),y),y+=k,S+=k,k=0;break}if(64&u)return c.Le="invalid distance code",k=c.We-p,k=k>h>>3?h>>3:k,p+=k,d-=k,h-=k<<3,o.ot=w,o.ct=h,c.We=p,c.qe+=d-c.nt,c.nt=d,o.write=y,st;f+=a[z+2],f+=w&ot[u],z=3*(l+f),u=a[z]}break}if(64&u)return 32&u?(k=c.We-p,k=k>h>>3?h>>3:k,p+=k,d-=k,h-=k<<3,o.ot=w,o.ct=h,c.We=p,c.qe+=d-c.nt,c.nt=d,o.write=y,1):(c.Le="invalid literal/length code",k=c.We-p,k=k>h>>3?h>>3:k,p+=k,d-=k,h-=k<<3,o.ot=w,o.ct=h,c.We=p,c.qe+=d-c.nt,c.nt=d,o.write=y,st);if(f+=a[z+2],f+=w&ot[u],z=3*(l+f),0===(u=a[z])){w>>=a[z+1],h-=a[z+1],o.lt[y++]=a[z+2],m--;break}}else w>>=a[z+1],h-=a[z+1],o.lt[y++]=a[z+2],m--}while(m>=258&&p>=10);return k=c.We-p,k=k>h>>3?h>>3:k,p+=k,d-=k,h-=k<<3,o.ot=w,o.ct=h,c.We=p,c.qe+=d-c.nt,c.nt=d,o.write=y,0}e.init=(e,i,o,c,f,a)=>{t=0,u=e,w=i,r=o,h=c,s=f,d=a,n=null},e.ut=(e,y,m)=>{let b,g,k,v,S,z,C,x=0,A=0,_=0;for(_=y.nt,v=y.We,x=e.ot,A=e.ct,S=e.write,z=S<e.read?e.read-S-1:e.end-S;;)switch(t){case 0:if(z>=258&&v>=10&&(e.ot=x,e.ct=A,y.We=v,y.qe+=_-y.nt,y.nt=_,e.write=S,m=p(u,w,r,h,s,d,e,y),_=y.nt,v=y.We,x=e.ot,A=e.ct,S=e.write,z=S<e.read?e.read-S-1:e.end-S,0!=m)){t=1==m?7:9;break}c=u,n=r,o=h,t=1;case 1:for(b=c;b>A;){if(0===v)return e.ot=x,e.ct=A,y.We=v,y.qe+=_-y.nt,y.nt=_,e.write=S,e.wt(y,m);m=0,v--,x|=(255&y.ft(_++))<<A,A+=8}if(g=3*(o+(x&ot[b])),x>>>=n[g+1],A-=n[g+1],k=n[g],0===k){f=n[g+2],t=6;break}if(16&k){a=15&k,i=n[g+2],t=2;break}if(!(64&k)){c=k,o=g/3+n[g+2];break}if(32&k){t=7;break}return t=9,y.Le="invalid literal/length code",m=st,e.ot=x,e.ct=A,y.We=v,y.qe+=_-y.nt,y.nt=_,e.write=S,e.wt(y,m);case 2:for(b=a;b>A;){if(0===v)return e.ot=x,e.ct=A,y.We=v,y.qe+=_-y.nt,y.nt=_,e.write=S,e.wt(y,m);m=0,v--,x|=(255&y.ft(_++))<<A,A+=8}i+=x&ot[b],x>>=b,A-=b,c=w,n=s,o=d,t=3;case 3:for(b=c;b>A;){if(0===v)return e.ot=x,e.ct=A,y.We=v,y.qe+=_-y.nt,y.nt=_,e.write=S,e.wt(y,m);m=0,v--,x|=(255&y.ft(_++))<<A,A+=8}if(g=3*(o+(x&ot[b])),x>>=n[g+1],A-=n[g+1],k=n[g],16&k){a=15&k,l=n[g+2],t=4;break}if(!(64&k)){c=k,o=g/3+n[g+2];break}return t=9,y.Le="invalid distance code",m=st,e.ot=x,e.ct=A,y.We=v,y.qe+=_-y.nt,y.nt=_,e.write=S,e.wt(y,m);case 4:for(b=a;b>A;){if(0===v)return e.ot=x,e.ct=A,y.We=v,y.qe+=_-y.nt,y.nt=_,e.write=S,e.wt(y,m);m=0,v--,x|=(255&y.ft(_++))<<A,A+=8}l+=x&ot[b],x>>=b,A-=b,t=5;case 5:for(C=S-l;0>C;)C+=e.end;for(;0!==i;){if(0===z&&(S==e.end&&0!==e.read&&(S=0,z=S<e.read?e.read-S-1:e.end-S),0===z&&(e.write=S,m=e.wt(y,m),S=e.write,z=S<e.read?e.read-S-1:e.end-S,S==e.end&&0!==e.read&&(S=0,z=S<e.read?e.read-S-1:e.end-S),0===z)))return e.ot=x,e.ct=A,y.We=v,y.qe+=_-y.nt,y.nt=_,e.write=S,e.wt(y,m);e.lt[S++]=e.lt[C++],z--,C==e.end&&(C=0),i--}t=0;break;case 6:if(0===z&&(S==e.end&&0!==e.read&&(S=0,z=S<e.read?e.read-S-1:e.end-S),0===z&&(e.write=S,m=e.wt(y,m),S=e.write,z=S<e.read?e.read-S-1:e.end-S,S==e.end&&0!==e.read&&(S=0,z=S<e.read?e.read-S-1:e.end-S),0===z)))return e.ot=x,e.ct=A,y.We=v,y.qe+=_-y.nt,y.nt=_,e.write=S,e.wt(y,m);m=0,e.lt[S++]=f,z--,t=0;break;case 7:if(A>7&&(A-=8,v++,_--),e.write=S,m=e.wt(y,m),S=e.write,z=S<e.read?e.read-S-1:e.end-S,e.read!=e.write)return e.ot=x,e.ct=A,y.We=v,y.qe+=_-y.nt,y.nt=_,e.write=S,e.wt(y,m);t=8;case 8:return m=1,e.ot=x,e.ct=A,y.We=v,y.qe+=_-y.nt,y.nt=_,e.write=S,e.wt(y,m);case 9:return m=st,e.ot=x,e.ct=A,y.We=v,y.qe+=_-y.nt,y.nt=_,e.write=S,e.wt(y,m);default:return m=rt,e.ot=x,e.ct=A,y.We=v,y.qe+=_-y.nt,y.nt=_,e.write=S,e.wt(y,m)}},e.ht=()=>{}}ht.dt=(e,t,n,r)=>(e[0]=9,t[0]=5,n[0]=ct,r[0]=ft,0);const pt=[16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15];function yt(e,t){const n=this;let r,s=0,o=0,c=0,a=0;const l=[0],u=[0],w=new dt;let h=0,d=new f(4320);const p=new ht;n.ct=0,n.ot=0,n.lt=new i(t),n.end=t,n.read=0,n.write=0,n.reset=(e,t)=>{t&&(t[0]=0),6==s&&w.ht(e),s=0,n.ct=0,n.ot=0,n.read=n.write=0},n.reset(e,null),n.wt=(e,t)=>{let r,s,i;return s=e.rt,i=n.read,r=(i>n.write?n.end:n.write)-i,r>e.tt&&(r=e.tt),0!==r&&t==it&&(t=0),e.tt-=r,e.Ge+=r,e.$e.set(n.lt.subarray(i,i+r),s),s+=r,i+=r,i==n.end&&(i=0,n.write==n.end&&(n.write=0),r=n.write-i,r>e.tt&&(r=e.tt),0!==r&&t==it&&(t=0),e.tt-=r,e.Ge+=r,e.$e.set(n.lt.subarray(i,i+r),s),s+=r,i+=r),e.rt=s,n.read=i,t},n.ut=(e,t)=>{let i,f,y,m,b,g,k,v;for(m=e.nt,b=e.We,f=n.ot,y=n.ct,g=n.write,k=g<n.read?n.read-g-1:n.end-g;;){let S,z,C,x,A,_,I,P;switch(s){case 0:for(;3>y;){if(0===b)return n.ot=f,n.ct=y,e.We=b,e.qe+=m-e.nt,e.nt=m,n.write=g,n.wt(e,t);t=0,b--,f|=(255&e.ft(m++))<<y,y+=8}switch(i=7&f,h=1&i,i>>>1){case 0:f>>>=3,y-=3,i=7&y,f>>>=i,y-=i,s=1;break;case 1:S=[],z=[],C=[[]],x=[[]],ht.dt(S,z,C,x),w.init(S[0],z[0],C[0],0,x[0],0),f>>>=3,y-=3,s=6;break;case 2:f>>>=3,y-=3,s=3;break;case 3:return f>>>=3,y-=3,s=9,e.Le="invalid block type",t=st,n.ot=f,n.ct=y,e.We=b,e.qe+=m-e.nt,e.nt=m,n.write=g,n.wt(e,t)}break;case 1:for(;32>y;){if(0===b)return n.ot=f,n.ct=y,e.We=b,e.qe+=m-e.nt,e.nt=m,n.write=g,n.wt(e,t);t=0,b--,f|=(255&e.ft(m++))<<y,y+=8}if((~f>>>16&65535)!=(65535&f))return s=9,e.Le="invalid stored block lengths",t=st,n.ot=f,n.ct=y,e.We=b,e.qe+=m-e.nt,e.nt=m,n.write=g,n.wt(e,t);o=65535&f,f=y=0,s=0!==o?2:0!==h?7:0;break;case 2:if(0===b)return n.ot=f,n.ct=y,e.We=b,e.qe+=m-e.nt,e.nt=m,n.write=g,n.wt(e,t);if(0===k&&(g==n.end&&0!==n.read&&(g=0,k=g<n.read?n.read-g-1:n.end-g),0===k&&(n.write=g,t=n.wt(e,t),g=n.write,k=g<n.read?n.read-g-1:n.end-g,g==n.end&&0!==n.read&&(g=0,k=g<n.read?n.read-g-1:n.end-g),0===k)))return n.ot=f,n.ct=y,e.We=b,e.qe+=m-e.nt,e.nt=m,n.write=g,n.wt(e,t);if(t=0,i=o,i>b&&(i=b),i>k&&(i=k),n.lt.set(e.je(m,i),g),m+=i,b-=i,g+=i,k-=i,0!=(o-=i))break;s=0!==h?7:0;break;case 3:for(;14>y;){if(0===b)return n.ot=f,n.ct=y,e.We=b,e.qe+=m-e.nt,e.nt=m,n.write=g,n.wt(e,t);t=0,b--,f|=(255&e.ft(m++))<<y,y+=8}if(c=i=16383&f,(31&i)>29||(i>>5&31)>29)return s=9,e.Le="too many length or distance symbols",t=st,n.ot=f,n.ct=y,e.We=b,e.qe+=m-e.nt,e.nt=m,n.write=g,n.wt(e,t);if(i=258+(31&i)+(i>>5&31),!r||r.length<i)r=[];else for(v=0;i>v;v++)r[v]=0;f>>>=14,y-=14,a=0,s=4;case 4:for(;4+(c>>>10)>a;){for(;3>y;){if(0===b)return n.ot=f,n.ct=y,e.We=b,e.qe+=m-e.nt,e.nt=m,n.write=g,n.wt(e,t);t=0,b--,f|=(255&e.ft(m++))<<y,y+=8}r[pt[a++]]=7&f,f>>>=3,y-=3}for(;19>a;)r[pt[a++]]=0;if(l[0]=7,i=p.st(r,l,u,d,e),0!=i)return(t=i)==st&&(r=null,s=9),n.ot=f,n.ct=y,e.We=b,e.qe+=m-e.nt,e.nt=m,n.write=g,n.wt(e,t);a=0,s=5;case 5:for(;i=c,258+(31&i)+(i>>5&31)>a;){let o,w;for(i=l[0];i>y;){if(0===b)return n.ot=f,n.ct=y,e.We=b,e.qe+=m-e.nt,e.nt=m,n.write=g,n.wt(e,t);t=0,b--,f|=(255&e.ft(m++))<<y,y+=8}if(i=d[3*(u[0]+(f&ot[i]))+1],w=d[3*(u[0]+(f&ot[i]))+2],16>w)f>>>=i,y-=i,r[a++]=w;else{for(v=18==w?7:w-14,o=18==w?11:3;i+v>y;){if(0===b)return n.ot=f,n.ct=y,e.We=b,e.qe+=m-e.nt,e.nt=m,n.write=g,n.wt(e,t);t=0,b--,f|=(255&e.ft(m++))<<y,y+=8}if(f>>>=i,y-=i,o+=f&ot[v],f>>>=v,y-=v,v=a,i=c,v+o>258+(31&i)+(i>>5&31)||16==w&&1>v)return r=null,s=9,e.Le="invalid bit length repeat",t=st,n.ot=f,n.ct=y,e.We=b,e.qe+=m-e.nt,e.nt=m,n.write=g,n.wt(e,t);w=16==w?r[v-1]:0;do{r[v++]=w}while(0!=--o);a=v}}if(u[0]=-1,A=[],_=[],I=[],P=[],A[0]=9,_[0]=6,i=c,i=p.it(257+(31&i),1+(i>>5&31),r,A,_,I,P,d,e),0!=i)return i==st&&(r=null,s=9),t=i,n.ot=f,n.ct=y,e.We=b,e.qe+=m-e.nt,e.nt=m,n.write=g,n.wt(e,t);w.init(A[0],_[0],d,I[0],d,P[0]),s=6;case 6:if(n.ot=f,n.ct=y,e.We=b,e.qe+=m-e.nt,e.nt=m,n.write=g,1!=(t=w.ut(n,e,t)))return n.wt(e,t);if(t=0,w.ht(e),m=e.nt,b=e.We,f=n.ot,y=n.ct,g=n.write,k=g<n.read?n.read-g-1:n.end-g,0===h){s=0;break}s=7;case 7:if(n.write=g,t=n.wt(e,t),g=n.write,k=g<n.read?n.read-g-1:n.end-g,n.read!=n.write)return n.ot=f,n.ct=y,e.We=b,e.qe+=m-e.nt,e.nt=m,n.write=g,n.wt(e,t);s=8;case 8:return t=1,n.ot=f,n.ct=y,e.We=b,e.qe+=m-e.nt,e.nt=m,n.write=g,n.wt(e,t);case 9:return t=st,n.ot=f,n.ct=y,e.We=b,e.qe+=m-e.nt,e.nt=m,n.write=g,n.wt(e,t);default:return t=rt,n.ot=f,n.ct=y,e.We=b,e.qe+=m-e.nt,e.nt=m,n.write=g,n.wt(e,t)}}},n.ht=e=>{n.reset(e,null),n.lt=null,d=null},n.yt=(e,t,r)=>{n.lt.set(e.subarray(t,t+r),0),n.read=n.write=r},n.bt=()=>1==s?1:0}const mt=13,bt=[0,0,255,255];function gt(){const e=this;function t(e){return e&&e.gt?(e.qe=e.Ge=0,e.Le=null,e.gt.mode=7,e.gt.kt.reset(e,null),0):rt}e.mode=0,e.method=0,e.vt=[0],e.St=0,e.marker=0,e.zt=0,e.Ct=t=>(e.kt&&e.kt.ht(t),e.kt=null,0),e.xt=(n,r)=>(n.Le=null,e.kt=null,8>r||r>15?(e.Ct(n),rt):(e.zt=r,n.gt.kt=new yt(n,1<<r),t(n),0)),e.At=(e,t)=>{let n,r;if(!e||!e.gt||!e.et)return rt;const s=e.gt;for(t=4==t?it:0,n=it;;)switch(s.mode){case 0:if(0===e.We)return n;if(n=t,e.We--,e.qe++,8!=(15&(s.method=e.ft(e.nt++)))){s.mode=mt,e.Le="unknown compression method",s.marker=5;break}if(8+(s.method>>4)>s.zt){s.mode=mt,e.Le="invalid win size",s.marker=5;break}s.mode=1;case 1:if(0===e.We)return n;if(n=t,e.We--,e.qe++,r=255&e.ft(e.nt++),((s.method<<8)+r)%31!=0){s.mode=mt,e.Le="incorrect header check",s.marker=5;break}if(!(32&r)){s.mode=7;break}s.mode=2;case 2:if(0===e.We)return n;n=t,e.We--,e.qe++,s.St=(255&e.ft(e.nt++))<<24&4278190080,s.mode=3;case 3:if(0===e.We)return n;n=t,e.We--,e.qe++,s.St+=(255&e.ft(e.nt++))<<16&16711680,s.mode=4;case 4:if(0===e.We)return n;n=t,e.We--,e.qe++,s.St+=(255&e.ft(e.nt++))<<8&65280,s.mode=5;case 5:return 0===e.We?n:(n=t,e.We--,e.qe++,s.St+=255&e.ft(e.nt++),s.mode=6,2);case 6:return s.mode=mt,e.Le="need dictionary",s.marker=0,rt;case 7:if(n=s.kt.ut(e,n),n==st){s.mode=mt,s.marker=0;break}if(0==n&&(n=t),1!=n)return n;n=t,s.kt.reset(e,s.vt),s.mode=12;case 12:return e.We=0,1;case mt:return st;default:return rt}},e._t=(e,t,n)=>{let r=0,s=n;if(!e||!e.gt||6!=e.gt.mode)return rt;const i=e.gt;return s<1<<i.zt||(s=(1<<i.zt)-1,r=n-s),i.kt.yt(t,r,s),i.mode=7,0},e.It=e=>{let n,r,s,i,o;if(!e||!e.gt)return rt;const c=e.gt;if(c.mode!=mt&&(c.mode=mt,c.marker=0),0===(n=e.We))return it;for(r=e.nt,s=c.marker;0!==n&&4>s;)e.ft(r)==bt[s]?s++:s=0!==e.ft(r)?0:4-s,r++,n--;return e.qe+=r-e.nt,e.nt=r,e.We=n,c.marker=s,4!=s?st:(i=e.qe,o=e.Ge,t(e),e.qe=i,e.Ge=o,c.mode=7,0)},e.Pt=e=>e&&e.gt&&e.gt.kt?e.gt.kt.bt():rt}function kt(){}function vt(e){const t=new kt,n=e&&e.chunkSize?r.floor(2*e.chunkSize):131072,o=new i(n);let c=!1;t.xt(),t.$e=o,this.append=(e,r)=>{const f=[];let a,l,u=0,w=0,h=0;if(0!==e.length){t.nt=0,t.et=e,t.We=e.length;do{if(t.rt=0,t.tt=n,0!==t.We||c||(t.nt=0,c=!0),a=t.At(0),c&&a===it){if(0!==t.We)throw new s("inflating: bad input")}else if(0!==a&&1!==a)throw new s("inflating: "+t.Le);if((c||1===a)&&t.We===e.length)throw new s("inflating: bad input");t.rt&&(t.rt===n?f.push(new i(o)):f.push(o.subarray(0,t.rt))),h+=t.rt,r&&t.nt>0&&t.nt!=u&&(r(t.nt),u=t.nt)}while(t.We>0||0===t.tt);return f.length>1?(l=new i(h),f.forEach((e=>{l.set(e,w),w+=e.length}))):l=f[0]?new i(f[0]):new i,l}},this.flush=()=>{t.Ct()}}kt.prototype={xt(e){const t=this;return t.gt=new gt,e||(e=15),t.gt.xt(t,e)},At(e){const t=this;return t.gt?t.gt.At(t,e):rt},Ct(){const e=this;if(!e.gt)return rt;const t=e.gt.Ct(e);return e.gt=null,t},It(){const e=this;return e.gt?e.gt.It(e):rt},_t(e,t){const n=this;return n.gt?n.gt._t(n,e,t):rt},ft(e){return this.et[e]},je(e,t){return this.et.subarray(e,e+t)}},self.initCodec=()=>{self.Deflate=nt,self.Inflate=vt};\n',r=()=>t.useDataURI?"data:text/javascript,"+encodeURIComponent(n):URL.createObjectURL(new Blob([n],{type:"text/javascript"}));e({workerScripts:{inflate:[r],deflate:[r]}});}
|
|
|
|
/*
|
|
Copyright (c) 2022 Gildas Lormeau. All rights reserved.
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
modification, are permitted provided that the following conditions are met:
|
|
|
|
1. Redistributions of source code must retain the above copyright notice,
|
|
this list of conditions and the following disclaimer.
|
|
|
|
2. Redistributions in binary form must reproduce the above copyright
|
|
notice, this list of conditions and the following disclaimer in
|
|
the documentation and/or other materials provided with the distribution.
|
|
|
|
3. The names of the authors may not be used to endorse or promote products
|
|
derived from this software without specific prior written permission.
|
|
|
|
THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
|
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
|
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
|
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
|
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
const ERR_ITERATOR_COMPLETED_TOO_SOON = "Writer iterator completed too soon";
|
|
const HTTP_HEADER_CONTENT_TYPE = "Content-Type";
|
|
const DEFAULT_CHUNK_SIZE = 64 * 1024;
|
|
|
|
const PROPERTY_NAME_WRITABLE = "writable";
|
|
|
|
class Stream {
|
|
|
|
constructor() {
|
|
this.size = 0;
|
|
}
|
|
|
|
init() {
|
|
this.initialized = true;
|
|
}
|
|
}
|
|
|
|
class Reader extends Stream {
|
|
|
|
get readable() {
|
|
const reader = this;
|
|
const { chunkSize = DEFAULT_CHUNK_SIZE } = reader;
|
|
const readable = new ReadableStream({
|
|
start() {
|
|
this.chunkOffset = 0;
|
|
},
|
|
async pull(controller) {
|
|
const { offset = 0, size, diskNumberStart } = readable;
|
|
const { chunkOffset } = this;
|
|
controller.enqueue(await readUint8Array(reader, offset + chunkOffset, Math.min(chunkSize, size - chunkOffset), diskNumberStart));
|
|
if (chunkOffset + chunkSize > size) {
|
|
controller.close();
|
|
} else {
|
|
this.chunkOffset += chunkSize;
|
|
}
|
|
}
|
|
});
|
|
return readable;
|
|
}
|
|
}
|
|
|
|
class BlobReader extends Reader {
|
|
|
|
constructor(blob) {
|
|
super();
|
|
Object.assign(this, {
|
|
blob,
|
|
size: blob.size
|
|
});
|
|
}
|
|
|
|
async readUint8Array(offset, length) {
|
|
const reader = this;
|
|
const offsetEnd = offset + length;
|
|
const blob = offset || offsetEnd < reader.size ? reader.blob.slice(offset, offsetEnd) : reader.blob;
|
|
let arrayBuffer = await blob.arrayBuffer();
|
|
if (arrayBuffer.byteLength > length) {
|
|
arrayBuffer = arrayBuffer.slice(offset, offsetEnd);
|
|
}
|
|
return new Uint8Array(arrayBuffer);
|
|
}
|
|
}
|
|
|
|
class BlobWriter extends Stream {
|
|
|
|
constructor(contentType) {
|
|
super();
|
|
const writer = this;
|
|
const transformStream = new TransformStream();
|
|
const headers = [];
|
|
if (contentType) {
|
|
headers.push([HTTP_HEADER_CONTENT_TYPE, contentType]);
|
|
}
|
|
Object.defineProperty(writer, PROPERTY_NAME_WRITABLE, {
|
|
get() {
|
|
return transformStream.writable;
|
|
}
|
|
});
|
|
writer.blob = new Response(transformStream.readable, { headers }).blob();
|
|
}
|
|
|
|
getData() {
|
|
return this.blob;
|
|
}
|
|
}
|
|
|
|
class TextWriter extends BlobWriter {
|
|
|
|
constructor(encoding) {
|
|
super(encoding);
|
|
Object.assign(this, {
|
|
encoding,
|
|
utf8: !encoding || encoding.toLowerCase() == "utf-8"
|
|
});
|
|
}
|
|
|
|
async getData() {
|
|
const {
|
|
encoding,
|
|
utf8
|
|
} = this;
|
|
const blob = await super.getData();
|
|
if (blob.text && utf8) {
|
|
return blob.text();
|
|
} else {
|
|
const reader = new FileReader();
|
|
return new Promise((resolve, reject) => {
|
|
Object.assign(reader, {
|
|
onload: ({ target }) => resolve(target.result),
|
|
onerror: () => reject(reader.error)
|
|
});
|
|
reader.readAsText(blob, encoding);
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
class SplitDataReader extends Reader {
|
|
|
|
constructor(readers) {
|
|
super();
|
|
this.readers = readers;
|
|
}
|
|
|
|
async init() {
|
|
const reader = this;
|
|
const { readers } = reader;
|
|
reader.lastDiskNumber = 0;
|
|
reader.lastDiskOffset = 0;
|
|
await Promise.all(readers.map(async (diskReader, indexDiskReader) => {
|
|
await diskReader.init();
|
|
if (indexDiskReader != readers.length - 1) {
|
|
reader.lastDiskOffset += diskReader.size;
|
|
}
|
|
reader.size += diskReader.size;
|
|
}));
|
|
super.init();
|
|
}
|
|
|
|
async readUint8Array(offset, length, diskNumber = 0) {
|
|
const reader = this;
|
|
const { readers } = this;
|
|
let result;
|
|
let currentDiskNumber = diskNumber;
|
|
if (currentDiskNumber == -1) {
|
|
currentDiskNumber = readers.length - 1;
|
|
}
|
|
let currentReaderOffset = offset;
|
|
while (currentReaderOffset >= readers[currentDiskNumber].size) {
|
|
currentReaderOffset -= readers[currentDiskNumber].size;
|
|
currentDiskNumber++;
|
|
}
|
|
const currentReader = readers[currentDiskNumber];
|
|
const currentReaderSize = currentReader.size;
|
|
if (currentReaderOffset + length <= currentReaderSize) {
|
|
result = await readUint8Array(currentReader, currentReaderOffset, length);
|
|
} else {
|
|
const chunkLength = currentReaderSize - currentReaderOffset;
|
|
result = new Uint8Array(length);
|
|
result.set(await readUint8Array(currentReader, currentReaderOffset, chunkLength));
|
|
result.set(await reader.readUint8Array(offset + chunkLength, length - chunkLength, diskNumber), chunkLength);
|
|
}
|
|
reader.lastDiskNumber = Math.max(currentDiskNumber, reader.lastDiskNumber);
|
|
return result;
|
|
}
|
|
}
|
|
|
|
class SplitDataWriter extends Stream {
|
|
|
|
constructor(writerGenerator, maxSize = 4294967295) {
|
|
super();
|
|
const writer = this;
|
|
Object.assign(writer, {
|
|
diskNumber: 0,
|
|
diskOffset: 0,
|
|
size: 0,
|
|
maxSize,
|
|
availableSize: maxSize
|
|
});
|
|
let diskSourceWriter, diskWritable, diskWriter;
|
|
const writable = new WritableStream({
|
|
async write(chunk) {
|
|
const { availableSize } = writer;
|
|
if (!diskWriter) {
|
|
const { value, done } = await writerGenerator.next();
|
|
if (done && !value) {
|
|
throw new Error(ERR_ITERATOR_COMPLETED_TOO_SOON);
|
|
} else {
|
|
diskSourceWriter = value;
|
|
diskSourceWriter.size = 0;
|
|
if (diskSourceWriter.maxSize) {
|
|
writer.maxSize = diskSourceWriter.maxSize;
|
|
}
|
|
writer.availableSize = writer.maxSize;
|
|
await initStream(diskSourceWriter);
|
|
diskWritable = value.writable;
|
|
diskWriter = diskWritable.getWriter();
|
|
}
|
|
await this.write(chunk);
|
|
} else if (chunk.length >= availableSize) {
|
|
await writeChunk(chunk.slice(0, availableSize));
|
|
await closeDisk();
|
|
writer.diskOffset += diskSourceWriter.size;
|
|
writer.diskNumber++;
|
|
diskWriter = null;
|
|
await this.write(chunk.slice(availableSize));
|
|
} else {
|
|
await writeChunk(chunk);
|
|
}
|
|
},
|
|
async close() {
|
|
await diskWriter.ready;
|
|
await closeDisk();
|
|
}
|
|
});
|
|
Object.defineProperty(writer, PROPERTY_NAME_WRITABLE, {
|
|
get() {
|
|
return writable;
|
|
}
|
|
});
|
|
|
|
async function writeChunk(chunk) {
|
|
const chunkLength = chunk.length;
|
|
if (chunkLength) {
|
|
await diskWriter.ready;
|
|
await diskWriter.write(chunk);
|
|
diskSourceWriter.size += chunkLength;
|
|
writer.size += chunkLength;
|
|
writer.availableSize -= chunkLength;
|
|
}
|
|
}
|
|
|
|
async function closeDisk() {
|
|
diskWritable.size = diskSourceWriter.size;
|
|
await diskWriter.close();
|
|
}
|
|
}
|
|
}
|
|
|
|
async function initStream(stream, initSize) {
|
|
if (stream.init && !stream.initialized) {
|
|
await stream.init(initSize);
|
|
} else {
|
|
return Promise.resolve();
|
|
}
|
|
}
|
|
|
|
function initReader(reader) {
|
|
if (Array.isArray(reader)) {
|
|
reader = new SplitDataReader(reader);
|
|
}
|
|
if (reader instanceof ReadableStream) {
|
|
reader = {
|
|
readable: reader
|
|
};
|
|
}
|
|
return reader;
|
|
}
|
|
|
|
function initWriter(writer) {
|
|
if (writer.writable === UNDEFINED_VALUE && typeof writer.next == FUNCTION_TYPE) {
|
|
writer = new SplitDataWriter(writer);
|
|
}
|
|
if (writer instanceof WritableStream) {
|
|
writer = {
|
|
writable: writer
|
|
};
|
|
}
|
|
const { writable } = writer;
|
|
if (writable.size === UNDEFINED_VALUE) {
|
|
writable.size = 0;
|
|
}
|
|
if (!(writer instanceof SplitDataWriter)) {
|
|
Object.assign(writer, {
|
|
diskNumber: 0,
|
|
diskOffset: 0,
|
|
availableSize: Infinity,
|
|
maxSize: Infinity
|
|
});
|
|
}
|
|
return writer;
|
|
}
|
|
|
|
function readUint8Array(reader, offset, size, diskNumber) {
|
|
return reader.readUint8Array(offset, size, diskNumber);
|
|
}
|
|
|
|
/*
|
|
Copyright (c) 2022 Gildas Lormeau. All rights reserved.
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
modification, are permitted provided that the following conditions are met:
|
|
|
|
1. Redistributions of source code must retain the above copyright notice,
|
|
this list of conditions and the following disclaimer.
|
|
|
|
2. Redistributions in binary form must reproduce the above copyright
|
|
notice, this list of conditions and the following disclaimer in
|
|
the documentation and/or other materials provided with the distribution.
|
|
|
|
3. The names of the authors may not be used to endorse or promote products
|
|
derived from this software without specific prior written permission.
|
|
|
|
THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
|
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
|
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
|
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
|
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
/* global TextDecoder */
|
|
|
|
const CP437 = "\0☺☻♥♦♣♠•◘○◙♂♀♪♫☼►◄↕‼¶§▬↨↑↓→←∟↔▲▼ !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~⌂ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜ¢£¥₧ƒáíóúñѪº¿⌐¬½¼¡«»░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀αßΓπΣσµτΦΘΩδ∞φε∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■ ".split("");
|
|
const VALID_CP437 = CP437.length == 256;
|
|
|
|
function decodeCP437(stringValue) {
|
|
if (VALID_CP437) {
|
|
let result = "";
|
|
for (let indexCharacter = 0; indexCharacter < stringValue.length; indexCharacter++) {
|
|
result += CP437[stringValue[indexCharacter]];
|
|
}
|
|
return result;
|
|
} else {
|
|
return new TextDecoder().decode(stringValue);
|
|
}
|
|
}
|
|
|
|
/*
|
|
Copyright (c) 2022 Gildas Lormeau. All rights reserved.
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
modification, are permitted provided that the following conditions are met:
|
|
|
|
1. Redistributions of source code must retain the above copyright notice,
|
|
this list of conditions and the following disclaimer.
|
|
|
|
2. Redistributions in binary form must reproduce the above copyright
|
|
notice, this list of conditions and the following disclaimer in
|
|
the documentation and/or other materials provided with the distribution.
|
|
|
|
3. The names of the authors may not be used to endorse or promote products
|
|
derived from this software without specific prior written permission.
|
|
|
|
THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
|
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
|
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
|
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
|
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
function decodeText(value, encoding) {
|
|
if (encoding && encoding.trim().toLowerCase() == "cp437") {
|
|
return decodeCP437(value);
|
|
} else {
|
|
return new TextDecoder(encoding).decode(value);
|
|
}
|
|
}
|
|
|
|
/*
|
|
Copyright (c) 2022 Gildas Lormeau. All rights reserved.
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
modification, are permitted provided that the following conditions are met:
|
|
|
|
1. Redistributions of source code must retain the above copyright notice,
|
|
this list of conditions and the following disclaimer.
|
|
|
|
2. Redistributions in binary form must reproduce the above copyright
|
|
notice, this list of conditions and the following disclaimer in
|
|
the documentation and/or other materials provided with the distribution.
|
|
|
|
3. The names of the authors may not be used to endorse or promote products
|
|
derived from this software without specific prior written permission.
|
|
|
|
THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
|
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
|
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
|
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
|
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
const PROPERTY_NAME_FILENAME = "filename";
|
|
const PROPERTY_NAME_RAW_FILENAME = "rawFilename";
|
|
const PROPERTY_NAME_COMMENT = "comment";
|
|
const PROPERTY_NAME_RAW_COMMENT = "rawComment";
|
|
const PROPERTY_NAME_UNCOMPPRESSED_SIZE = "uncompressedSize";
|
|
const PROPERTY_NAME_COMPPRESSED_SIZE = "compressedSize";
|
|
const PROPERTY_NAME_OFFSET = "offset";
|
|
const PROPERTY_NAME_DISK_NUMBER_START = "diskNumberStart";
|
|
const PROPERTY_NAME_LAST_MODIFICATION_DATE = "lastModDate";
|
|
const PROPERTY_NAME_RAW_LAST_MODIFICATION_DATE = "rawLastModDate";
|
|
const PROPERTY_NAME_LAST_ACCESS_DATE = "lastAccessDate";
|
|
const PROPERTY_NAME_RAW_LAST_ACCESS_DATE = "rawLastAccessDate";
|
|
const PROPERTY_NAME_CREATION_DATE = "creationDate";
|
|
const PROPERTY_NAME_RAW_CREATION_DATE = "rawCreationDate";
|
|
const PROPERTY_NAME_INTERNAL_FILE_ATTRIBUTE = "internalFileAttribute";
|
|
const PROPERTY_NAME_EXTERNAL_FILE_ATTRIBUTE = "externalFileAttribute";
|
|
const PROPERTY_NAME_MS_DOS_COMPATIBLE = "msDosCompatible";
|
|
const PROPERTY_NAME_ZIP64 = "zip64";
|
|
const PROPERTY_NAME_ENCRYPTED = "encrypted";
|
|
const PROPERTY_NAME_VERSION = "version";
|
|
const PROPERTY_NAME_VERSION_MADE_BY = "versionMadeBy";
|
|
const PROPERTY_NAME_ZIPCRYPTO = "zipCrypto";
|
|
|
|
const PROPERTY_NAMES = [
|
|
PROPERTY_NAME_FILENAME, PROPERTY_NAME_RAW_FILENAME, PROPERTY_NAME_COMPPRESSED_SIZE, PROPERTY_NAME_UNCOMPPRESSED_SIZE,
|
|
PROPERTY_NAME_LAST_MODIFICATION_DATE, PROPERTY_NAME_RAW_LAST_MODIFICATION_DATE, PROPERTY_NAME_COMMENT, PROPERTY_NAME_RAW_COMMENT,
|
|
PROPERTY_NAME_LAST_ACCESS_DATE, PROPERTY_NAME_CREATION_DATE, PROPERTY_NAME_OFFSET, PROPERTY_NAME_DISK_NUMBER_START,
|
|
PROPERTY_NAME_DISK_NUMBER_START, PROPERTY_NAME_INTERNAL_FILE_ATTRIBUTE, PROPERTY_NAME_EXTERNAL_FILE_ATTRIBUTE,
|
|
PROPERTY_NAME_MS_DOS_COMPATIBLE, PROPERTY_NAME_ZIP64, PROPERTY_NAME_ENCRYPTED, PROPERTY_NAME_VERSION, PROPERTY_NAME_VERSION_MADE_BY,
|
|
PROPERTY_NAME_ZIPCRYPTO, "directory", "bitFlag", "signature", "filenameUTF8", "commentUTF8", "compressionMethod", "extraField", "rawExtraField",
|
|
"extraFieldZip64", "extraFieldUnicodePath", "extraFieldUnicodeComment", "extraFieldAES", "extraFieldNTFS", "extraFieldExtendedTimestamp"];
|
|
|
|
class Entry {
|
|
|
|
constructor(data) {
|
|
PROPERTY_NAMES.forEach(name => this[name] = data[name]);
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
Copyright (c) 2022 Gildas Lormeau. All rights reserved.
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
modification, are permitted provided that the following conditions are met:
|
|
|
|
1. Redistributions of source code must retain the above copyright notice,
|
|
this list of conditions and the following disclaimer.
|
|
|
|
2. Redistributions in binary form must reproduce the above copyright
|
|
notice, this list of conditions and the following disclaimer in
|
|
the documentation and/or other materials provided with the distribution.
|
|
|
|
3. The names of the authors may not be used to endorse or promote products
|
|
derived from this software without specific prior written permission.
|
|
|
|
THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
|
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
|
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
|
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
|
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
const ERR_BAD_FORMAT = "File format is not recognized";
|
|
const ERR_EOCDR_NOT_FOUND = "End of central directory not found";
|
|
const ERR_EOCDR_LOCATOR_ZIP64_NOT_FOUND = "End of Zip64 central directory locator not found";
|
|
const ERR_CENTRAL_DIRECTORY_NOT_FOUND = "Central directory header not found";
|
|
const ERR_LOCAL_FILE_HEADER_NOT_FOUND = "Local file header not found";
|
|
const ERR_EXTRAFIELD_ZIP64_NOT_FOUND = "Zip64 extra field not found";
|
|
const ERR_ENCRYPTED = "File contains encrypted entry";
|
|
const ERR_UNSUPPORTED_ENCRYPTION = "Encryption method not supported";
|
|
const ERR_UNSUPPORTED_COMPRESSION = "Compression method not supported";
|
|
const ERR_SPLIT_ZIP_FILE = "Split zip file";
|
|
const CHARSET_UTF8 = "utf-8";
|
|
const CHARSET_CP437 = "cp437";
|
|
const ZIP64_PROPERTIES = [
|
|
[PROPERTY_NAME_UNCOMPPRESSED_SIZE, MAX_32_BITS],
|
|
[PROPERTY_NAME_COMPPRESSED_SIZE, MAX_32_BITS],
|
|
[PROPERTY_NAME_OFFSET, MAX_32_BITS],
|
|
[PROPERTY_NAME_DISK_NUMBER_START, MAX_16_BITS]
|
|
];
|
|
const ZIP64_EXTRACTION = {
|
|
[MAX_16_BITS]: {
|
|
getValue: getUint32,
|
|
bytes: 4
|
|
},
|
|
[MAX_32_BITS]: {
|
|
getValue: getBigUint64,
|
|
bytes: 8
|
|
}
|
|
};
|
|
|
|
class ZipReader {
|
|
|
|
constructor(reader, options = {}) {
|
|
Object.assign(this, {
|
|
reader: initReader(reader),
|
|
options,
|
|
config: getConfiguration()
|
|
});
|
|
}
|
|
|
|
async* getEntriesGenerator(options = {}) {
|
|
const zipReader = this;
|
|
let { reader } = zipReader;
|
|
const { config } = zipReader;
|
|
await initStream(reader);
|
|
if (reader.size === UNDEFINED_VALUE || !reader.readUint8Array) {
|
|
reader = new BlobReader(await new Response(reader.readable).blob());
|
|
await initStream(reader);
|
|
}
|
|
if (reader.size < END_OF_CENTRAL_DIR_LENGTH) {
|
|
throw new Error(ERR_BAD_FORMAT);
|
|
}
|
|
reader.chunkSize = getChunkSize(config);
|
|
const endOfDirectoryInfo = await seekSignature(reader, END_OF_CENTRAL_DIR_SIGNATURE, reader.size, END_OF_CENTRAL_DIR_LENGTH, MAX_16_BITS * 16);
|
|
if (!endOfDirectoryInfo) {
|
|
const signatureArray = await readUint8Array(reader, 0, 4);
|
|
const signatureView = getDataView(signatureArray);
|
|
if (getUint32(signatureView) == SPLIT_ZIP_FILE_SIGNATURE) {
|
|
throw new Error(ERR_SPLIT_ZIP_FILE);
|
|
} else {
|
|
throw new Error(ERR_EOCDR_NOT_FOUND);
|
|
}
|
|
}
|
|
const endOfDirectoryView = getDataView(endOfDirectoryInfo);
|
|
let directoryDataLength = getUint32(endOfDirectoryView, 12);
|
|
let directoryDataOffset = getUint32(endOfDirectoryView, 16);
|
|
const commentOffset = endOfDirectoryInfo.offset;
|
|
const commentLength = getUint16(endOfDirectoryView, 20);
|
|
const appendedDataOffset = commentOffset + END_OF_CENTRAL_DIR_LENGTH + commentLength;
|
|
let lastDiskNumber = getUint16(endOfDirectoryView, 4);
|
|
const expectedLastDiskNumber = reader.lastDiskNumber || 0;
|
|
let diskNumber = getUint16(endOfDirectoryView, 6);
|
|
let filesLength = getUint16(endOfDirectoryView, 8);
|
|
let prependedDataLength = 0;
|
|
let startOffset = 0;
|
|
if (directoryDataOffset == MAX_32_BITS || directoryDataLength == MAX_32_BITS || filesLength == MAX_16_BITS || diskNumber == MAX_16_BITS) {
|
|
const endOfDirectoryLocatorArray = await readUint8Array(reader, endOfDirectoryInfo.offset - ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH, ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH);
|
|
const endOfDirectoryLocatorView = getDataView(endOfDirectoryLocatorArray);
|
|
if (getUint32(endOfDirectoryLocatorView, 0) == ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIGNATURE) {
|
|
directoryDataOffset = getBigUint64(endOfDirectoryLocatorView, 8);
|
|
let endOfDirectoryArray = await readUint8Array(reader, directoryDataOffset, ZIP64_END_OF_CENTRAL_DIR_LENGTH, -1);
|
|
let endOfDirectoryView = getDataView(endOfDirectoryArray);
|
|
const expectedDirectoryDataOffset = endOfDirectoryInfo.offset - ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH - ZIP64_END_OF_CENTRAL_DIR_LENGTH;
|
|
if (getUint32(endOfDirectoryView, 0) != ZIP64_END_OF_CENTRAL_DIR_SIGNATURE && directoryDataOffset != expectedDirectoryDataOffset) {
|
|
const originalDirectoryDataOffset = directoryDataOffset;
|
|
directoryDataOffset = expectedDirectoryDataOffset;
|
|
prependedDataLength = directoryDataOffset - originalDirectoryDataOffset;
|
|
endOfDirectoryArray = await readUint8Array(reader, directoryDataOffset, ZIP64_END_OF_CENTRAL_DIR_LENGTH, -1);
|
|
endOfDirectoryView = getDataView(endOfDirectoryArray);
|
|
}
|
|
if (getUint32(endOfDirectoryView, 0) != ZIP64_END_OF_CENTRAL_DIR_SIGNATURE) {
|
|
throw new Error(ERR_EOCDR_LOCATOR_ZIP64_NOT_FOUND);
|
|
}
|
|
if (lastDiskNumber == MAX_16_BITS) {
|
|
lastDiskNumber = getUint32(endOfDirectoryView, 16);
|
|
}
|
|
if (diskNumber == MAX_16_BITS) {
|
|
diskNumber = getUint32(endOfDirectoryView, 20);
|
|
}
|
|
if (filesLength == MAX_16_BITS) {
|
|
filesLength = getBigUint64(endOfDirectoryView, 32);
|
|
}
|
|
if (directoryDataLength == MAX_32_BITS) {
|
|
directoryDataLength = getBigUint64(endOfDirectoryView, 40);
|
|
}
|
|
directoryDataOffset -= directoryDataLength;
|
|
}
|
|
}
|
|
if (directoryDataOffset >= reader.size) {
|
|
prependedDataLength = reader.size - directoryDataOffset - directoryDataLength - END_OF_CENTRAL_DIR_LENGTH;
|
|
directoryDataOffset = reader.size - directoryDataLength - END_OF_CENTRAL_DIR_LENGTH;
|
|
}
|
|
if (expectedLastDiskNumber != lastDiskNumber) {
|
|
throw new Error(ERR_SPLIT_ZIP_FILE);
|
|
}
|
|
if (directoryDataOffset < 0) {
|
|
throw new Error(ERR_BAD_FORMAT);
|
|
}
|
|
let offset = 0;
|
|
let directoryArray = await readUint8Array(reader, directoryDataOffset, directoryDataLength, diskNumber);
|
|
let directoryView = getDataView(directoryArray);
|
|
if (directoryDataLength) {
|
|
const expectedDirectoryDataOffset = endOfDirectoryInfo.offset - directoryDataLength;
|
|
if (getUint32(directoryView, offset) != CENTRAL_FILE_HEADER_SIGNATURE && directoryDataOffset != expectedDirectoryDataOffset) {
|
|
const originalDirectoryDataOffset = directoryDataOffset;
|
|
directoryDataOffset = expectedDirectoryDataOffset;
|
|
prependedDataLength += directoryDataOffset - originalDirectoryDataOffset;
|
|
directoryArray = await readUint8Array(reader, directoryDataOffset, directoryDataLength, diskNumber);
|
|
directoryView = getDataView(directoryArray);
|
|
}
|
|
}
|
|
const expectedDirectoryDataLength = endOfDirectoryInfo.offset - directoryDataOffset - (reader.lastDiskOffset || 0);
|
|
if (directoryDataLength != expectedDirectoryDataLength && expectedDirectoryDataLength >= 0) {
|
|
directoryDataLength = expectedDirectoryDataLength;
|
|
directoryArray = await readUint8Array(reader, directoryDataOffset, directoryDataLength, diskNumber);
|
|
directoryView = getDataView(directoryArray);
|
|
}
|
|
if (directoryDataOffset < 0 || directoryDataOffset >= reader.size) {
|
|
throw new Error(ERR_BAD_FORMAT);
|
|
}
|
|
const filenameEncoding = getOptionValue(zipReader, options, "filenameEncoding");
|
|
const commentEncoding = getOptionValue(zipReader, options, "commentEncoding");
|
|
for (let indexFile = 0; indexFile < filesLength; indexFile++) {
|
|
const fileEntry = new ZipEntry(reader, config, zipReader.options);
|
|
if (getUint32(directoryView, offset) != CENTRAL_FILE_HEADER_SIGNATURE) {
|
|
throw new Error(ERR_CENTRAL_DIRECTORY_NOT_FOUND);
|
|
}
|
|
readCommonHeader(fileEntry, directoryView, offset + 6);
|
|
const languageEncodingFlag = Boolean(fileEntry.bitFlag.languageEncodingFlag);
|
|
const filenameOffset = offset + 46;
|
|
const extraFieldOffset = filenameOffset + fileEntry.filenameLength;
|
|
const commentOffset = extraFieldOffset + fileEntry.extraFieldLength;
|
|
const versionMadeBy = getUint16(directoryView, offset + 4);
|
|
const msDosCompatible = (versionMadeBy & 0) == 0;
|
|
const rawFilename = directoryArray.subarray(filenameOffset, extraFieldOffset);
|
|
const commentLength = getUint16(directoryView, offset + 32);
|
|
const endOffset = commentOffset + commentLength;
|
|
const rawComment = directoryArray.subarray(commentOffset, endOffset);
|
|
const filenameUTF8 = languageEncodingFlag;
|
|
const commentUTF8 = languageEncodingFlag;
|
|
const directory = msDosCompatible && ((getUint8(directoryView, offset + 38) & FILE_ATTR_MSDOS_DIR_MASK) == FILE_ATTR_MSDOS_DIR_MASK);
|
|
const offsetFileEntry = getUint32(directoryView, offset + 42) + prependedDataLength;
|
|
Object.assign(fileEntry, {
|
|
versionMadeBy,
|
|
msDosCompatible,
|
|
compressedSize: 0,
|
|
uncompressedSize: 0,
|
|
commentLength,
|
|
directory,
|
|
offset: offsetFileEntry,
|
|
diskNumberStart: getUint16(directoryView, offset + 34),
|
|
internalFileAttribute: getUint16(directoryView, offset + 36),
|
|
externalFileAttribute: getUint32(directoryView, offset + 38),
|
|
rawFilename,
|
|
filenameUTF8,
|
|
commentUTF8,
|
|
rawExtraField: directoryArray.subarray(extraFieldOffset, commentOffset)
|
|
});
|
|
const decode = getOptionValue(zipReader, options, "decodeText") || decodeText;
|
|
const rawFilenameEncoding = filenameUTF8 ? CHARSET_UTF8 : filenameEncoding || CHARSET_CP437;
|
|
const rawCommentEncoding = commentUTF8 ? CHARSET_UTF8 : commentEncoding || CHARSET_CP437;
|
|
let filename = decode(rawFilename, rawFilenameEncoding);
|
|
if (filename === UNDEFINED_VALUE) {
|
|
filename = decodeText(rawFilename, rawFilenameEncoding);
|
|
}
|
|
let comment = decode(rawComment, rawCommentEncoding);
|
|
if (comment === UNDEFINED_VALUE) {
|
|
comment = decodeText(rawComment, rawCommentEncoding);
|
|
}
|
|
Object.assign(fileEntry, {
|
|
rawComment,
|
|
filename,
|
|
comment,
|
|
directory: directory || filename.endsWith(DIRECTORY_SIGNATURE)
|
|
});
|
|
startOffset = Math.max(offsetFileEntry, startOffset);
|
|
readCommonFooter(fileEntry, fileEntry, directoryView, offset + 6);
|
|
fileEntry.zipCrypto = fileEntry.encrypted && !fileEntry.extraFieldAES;
|
|
const entry = new Entry(fileEntry);
|
|
entry.getData = (writer, options) => fileEntry.getData(writer, entry, options);
|
|
offset = endOffset;
|
|
const { onprogress } = options;
|
|
if (onprogress) {
|
|
try {
|
|
await onprogress(indexFile + 1, filesLength, new Entry(fileEntry));
|
|
} catch (_error) {
|
|
// ignored
|
|
}
|
|
}
|
|
yield entry;
|
|
}
|
|
const extractPrependedData = getOptionValue(zipReader, options, "extractPrependedData");
|
|
const extractAppendedData = getOptionValue(zipReader, options, "extractAppendedData");
|
|
if (extractPrependedData) {
|
|
zipReader.prependedData = startOffset > 0 ? await readUint8Array(reader, 0, startOffset) : new Uint8Array();
|
|
}
|
|
zipReader.comment = commentLength ? await readUint8Array(reader, commentOffset + END_OF_CENTRAL_DIR_LENGTH, commentLength) : new Uint8Array();
|
|
if (extractAppendedData) {
|
|
zipReader.appendedData = appendedDataOffset < reader.size ? await readUint8Array(reader, appendedDataOffset, reader.size - appendedDataOffset) : new Uint8Array();
|
|
}
|
|
return true;
|
|
}
|
|
|
|
async getEntries(options = {}) {
|
|
const entries = [];
|
|
for await (const entry of this.getEntriesGenerator(options)) {
|
|
entries.push(entry);
|
|
}
|
|
return entries;
|
|
}
|
|
|
|
async close() {
|
|
}
|
|
}
|
|
|
|
class ZipEntry {
|
|
|
|
constructor(reader, config, options) {
|
|
Object.assign(this, {
|
|
reader,
|
|
config,
|
|
options
|
|
});
|
|
}
|
|
|
|
async getData(writer, fileEntry, options = {}) {
|
|
const zipEntry = this;
|
|
const {
|
|
reader,
|
|
offset,
|
|
diskNumberStart,
|
|
extraFieldAES,
|
|
compressionMethod,
|
|
config,
|
|
bitFlag,
|
|
signature,
|
|
rawLastModDate,
|
|
uncompressedSize,
|
|
compressedSize
|
|
} = zipEntry;
|
|
const localDirectory = fileEntry.localDirectory = {};
|
|
const dataArray = await readUint8Array(reader, offset, 30, diskNumberStart);
|
|
const dataView = getDataView(dataArray);
|
|
let password = getOptionValue(zipEntry, options, "password");
|
|
let rawPassword = getOptionValue(zipEntry, options, "rawPassword");
|
|
const passThrough = getOptionValue(zipEntry, options, "passThrough");
|
|
password = password && password.length && password;
|
|
rawPassword = rawPassword && rawPassword.length && rawPassword;
|
|
if (extraFieldAES) {
|
|
if (extraFieldAES.originalCompressionMethod != COMPRESSION_METHOD_AES) {
|
|
throw new Error(ERR_UNSUPPORTED_COMPRESSION);
|
|
}
|
|
}
|
|
if ((compressionMethod != COMPRESSION_METHOD_STORE && compressionMethod != COMPRESSION_METHOD_DEFLATE) && !passThrough) {
|
|
throw new Error(ERR_UNSUPPORTED_COMPRESSION);
|
|
}
|
|
if (getUint32(dataView, 0) != LOCAL_FILE_HEADER_SIGNATURE) {
|
|
throw new Error(ERR_LOCAL_FILE_HEADER_NOT_FOUND);
|
|
}
|
|
readCommonHeader(localDirectory, dataView, 4);
|
|
localDirectory.rawExtraField = localDirectory.extraFieldLength ?
|
|
await readUint8Array(reader, offset + 30 + localDirectory.filenameLength, localDirectory.extraFieldLength, diskNumberStart) :
|
|
new Uint8Array();
|
|
readCommonFooter(zipEntry, localDirectory, dataView, 4, true);
|
|
Object.assign(fileEntry, {
|
|
lastAccessDate: localDirectory.lastAccessDate,
|
|
creationDate: localDirectory.creationDate
|
|
});
|
|
const encrypted = zipEntry.encrypted && localDirectory.encrypted && !passThrough;
|
|
const zipCrypto = encrypted && !extraFieldAES;
|
|
if (!passThrough) {
|
|
fileEntry.zipCrypto = zipCrypto;
|
|
}
|
|
if (encrypted) {
|
|
if (!zipCrypto && extraFieldAES.strength === UNDEFINED_VALUE) {
|
|
throw new Error(ERR_UNSUPPORTED_ENCRYPTION);
|
|
} else if (!password && !rawPassword) {
|
|
throw new Error(ERR_ENCRYPTED);
|
|
}
|
|
}
|
|
const dataOffset = offset + 30 + localDirectory.filenameLength + localDirectory.extraFieldLength;
|
|
const size = compressedSize;
|
|
const readable = reader.readable;
|
|
Object.assign(readable, {
|
|
diskNumberStart,
|
|
offset: dataOffset,
|
|
size
|
|
});
|
|
const signal = getOptionValue(zipEntry, options, "signal");
|
|
const checkPasswordOnly = getOptionValue(zipEntry, options, "checkPasswordOnly");
|
|
if (checkPasswordOnly) {
|
|
writer = new WritableStream();
|
|
}
|
|
writer = initWriter(writer);
|
|
await initStream(writer, passThrough ? compressedSize : uncompressedSize);
|
|
const { writable } = writer;
|
|
const { onstart, onprogress, onend } = options;
|
|
const workerOptions = {
|
|
options: {
|
|
codecType: CODEC_INFLATE,
|
|
password,
|
|
rawPassword,
|
|
zipCrypto,
|
|
encryptionStrength: extraFieldAES && extraFieldAES.strength,
|
|
signed: getOptionValue(zipEntry, options, "checkSignature") && !passThrough,
|
|
passwordVerification: zipCrypto && (bitFlag.dataDescriptor ? ((rawLastModDate >>> 8) & 0xFF) : ((signature >>> 24) & 0xFF)),
|
|
signature,
|
|
compressed: compressionMethod != 0 && !passThrough,
|
|
encrypted: zipEntry.encrypted && !passThrough,
|
|
useWebWorkers: getOptionValue(zipEntry, options, "useWebWorkers"),
|
|
useCompressionStream: getOptionValue(zipEntry, options, "useCompressionStream"),
|
|
transferStreams: getOptionValue(zipEntry, options, "transferStreams"),
|
|
checkPasswordOnly
|
|
},
|
|
config,
|
|
streamOptions: { signal, size, onstart, onprogress, onend }
|
|
};
|
|
let outputSize = 0;
|
|
try {
|
|
({ outputSize } = (await runWorker({ readable, writable }, workerOptions)));
|
|
} catch (error) {
|
|
if (!checkPasswordOnly || error.message != ERR_ABORT_CHECK_PASSWORD) {
|
|
throw error;
|
|
}
|
|
} finally {
|
|
const preventClose = getOptionValue(zipEntry, options, "preventClose");
|
|
writable.size += outputSize;
|
|
if (!preventClose && !writable.locked) {
|
|
await writable.getWriter().close();
|
|
}
|
|
}
|
|
return checkPasswordOnly ? UNDEFINED_VALUE : writer.getData ? writer.getData() : writable;
|
|
}
|
|
}
|
|
|
|
function readCommonHeader(directory, dataView, offset) {
|
|
const rawBitFlag = directory.rawBitFlag = getUint16(dataView, offset + 2);
|
|
const encrypted = (rawBitFlag & BITFLAG_ENCRYPTED) == BITFLAG_ENCRYPTED;
|
|
const rawLastModDate = getUint32(dataView, offset + 6);
|
|
Object.assign(directory, {
|
|
encrypted,
|
|
version: getUint16(dataView, offset),
|
|
bitFlag: {
|
|
level: (rawBitFlag & BITFLAG_LEVEL) >> 1,
|
|
dataDescriptor: (rawBitFlag & BITFLAG_DATA_DESCRIPTOR) == BITFLAG_DATA_DESCRIPTOR,
|
|
languageEncodingFlag: (rawBitFlag & BITFLAG_LANG_ENCODING_FLAG) == BITFLAG_LANG_ENCODING_FLAG
|
|
},
|
|
rawLastModDate,
|
|
lastModDate: getDate(rawLastModDate),
|
|
filenameLength: getUint16(dataView, offset + 22),
|
|
extraFieldLength: getUint16(dataView, offset + 24)
|
|
});
|
|
}
|
|
|
|
function readCommonFooter(fileEntry, directory, dataView, offset, localDirectory) {
|
|
const { rawExtraField } = directory;
|
|
const extraField = directory.extraField = new Map();
|
|
const rawExtraFieldView = getDataView(new Uint8Array(rawExtraField));
|
|
let offsetExtraField = 0;
|
|
try {
|
|
while (offsetExtraField < rawExtraField.length) {
|
|
const type = getUint16(rawExtraFieldView, offsetExtraField);
|
|
const size = getUint16(rawExtraFieldView, offsetExtraField + 2);
|
|
extraField.set(type, {
|
|
type,
|
|
data: rawExtraField.slice(offsetExtraField + 4, offsetExtraField + 4 + size)
|
|
});
|
|
offsetExtraField += 4 + size;
|
|
}
|
|
} catch (_error) {
|
|
// ignored
|
|
}
|
|
const compressionMethod = getUint16(dataView, offset + 4);
|
|
Object.assign(directory, {
|
|
signature: getUint32(dataView, offset + 10),
|
|
uncompressedSize: getUint32(dataView, offset + 18),
|
|
compressedSize: getUint32(dataView, offset + 14)
|
|
});
|
|
const extraFieldZip64 = extraField.get(EXTRAFIELD_TYPE_ZIP64);
|
|
if (extraFieldZip64) {
|
|
readExtraFieldZip64(extraFieldZip64, directory);
|
|
directory.extraFieldZip64 = extraFieldZip64;
|
|
}
|
|
const extraFieldUnicodePath = extraField.get(EXTRAFIELD_TYPE_UNICODE_PATH);
|
|
if (extraFieldUnicodePath) {
|
|
readExtraFieldUnicode(extraFieldUnicodePath, PROPERTY_NAME_FILENAME, PROPERTY_NAME_RAW_FILENAME, directory, fileEntry);
|
|
directory.extraFieldUnicodePath = extraFieldUnicodePath;
|
|
}
|
|
const extraFieldUnicodeComment = extraField.get(EXTRAFIELD_TYPE_UNICODE_COMMENT);
|
|
if (extraFieldUnicodeComment) {
|
|
readExtraFieldUnicode(extraFieldUnicodeComment, PROPERTY_NAME_COMMENT, PROPERTY_NAME_RAW_COMMENT, directory, fileEntry);
|
|
directory.extraFieldUnicodeComment = extraFieldUnicodeComment;
|
|
}
|
|
const extraFieldAES = extraField.get(EXTRAFIELD_TYPE_AES);
|
|
if (extraFieldAES) {
|
|
readExtraFieldAES(extraFieldAES, directory, compressionMethod);
|
|
directory.extraFieldAES = extraFieldAES;
|
|
} else {
|
|
directory.compressionMethod = compressionMethod;
|
|
}
|
|
const extraFieldNTFS = extraField.get(EXTRAFIELD_TYPE_NTFS);
|
|
if (extraFieldNTFS) {
|
|
readExtraFieldNTFS(extraFieldNTFS, directory);
|
|
directory.extraFieldNTFS = extraFieldNTFS;
|
|
}
|
|
const extraFieldExtendedTimestamp = extraField.get(EXTRAFIELD_TYPE_EXTENDED_TIMESTAMP);
|
|
if (extraFieldExtendedTimestamp) {
|
|
readExtraFieldExtendedTimestamp(extraFieldExtendedTimestamp, directory, localDirectory);
|
|
directory.extraFieldExtendedTimestamp = extraFieldExtendedTimestamp;
|
|
}
|
|
const extraFieldUSDZ = extraField.get(EXTRAFIELD_TYPE_USDZ);
|
|
if (extraFieldUSDZ) {
|
|
directory.extraFieldUSDZ = extraFieldUSDZ;
|
|
}
|
|
}
|
|
|
|
function readExtraFieldZip64(extraFieldZip64, directory) {
|
|
directory.zip64 = true;
|
|
const extraFieldView = getDataView(extraFieldZip64.data);
|
|
const missingProperties = ZIP64_PROPERTIES.filter(([propertyName, max]) => directory[propertyName] == max);
|
|
for (let indexMissingProperty = 0, offset = 0; indexMissingProperty < missingProperties.length; indexMissingProperty++) {
|
|
const [propertyName, max] = missingProperties[indexMissingProperty];
|
|
if (directory[propertyName] == max) {
|
|
const extraction = ZIP64_EXTRACTION[max];
|
|
directory[propertyName] = extraFieldZip64[propertyName] = extraction.getValue(extraFieldView, offset);
|
|
offset += extraction.bytes;
|
|
} else if (extraFieldZip64[propertyName]) {
|
|
throw new Error(ERR_EXTRAFIELD_ZIP64_NOT_FOUND);
|
|
}
|
|
}
|
|
}
|
|
|
|
function readExtraFieldUnicode(extraFieldUnicode, propertyName, rawPropertyName, directory, fileEntry) {
|
|
const extraFieldView = getDataView(extraFieldUnicode.data);
|
|
const crc32 = new Crc32();
|
|
crc32.append(fileEntry[rawPropertyName]);
|
|
const dataViewSignature = getDataView(new Uint8Array(4));
|
|
dataViewSignature.setUint32(0, crc32.get(), true);
|
|
const signature = getUint32(extraFieldView, 1);
|
|
Object.assign(extraFieldUnicode, {
|
|
version: getUint8(extraFieldView, 0),
|
|
[propertyName]: decodeText(extraFieldUnicode.data.subarray(5)),
|
|
valid: !fileEntry.bitFlag.languageEncodingFlag && signature == getUint32(dataViewSignature, 0)
|
|
});
|
|
if (extraFieldUnicode.valid) {
|
|
directory[propertyName] = extraFieldUnicode[propertyName];
|
|
directory[propertyName + "UTF8"] = true;
|
|
}
|
|
}
|
|
|
|
function readExtraFieldAES(extraFieldAES, directory, compressionMethod) {
|
|
const extraFieldView = getDataView(extraFieldAES.data);
|
|
const strength = getUint8(extraFieldView, 4);
|
|
Object.assign(extraFieldAES, {
|
|
vendorVersion: getUint8(extraFieldView, 0),
|
|
vendorId: getUint8(extraFieldView, 2),
|
|
strength,
|
|
originalCompressionMethod: compressionMethod,
|
|
compressionMethod: getUint16(extraFieldView, 5)
|
|
});
|
|
directory.compressionMethod = extraFieldAES.compressionMethod;
|
|
}
|
|
|
|
function readExtraFieldNTFS(extraFieldNTFS, directory) {
|
|
const extraFieldView = getDataView(extraFieldNTFS.data);
|
|
let offsetExtraField = 4;
|
|
let tag1Data;
|
|
try {
|
|
while (offsetExtraField < extraFieldNTFS.data.length && !tag1Data) {
|
|
const tagValue = getUint16(extraFieldView, offsetExtraField);
|
|
const attributeSize = getUint16(extraFieldView, offsetExtraField + 2);
|
|
if (tagValue == EXTRAFIELD_TYPE_NTFS_TAG1) {
|
|
tag1Data = extraFieldNTFS.data.slice(offsetExtraField + 4, offsetExtraField + 4 + attributeSize);
|
|
}
|
|
offsetExtraField += 4 + attributeSize;
|
|
}
|
|
} catch (_error) {
|
|
// ignored
|
|
}
|
|
try {
|
|
if (tag1Data && tag1Data.length == 24) {
|
|
const tag1View = getDataView(tag1Data);
|
|
const rawLastModDate = tag1View.getBigUint64(0, true);
|
|
const rawLastAccessDate = tag1View.getBigUint64(8, true);
|
|
const rawCreationDate = tag1View.getBigUint64(16, true);
|
|
Object.assign(extraFieldNTFS, {
|
|
rawLastModDate,
|
|
rawLastAccessDate,
|
|
rawCreationDate
|
|
});
|
|
const lastModDate = getDateNTFS(rawLastModDate);
|
|
const lastAccessDate = getDateNTFS(rawLastAccessDate);
|
|
const creationDate = getDateNTFS(rawCreationDate);
|
|
const extraFieldData = { lastModDate, lastAccessDate, creationDate };
|
|
Object.assign(extraFieldNTFS, extraFieldData);
|
|
Object.assign(directory, extraFieldData);
|
|
}
|
|
} catch (_error) {
|
|
// ignored
|
|
}
|
|
}
|
|
|
|
function readExtraFieldExtendedTimestamp(extraFieldExtendedTimestamp, directory, localDirectory) {
|
|
const extraFieldView = getDataView(extraFieldExtendedTimestamp.data);
|
|
const flags = getUint8(extraFieldView, 0);
|
|
const timeProperties = [];
|
|
const timeRawProperties = [];
|
|
if (localDirectory) {
|
|
if ((flags & 0x1) == 0x1) {
|
|
timeProperties.push(PROPERTY_NAME_LAST_MODIFICATION_DATE);
|
|
timeRawProperties.push(PROPERTY_NAME_RAW_LAST_MODIFICATION_DATE);
|
|
}
|
|
if ((flags & 0x2) == 0x2) {
|
|
timeProperties.push(PROPERTY_NAME_LAST_ACCESS_DATE);
|
|
timeRawProperties.push(PROPERTY_NAME_RAW_LAST_ACCESS_DATE);
|
|
}
|
|
if ((flags & 0x4) == 0x4) {
|
|
timeProperties.push(PROPERTY_NAME_CREATION_DATE);
|
|
timeRawProperties.push(PROPERTY_NAME_RAW_CREATION_DATE);
|
|
}
|
|
} else if (extraFieldExtendedTimestamp.data.length >= 5) {
|
|
timeProperties.push(PROPERTY_NAME_LAST_MODIFICATION_DATE);
|
|
timeRawProperties.push(PROPERTY_NAME_RAW_LAST_MODIFICATION_DATE);
|
|
}
|
|
let offset = 1;
|
|
timeProperties.forEach((propertyName, indexProperty) => {
|
|
if (extraFieldExtendedTimestamp.data.length >= offset + 4) {
|
|
const time = getUint32(extraFieldView, offset);
|
|
directory[propertyName] = extraFieldExtendedTimestamp[propertyName] = new Date(time * 1000);
|
|
const rawPropertyName = timeRawProperties[indexProperty];
|
|
extraFieldExtendedTimestamp[rawPropertyName] = time;
|
|
}
|
|
offset += 4;
|
|
});
|
|
}
|
|
|
|
async function seekSignature(reader, signature, startOffset, minimumBytes, maximumLength) {
|
|
const signatureArray = new Uint8Array(4);
|
|
const signatureView = getDataView(signatureArray);
|
|
setUint32(signatureView, 0, signature);
|
|
const maximumBytes = minimumBytes + maximumLength;
|
|
return (await seek(minimumBytes)) || await seek(Math.min(maximumBytes, startOffset));
|
|
|
|
async function seek(length) {
|
|
const offset = startOffset - length;
|
|
const bytes = await readUint8Array(reader, offset, length);
|
|
for (let indexByte = bytes.length - minimumBytes; indexByte >= 0; indexByte--) {
|
|
if (bytes[indexByte] == signatureArray[0] && bytes[indexByte + 1] == signatureArray[1] &&
|
|
bytes[indexByte + 2] == signatureArray[2] && bytes[indexByte + 3] == signatureArray[3]) {
|
|
return {
|
|
offset: offset + indexByte,
|
|
buffer: bytes.slice(indexByte, indexByte + minimumBytes).buffer
|
|
};
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function getOptionValue(zipReader, options, name) {
|
|
return options[name] === UNDEFINED_VALUE ? zipReader.options[name] : options[name];
|
|
}
|
|
|
|
function getDate(timeRaw) {
|
|
const date = (timeRaw & 0xffff0000) >> 16, time = timeRaw & 0x0000ffff;
|
|
try {
|
|
return new Date(1980 + ((date & 0xFE00) >> 9), ((date & 0x01E0) >> 5) - 1, date & 0x001F, (time & 0xF800) >> 11, (time & 0x07E0) >> 5, (time & 0x001F) * 2, 0);
|
|
} catch (_error) {
|
|
// ignored
|
|
}
|
|
}
|
|
|
|
function getDateNTFS(timeRaw) {
|
|
return new Date((Number((timeRaw / BigInt(10000)) - BigInt(11644473600000))));
|
|
}
|
|
|
|
function getUint8(view, offset) {
|
|
return view.getUint8(offset);
|
|
}
|
|
|
|
function getUint16(view, offset) {
|
|
return view.getUint16(offset, true);
|
|
}
|
|
|
|
function getUint32(view, offset) {
|
|
return view.getUint32(offset, true);
|
|
}
|
|
|
|
function getBigUint64(view, offset) {
|
|
return Number(view.getBigUint64(offset, true));
|
|
}
|
|
|
|
function setUint32(view, offset, value) {
|
|
view.setUint32(offset, value, true);
|
|
}
|
|
|
|
function getDataView(array) {
|
|
return new DataView(array.buffer);
|
|
}
|
|
|
|
/*
|
|
Copyright (c) 2022 Gildas Lormeau. All rights reserved.
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
modification, are permitted provided that the following conditions are met:
|
|
|
|
1. Redistributions of source code must retain the above copyright notice,
|
|
this list of conditions and the following disclaimer.
|
|
|
|
2. Redistributions in binary form must reproduce the above copyright
|
|
notice, this list of conditions and the following disclaimer in
|
|
the documentation and/or other materials provided with the distribution.
|
|
|
|
3. The names of the authors may not be used to endorse or promote products
|
|
derived from this software without specific prior written permission.
|
|
|
|
THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
|
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
|
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
|
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
|
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
let baseURL$1;
|
|
try {
|
|
baseURL$1 = (typeof document === 'undefined' ? new (require('u' + 'rl').URL)('file:' + __filename).href : (document.currentScript && document.currentScript.tagName.toUpperCase() === 'SCRIPT' && document.currentScript.src || new URL('main.js', document.baseURI).href));
|
|
} catch (_error) {
|
|
// ignored
|
|
}
|
|
configure({ baseURL: baseURL$1 });
|
|
e(configure);
|
|
|
|
/// <reference types="./index.d.ts" />
|
|
|
|
configure({ Deflate: ZipDeflate, Inflate: ZipInflate });
|
|
|
|
/*
|
|
|
|
TypeScript Md5
|
|
==============
|
|
|
|
Based on work by
|
|
* Joseph Myers: http://www.myersdaily.org/joseph/javascript/md5-text.html
|
|
* André Cruz: https://github.com/satazor/SparkMD5
|
|
* Raymond Hill: https://github.com/gorhill/yamd5.js
|
|
|
|
Effectively a TypeScrypt re-write of Raymond Hill JS Library
|
|
|
|
The MIT License (MIT)
|
|
|
|
Copyright (C) 2014 Raymond Hill
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
of this software and associated documentation files (the "Software"), to deal
|
|
in the Software without restriction, including without limitation the rights
|
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
copies of the Software, and to permit persons to whom the Software is
|
|
furnished to do so, subject to the following conditions:
|
|
|
|
The above copyright notice and this permission notice shall be included in
|
|
all copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
THE SOFTWARE.
|
|
|
|
|
|
|
|
DO WHAT YOU WANT TO PUBLIC LICENSE
|
|
Version 2, December 2004
|
|
|
|
Copyright (C) 2015 André Cruz <amdfcruz@gmail.com>
|
|
|
|
Everyone is permitted to copy and distribute verbatim or modified
|
|
copies of this license document, and changing it is allowed as long
|
|
as the name is changed.
|
|
|
|
DO WHAT YOU WANT TO PUBLIC LICENSE
|
|
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
|
|
|
0. You just DO WHAT YOU WANT TO.
|
|
|
|
|
|
*/
|
|
class Md5 {
|
|
constructor() {
|
|
this._dataLength = 0;
|
|
this._bufferLength = 0;
|
|
this._state = new Int32Array(4);
|
|
this._buffer = new ArrayBuffer(68);
|
|
this._buffer8 = new Uint8Array(this._buffer, 0, 68);
|
|
this._buffer32 = new Uint32Array(this._buffer, 0, 17);
|
|
this.start();
|
|
}
|
|
static hashStr(str, raw = false) {
|
|
return this.onePassHasher
|
|
.start()
|
|
.appendStr(str)
|
|
.end(raw);
|
|
}
|
|
static hashAsciiStr(str, raw = false) {
|
|
return this.onePassHasher
|
|
.start()
|
|
.appendAsciiStr(str)
|
|
.end(raw);
|
|
}
|
|
static _hex(x) {
|
|
const hc = Md5.hexChars;
|
|
const ho = Md5.hexOut;
|
|
let n;
|
|
let offset;
|
|
let j;
|
|
let i;
|
|
for (i = 0; i < 4; i += 1) {
|
|
offset = i * 8;
|
|
n = x[i];
|
|
for (j = 0; j < 8; j += 2) {
|
|
ho[offset + 1 + j] = hc.charAt(n & 0x0F);
|
|
n >>>= 4;
|
|
ho[offset + 0 + j] = hc.charAt(n & 0x0F);
|
|
n >>>= 4;
|
|
}
|
|
}
|
|
return ho.join('');
|
|
}
|
|
static _md5cycle(x, k) {
|
|
let a = x[0];
|
|
let b = x[1];
|
|
let c = x[2];
|
|
let d = x[3];
|
|
// ff()
|
|
a += (b & c | ~b & d) + k[0] - 680876936 | 0;
|
|
a = (a << 7 | a >>> 25) + b | 0;
|
|
d += (a & b | ~a & c) + k[1] - 389564586 | 0;
|
|
d = (d << 12 | d >>> 20) + a | 0;
|
|
c += (d & a | ~d & b) + k[2] + 606105819 | 0;
|
|
c = (c << 17 | c >>> 15) + d | 0;
|
|
b += (c & d | ~c & a) + k[3] - 1044525330 | 0;
|
|
b = (b << 22 | b >>> 10) + c | 0;
|
|
a += (b & c | ~b & d) + k[4] - 176418897 | 0;
|
|
a = (a << 7 | a >>> 25) + b | 0;
|
|
d += (a & b | ~a & c) + k[5] + 1200080426 | 0;
|
|
d = (d << 12 | d >>> 20) + a | 0;
|
|
c += (d & a | ~d & b) + k[6] - 1473231341 | 0;
|
|
c = (c << 17 | c >>> 15) + d | 0;
|
|
b += (c & d | ~c & a) + k[7] - 45705983 | 0;
|
|
b = (b << 22 | b >>> 10) + c | 0;
|
|
a += (b & c | ~b & d) + k[8] + 1770035416 | 0;
|
|
a = (a << 7 | a >>> 25) + b | 0;
|
|
d += (a & b | ~a & c) + k[9] - 1958414417 | 0;
|
|
d = (d << 12 | d >>> 20) + a | 0;
|
|
c += (d & a | ~d & b) + k[10] - 42063 | 0;
|
|
c = (c << 17 | c >>> 15) + d | 0;
|
|
b += (c & d | ~c & a) + k[11] - 1990404162 | 0;
|
|
b = (b << 22 | b >>> 10) + c | 0;
|
|
a += (b & c | ~b & d) + k[12] + 1804603682 | 0;
|
|
a = (a << 7 | a >>> 25) + b | 0;
|
|
d += (a & b | ~a & c) + k[13] - 40341101 | 0;
|
|
d = (d << 12 | d >>> 20) + a | 0;
|
|
c += (d & a | ~d & b) + k[14] - 1502002290 | 0;
|
|
c = (c << 17 | c >>> 15) + d | 0;
|
|
b += (c & d | ~c & a) + k[15] + 1236535329 | 0;
|
|
b = (b << 22 | b >>> 10) + c | 0;
|
|
// gg()
|
|
a += (b & d | c & ~d) + k[1] - 165796510 | 0;
|
|
a = (a << 5 | a >>> 27) + b | 0;
|
|
d += (a & c | b & ~c) + k[6] - 1069501632 | 0;
|
|
d = (d << 9 | d >>> 23) + a | 0;
|
|
c += (d & b | a & ~b) + k[11] + 643717713 | 0;
|
|
c = (c << 14 | c >>> 18) + d | 0;
|
|
b += (c & a | d & ~a) + k[0] - 373897302 | 0;
|
|
b = (b << 20 | b >>> 12) + c | 0;
|
|
a += (b & d | c & ~d) + k[5] - 701558691 | 0;
|
|
a = (a << 5 | a >>> 27) + b | 0;
|
|
d += (a & c | b & ~c) + k[10] + 38016083 | 0;
|
|
d = (d << 9 | d >>> 23) + a | 0;
|
|
c += (d & b | a & ~b) + k[15] - 660478335 | 0;
|
|
c = (c << 14 | c >>> 18) + d | 0;
|
|
b += (c & a | d & ~a) + k[4] - 405537848 | 0;
|
|
b = (b << 20 | b >>> 12) + c | 0;
|
|
a += (b & d | c & ~d) + k[9] + 568446438 | 0;
|
|
a = (a << 5 | a >>> 27) + b | 0;
|
|
d += (a & c | b & ~c) + k[14] - 1019803690 | 0;
|
|
d = (d << 9 | d >>> 23) + a | 0;
|
|
c += (d & b | a & ~b) + k[3] - 187363961 | 0;
|
|
c = (c << 14 | c >>> 18) + d | 0;
|
|
b += (c & a | d & ~a) + k[8] + 1163531501 | 0;
|
|
b = (b << 20 | b >>> 12) + c | 0;
|
|
a += (b & d | c & ~d) + k[13] - 1444681467 | 0;
|
|
a = (a << 5 | a >>> 27) + b | 0;
|
|
d += (a & c | b & ~c) + k[2] - 51403784 | 0;
|
|
d = (d << 9 | d >>> 23) + a | 0;
|
|
c += (d & b | a & ~b) + k[7] + 1735328473 | 0;
|
|
c = (c << 14 | c >>> 18) + d | 0;
|
|
b += (c & a | d & ~a) + k[12] - 1926607734 | 0;
|
|
b = (b << 20 | b >>> 12) + c | 0;
|
|
// hh()
|
|
a += (b ^ c ^ d) + k[5] - 378558 | 0;
|
|
a = (a << 4 | a >>> 28) + b | 0;
|
|
d += (a ^ b ^ c) + k[8] - 2022574463 | 0;
|
|
d = (d << 11 | d >>> 21) + a | 0;
|
|
c += (d ^ a ^ b) + k[11] + 1839030562 | 0;
|
|
c = (c << 16 | c >>> 16) + d | 0;
|
|
b += (c ^ d ^ a) + k[14] - 35309556 | 0;
|
|
b = (b << 23 | b >>> 9) + c | 0;
|
|
a += (b ^ c ^ d) + k[1] - 1530992060 | 0;
|
|
a = (a << 4 | a >>> 28) + b | 0;
|
|
d += (a ^ b ^ c) + k[4] + 1272893353 | 0;
|
|
d = (d << 11 | d >>> 21) + a | 0;
|
|
c += (d ^ a ^ b) + k[7] - 155497632 | 0;
|
|
c = (c << 16 | c >>> 16) + d | 0;
|
|
b += (c ^ d ^ a) + k[10] - 1094730640 | 0;
|
|
b = (b << 23 | b >>> 9) + c | 0;
|
|
a += (b ^ c ^ d) + k[13] + 681279174 | 0;
|
|
a = (a << 4 | a >>> 28) + b | 0;
|
|
d += (a ^ b ^ c) + k[0] - 358537222 | 0;
|
|
d = (d << 11 | d >>> 21) + a | 0;
|
|
c += (d ^ a ^ b) + k[3] - 722521979 | 0;
|
|
c = (c << 16 | c >>> 16) + d | 0;
|
|
b += (c ^ d ^ a) + k[6] + 76029189 | 0;
|
|
b = (b << 23 | b >>> 9) + c | 0;
|
|
a += (b ^ c ^ d) + k[9] - 640364487 | 0;
|
|
a = (a << 4 | a >>> 28) + b | 0;
|
|
d += (a ^ b ^ c) + k[12] - 421815835 | 0;
|
|
d = (d << 11 | d >>> 21) + a | 0;
|
|
c += (d ^ a ^ b) + k[15] + 530742520 | 0;
|
|
c = (c << 16 | c >>> 16) + d | 0;
|
|
b += (c ^ d ^ a) + k[2] - 995338651 | 0;
|
|
b = (b << 23 | b >>> 9) + c | 0;
|
|
// ii()
|
|
a += (c ^ (b | ~d)) + k[0] - 198630844 | 0;
|
|
a = (a << 6 | a >>> 26) + b | 0;
|
|
d += (b ^ (a | ~c)) + k[7] + 1126891415 | 0;
|
|
d = (d << 10 | d >>> 22) + a | 0;
|
|
c += (a ^ (d | ~b)) + k[14] - 1416354905 | 0;
|
|
c = (c << 15 | c >>> 17) + d | 0;
|
|
b += (d ^ (c | ~a)) + k[5] - 57434055 | 0;
|
|
b = (b << 21 | b >>> 11) + c | 0;
|
|
a += (c ^ (b | ~d)) + k[12] + 1700485571 | 0;
|
|
a = (a << 6 | a >>> 26) + b | 0;
|
|
d += (b ^ (a | ~c)) + k[3] - 1894986606 | 0;
|
|
d = (d << 10 | d >>> 22) + a | 0;
|
|
c += (a ^ (d | ~b)) + k[10] - 1051523 | 0;
|
|
c = (c << 15 | c >>> 17) + d | 0;
|
|
b += (d ^ (c | ~a)) + k[1] - 2054922799 | 0;
|
|
b = (b << 21 | b >>> 11) + c | 0;
|
|
a += (c ^ (b | ~d)) + k[8] + 1873313359 | 0;
|
|
a = (a << 6 | a >>> 26) + b | 0;
|
|
d += (b ^ (a | ~c)) + k[15] - 30611744 | 0;
|
|
d = (d << 10 | d >>> 22) + a | 0;
|
|
c += (a ^ (d | ~b)) + k[6] - 1560198380 | 0;
|
|
c = (c << 15 | c >>> 17) + d | 0;
|
|
b += (d ^ (c | ~a)) + k[13] + 1309151649 | 0;
|
|
b = (b << 21 | b >>> 11) + c | 0;
|
|
a += (c ^ (b | ~d)) + k[4] - 145523070 | 0;
|
|
a = (a << 6 | a >>> 26) + b | 0;
|
|
d += (b ^ (a | ~c)) + k[11] - 1120210379 | 0;
|
|
d = (d << 10 | d >>> 22) + a | 0;
|
|
c += (a ^ (d | ~b)) + k[2] + 718787259 | 0;
|
|
c = (c << 15 | c >>> 17) + d | 0;
|
|
b += (d ^ (c | ~a)) + k[9] - 343485551 | 0;
|
|
b = (b << 21 | b >>> 11) + c | 0;
|
|
x[0] = a + x[0] | 0;
|
|
x[1] = b + x[1] | 0;
|
|
x[2] = c + x[2] | 0;
|
|
x[3] = d + x[3] | 0;
|
|
}
|
|
/**
|
|
* Initialise buffer to be hashed
|
|
*/
|
|
start() {
|
|
this._dataLength = 0;
|
|
this._bufferLength = 0;
|
|
this._state.set(Md5.stateIdentity);
|
|
return this;
|
|
}
|
|
// Char to code point to to array conversion:
|
|
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/charCodeAt
|
|
// #Example.3A_Fixing_charCodeAt_to_handle_non-Basic-Multilingual-Plane_characters_if_their_presence_earlier_in_the_string_is_unknown
|
|
/**
|
|
* Append a UTF-8 string to the hash buffer
|
|
* @param str String to append
|
|
*/
|
|
appendStr(str) {
|
|
const buf8 = this._buffer8;
|
|
const buf32 = this._buffer32;
|
|
let bufLen = this._bufferLength;
|
|
let code;
|
|
let i;
|
|
for (i = 0; i < str.length; i += 1) {
|
|
code = str.charCodeAt(i);
|
|
if (code < 128) {
|
|
buf8[bufLen++] = code;
|
|
}
|
|
else if (code < 0x800) {
|
|
buf8[bufLen++] = (code >>> 6) + 0xC0;
|
|
buf8[bufLen++] = code & 0x3F | 0x80;
|
|
}
|
|
else if (code < 0xD800 || code > 0xDBFF) {
|
|
buf8[bufLen++] = (code >>> 12) + 0xE0;
|
|
buf8[bufLen++] = (code >>> 6 & 0x3F) | 0x80;
|
|
buf8[bufLen++] = (code & 0x3F) | 0x80;
|
|
}
|
|
else {
|
|
code = ((code - 0xD800) * 0x400) + (str.charCodeAt(++i) - 0xDC00) + 0x10000;
|
|
if (code > 0x10FFFF) {
|
|
throw new Error('Unicode standard supports code points up to U+10FFFF');
|
|
}
|
|
buf8[bufLen++] = (code >>> 18) + 0xF0;
|
|
buf8[bufLen++] = (code >>> 12 & 0x3F) | 0x80;
|
|
buf8[bufLen++] = (code >>> 6 & 0x3F) | 0x80;
|
|
buf8[bufLen++] = (code & 0x3F) | 0x80;
|
|
}
|
|
if (bufLen >= 64) {
|
|
this._dataLength += 64;
|
|
Md5._md5cycle(this._state, buf32);
|
|
bufLen -= 64;
|
|
buf32[0] = buf32[16];
|
|
}
|
|
}
|
|
this._bufferLength = bufLen;
|
|
return this;
|
|
}
|
|
/**
|
|
* Append an ASCII string to the hash buffer
|
|
* @param str String to append
|
|
*/
|
|
appendAsciiStr(str) {
|
|
const buf8 = this._buffer8;
|
|
const buf32 = this._buffer32;
|
|
let bufLen = this._bufferLength;
|
|
let i;
|
|
let j = 0;
|
|
for (;;) {
|
|
i = Math.min(str.length - j, 64 - bufLen);
|
|
while (i--) {
|
|
buf8[bufLen++] = str.charCodeAt(j++);
|
|
}
|
|
if (bufLen < 64) {
|
|
break;
|
|
}
|
|
this._dataLength += 64;
|
|
Md5._md5cycle(this._state, buf32);
|
|
bufLen = 0;
|
|
}
|
|
this._bufferLength = bufLen;
|
|
return this;
|
|
}
|
|
/**
|
|
* Append a byte array to the hash buffer
|
|
* @param input array to append
|
|
*/
|
|
appendByteArray(input) {
|
|
const buf8 = this._buffer8;
|
|
const buf32 = this._buffer32;
|
|
let bufLen = this._bufferLength;
|
|
let i;
|
|
let j = 0;
|
|
for (;;) {
|
|
i = Math.min(input.length - j, 64 - bufLen);
|
|
while (i--) {
|
|
buf8[bufLen++] = input[j++];
|
|
}
|
|
if (bufLen < 64) {
|
|
break;
|
|
}
|
|
this._dataLength += 64;
|
|
Md5._md5cycle(this._state, buf32);
|
|
bufLen = 0;
|
|
}
|
|
this._bufferLength = bufLen;
|
|
return this;
|
|
}
|
|
/**
|
|
* Get the state of the hash buffer
|
|
*/
|
|
getState() {
|
|
const s = this._state;
|
|
return {
|
|
buffer: String.fromCharCode.apply(null, Array.from(this._buffer8)),
|
|
buflen: this._bufferLength,
|
|
length: this._dataLength,
|
|
state: [s[0], s[1], s[2], s[3]]
|
|
};
|
|
}
|
|
/**
|
|
* Override the current state of the hash buffer
|
|
* @param state New hash buffer state
|
|
*/
|
|
setState(state) {
|
|
const buf = state.buffer;
|
|
const x = state.state;
|
|
const s = this._state;
|
|
let i;
|
|
this._dataLength = state.length;
|
|
this._bufferLength = state.buflen;
|
|
s[0] = x[0];
|
|
s[1] = x[1];
|
|
s[2] = x[2];
|
|
s[3] = x[3];
|
|
for (i = 0; i < buf.length; i += 1) {
|
|
this._buffer8[i] = buf.charCodeAt(i);
|
|
}
|
|
}
|
|
/**
|
|
* Hash the current state of the hash buffer and return the result
|
|
* @param raw Whether to return the value as an `Int32Array`
|
|
*/
|
|
end(raw = false) {
|
|
const bufLen = this._bufferLength;
|
|
const buf8 = this._buffer8;
|
|
const buf32 = this._buffer32;
|
|
const i = (bufLen >> 2) + 1;
|
|
this._dataLength += bufLen;
|
|
const dataBitsLen = this._dataLength * 8;
|
|
buf8[bufLen] = 0x80;
|
|
buf8[bufLen + 1] = buf8[bufLen + 2] = buf8[bufLen + 3] = 0;
|
|
buf32.set(Md5.buffer32Identity.subarray(i), i);
|
|
if (bufLen > 55) {
|
|
Md5._md5cycle(this._state, buf32);
|
|
buf32.set(Md5.buffer32Identity);
|
|
}
|
|
// Do the final computation based on the tail and length
|
|
// Beware that the final length may not fit in 32 bits so we take care of that
|
|
if (dataBitsLen <= 0xFFFFFFFF) {
|
|
buf32[14] = dataBitsLen;
|
|
}
|
|
else {
|
|
const matches = dataBitsLen.toString(16).match(/(.*?)(.{0,8})$/);
|
|
if (matches === null) {
|
|
return;
|
|
}
|
|
const lo = parseInt(matches[2], 16);
|
|
const hi = parseInt(matches[1], 16) || 0;
|
|
buf32[14] = lo;
|
|
buf32[15] = hi;
|
|
}
|
|
Md5._md5cycle(this._state, buf32);
|
|
return raw ? this._state : Md5._hex(this._state);
|
|
}
|
|
}
|
|
// Private Static Variables
|
|
Md5.stateIdentity = new Int32Array([1732584193, -271733879, -1732584194, 271733878]);
|
|
Md5.buffer32Identity = new Int32Array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
|
|
Md5.hexChars = '0123456789abcdef';
|
|
Md5.hexOut = [];
|
|
// Permanent instance is to use for one-call hashing
|
|
Md5.onePassHasher = new Md5();
|
|
if (Md5.hashStr('hello') !== '5d41402abc4b2a76b9719d911017c592') {
|
|
throw new Error('Md5 self test failed.');
|
|
}
|
|
|
|
// Inspired by
|
|
// https://github.com/renehernandez/obsidian-readwise/blob/eee5676524962ebfa7eaf1084e018dafe3c2f394/src/status.ts
|
|
class StatusBar {
|
|
constructor(statusBarEl) {
|
|
this.messages = [];
|
|
this.statusBarEl = statusBarEl;
|
|
}
|
|
displayMessage(message, timeout, forcing = false) {
|
|
if (this.messages[0] && this.messages[0].message === message) {
|
|
// don't show the same message twice
|
|
return;
|
|
}
|
|
this.messages.push({
|
|
message: `readwise: ${message.slice(0, 100)}`,
|
|
timeout: timeout * 1000,
|
|
});
|
|
if (forcing) {
|
|
this.currentMessage = null;
|
|
this.lastMessageTimestamp = null;
|
|
this.statusBarEl.setText("");
|
|
}
|
|
this.display();
|
|
}
|
|
display() {
|
|
if (this.currentMessage) {
|
|
let messageAge = Date.now() - this.lastMessageTimestamp;
|
|
if (messageAge >= this.currentMessage.timeout) {
|
|
this.currentMessage = null;
|
|
this.lastMessageTimestamp = null;
|
|
}
|
|
}
|
|
else if (this.messages.length) {
|
|
this.currentMessage = this.messages.shift();
|
|
this.statusBarEl.setText(this.currentMessage.message);
|
|
this.lastMessageTimestamp = Date.now();
|
|
return;
|
|
}
|
|
else {
|
|
this.statusBarEl.setText("");
|
|
}
|
|
}
|
|
}
|
|
|
|
// keep pluginVersion in sync with manifest.json
|
|
const pluginVersion = "3.0.1";
|
|
// switch to local dev server for development
|
|
const baseURL = "https://readwise.io";
|
|
// define our initial settings
|
|
// quoted keys for easy copying to data.json during development
|
|
const DEFAULT_SETTINGS = {
|
|
"token": "",
|
|
"readwiseDir": "Readwise",
|
|
"frequency": "0",
|
|
"triggerOnLoad": true,
|
|
"isSyncing": false,
|
|
"lastSyncFailed": false,
|
|
"lastSavedStatusID": 0,
|
|
"currentSyncStatusID": 0,
|
|
"refreshBooks": false,
|
|
"booksToRefresh": [],
|
|
"failedBooks": [],
|
|
"booksIDsMap": {},
|
|
"reimportShowConfirmation": true
|
|
};
|
|
/** The name of the Readwise Sync history file, without the extension.
|
|
* This is described as "Sync notification" in the Obsidian export settings
|
|
* on the Readwise website. */
|
|
const READWISE_SYNC_FILENAME = "Readwise Syncs";
|
|
class ReadwisePlugin extends obsidian.Plugin {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.scheduleInterval = null;
|
|
}
|
|
getErrorMessageFromResponse(response) {
|
|
if (response && response.status === 409) {
|
|
return "Sync in progress initiated by different client";
|
|
}
|
|
if (response && response.status === 417) {
|
|
return "Obsidian export is locked. Wait for an hour.";
|
|
}
|
|
return `${response ? response.statusText : "Can't connect to server"}`;
|
|
}
|
|
handleSyncError(buttonContext, msg) {
|
|
return __awaiter(this, void 0, void 0, function* () {
|
|
yield this.clearSettingsAfterRun();
|
|
this.settings.lastSyncFailed = true;
|
|
yield this.saveSettings();
|
|
if (buttonContext) {
|
|
this.showInfoStatus(buttonContext.buttonEl.parentElement, msg, "rw-error");
|
|
buttonContext.buttonEl.setText("Run sync");
|
|
}
|
|
else {
|
|
this.notice(msg, true, 4, true);
|
|
}
|
|
});
|
|
}
|
|
clearSettingsAfterRun() {
|
|
return __awaiter(this, void 0, void 0, function* () {
|
|
this.settings.isSyncing = false;
|
|
this.settings.currentSyncStatusID = 0;
|
|
yield this.saveSettings();
|
|
});
|
|
}
|
|
handleSyncSuccess(buttonContext, msg = "Synced", exportID = null) {
|
|
return __awaiter(this, void 0, void 0, function* () {
|
|
yield this.clearSettingsAfterRun();
|
|
this.settings.lastSyncFailed = false;
|
|
if (exportID) {
|
|
this.settings.lastSavedStatusID = exportID;
|
|
}
|
|
yield this.saveSettings();
|
|
// if we have a button context, update the text on it
|
|
// this is the case if we fired on a "Run sync" click (the button)
|
|
if (buttonContext) {
|
|
this.showInfoStatus(buttonContext.buttonEl.parentNode.parentElement, msg, "rw-success");
|
|
buttonContext.buttonEl.setText("Run sync");
|
|
}
|
|
});
|
|
}
|
|
/** Polls the Readwise API for the status of a given export;
|
|
* uses recursion for polling so that it can be awaited. */
|
|
getExportStatus(statusID, buttonContext, _processedArtifactIds) {
|
|
return __awaiter(this, void 0, void 0, function* () {
|
|
if (statusID <= this.settings.lastSavedStatusID) {
|
|
console.log(`Readwise Official plugin: Already saved data from export ${statusID}`);
|
|
yield this.handleSyncSuccess(buttonContext);
|
|
this.notice("Readwise data is already up to date", false, 4);
|
|
return;
|
|
}
|
|
const processedArtifactIds = _processedArtifactIds !== null && _processedArtifactIds !== void 0 ? _processedArtifactIds : new Set();
|
|
const downloadUnprocessedArtifacts = (allArtifactIds) => __awaiter(this, void 0, void 0, function* () {
|
|
for (const artifactId of allArtifactIds) {
|
|
if (!processedArtifactIds.has(artifactId)) {
|
|
yield this.downloadArtifact(artifactId, buttonContext);
|
|
processedArtifactIds.add(artifactId);
|
|
}
|
|
}
|
|
});
|
|
try {
|
|
const response = yield fetch(
|
|
// status of archive build from this endpoint
|
|
`${baseURL}/api/get_export_status?exportStatusId=${statusID}`, {
|
|
headers: this.getAuthHeaders(),
|
|
});
|
|
if (response && response.ok) {
|
|
const data = yield response.json();
|
|
const WAITING_STATUSES = ['PENDING', 'RECEIVED', 'STARTED', 'RETRY'];
|
|
const SUCCESS_STATUSES = ['SUCCESS'];
|
|
if (WAITING_STATUSES.includes(data.taskStatus)) {
|
|
if (data.booksExported) {
|
|
const progressMsg = `Exporting Readwise data (${data.booksExported} / ${data.totalBooks}) ...`;
|
|
this.notice(progressMsg, false, 35, true);
|
|
}
|
|
else {
|
|
this.notice("Building export...");
|
|
}
|
|
// process any artifacts available while the export is still being generated
|
|
yield downloadUnprocessedArtifacts(data.artifactIds);
|
|
// wait 1 second
|
|
yield new Promise(resolve => setTimeout(resolve, 1000));
|
|
// then keep polling
|
|
yield this.getExportStatus(statusID, buttonContext, processedArtifactIds);
|
|
}
|
|
else if (SUCCESS_STATUSES.includes(data.taskStatus)) {
|
|
// make sure all artifacts are processed
|
|
yield downloadUnprocessedArtifacts(data.artifactIds);
|
|
yield this.acknowledgeSyncCompleted(buttonContext);
|
|
yield this.handleSyncSuccess(buttonContext, "Synced!", statusID);
|
|
this.notice("Readwise sync completed", true, 1, true);
|
|
console.log("Readwise Official plugin: completed sync");
|
|
// @ts-ignore
|
|
if (this.app.isMobile) {
|
|
this.notice("If you don't see all of your Readwise files, please reload the Obsidian app", true);
|
|
}
|
|
}
|
|
else {
|
|
console.log("Readwise Official plugin: unknown status in getExportStatus: ", data);
|
|
yield this.handleSyncError(buttonContext, "Sync failed");
|
|
return;
|
|
}
|
|
}
|
|
else {
|
|
console.log("Readwise Official plugin: bad response in getExportStatus: ", response);
|
|
yield this.handleSyncError(buttonContext, this.getErrorMessageFromResponse(response));
|
|
}
|
|
}
|
|
catch (e) {
|
|
console.log("Readwise Official plugin: fetch failed in getExportStatus: ", e);
|
|
yield this.handleSyncError(buttonContext, "Sync failed");
|
|
}
|
|
});
|
|
}
|
|
/** Requests the archive from Readwise, polling until it's ready */
|
|
queueExport(buttonContext, statusId, auto) {
|
|
return __awaiter(this, void 0, void 0, function* () {
|
|
if (this.settings.isSyncing) {
|
|
this.notice("Readwise sync already in progress", true);
|
|
return;
|
|
}
|
|
console.log('Readwise Official plugin: requesting archive...');
|
|
this.settings.isSyncing = true;
|
|
yield this.saveSettings();
|
|
const parentDeleted = !(yield this.app.vault.adapter.exists(this.settings.readwiseDir));
|
|
// kickoff archive build form this endpoint
|
|
let url = `${baseURL}/api/obsidian/init?parentPageDeleted=${parentDeleted}`;
|
|
if (statusId) {
|
|
url += `&statusID=${statusId}`;
|
|
}
|
|
if (auto) {
|
|
url += `&auto=${auto}`;
|
|
}
|
|
let response, data;
|
|
try {
|
|
response = yield fetch(url, {
|
|
headers: this.getAuthHeaders()
|
|
});
|
|
}
|
|
catch (e) {
|
|
console.log("Readwise Official plugin: fetch failed in queueExport: ", e);
|
|
}
|
|
if (response && response.ok) {
|
|
data = yield response.json();
|
|
if (data.latest_id <= this.settings.lastSavedStatusID) {
|
|
yield this.handleSyncSuccess(buttonContext);
|
|
this.notice("Readwise data is already up to date", false, 4, true);
|
|
return;
|
|
}
|
|
// save the sync status ID so it can be polled until the archive is ready
|
|
this.settings.currentSyncStatusID = data.latest_id;
|
|
yield this.saveSettings();
|
|
console.log("Readwise Official plugin: saved currentSyncStatusID", this.settings.currentSyncStatusID);
|
|
if (response.status === 201) {
|
|
this.notice("Syncing Readwise data");
|
|
yield this.getExportStatus(this.settings.currentSyncStatusID, buttonContext);
|
|
console.log('Readwise Official plugin: queueExport done');
|
|
}
|
|
else {
|
|
yield this.handleSyncSuccess(buttonContext, "Synced", data.latest_id);
|
|
this.notice("Latest Readwise sync already happened on your other device. Data should be up to date", false, 4, true);
|
|
}
|
|
}
|
|
else {
|
|
console.log("Readwise Official plugin: bad response in queueExport: ", response);
|
|
yield this.handleSyncError(buttonContext, this.getErrorMessageFromResponse(response));
|
|
return;
|
|
}
|
|
});
|
|
}
|
|
notice(msg, show = false, timeout = 0, forcing = false) {
|
|
if (show) {
|
|
new obsidian.Notice(msg);
|
|
}
|
|
// @ts-ignore
|
|
if (!this.app.isMobile) {
|
|
this.statusBar.displayMessage(msg.toLowerCase(), timeout, forcing);
|
|
}
|
|
else {
|
|
if (!show) {
|
|
new obsidian.Notice(msg);
|
|
}
|
|
}
|
|
}
|
|
showInfoStatus(container, msg, className = "") {
|
|
let info = container.find('.rw-info-container');
|
|
info.setText(msg);
|
|
info.addClass(className);
|
|
}
|
|
clearInfoStatus(container) {
|
|
let info = container.find('.rw-info-container');
|
|
info.empty();
|
|
}
|
|
getAuthHeaders() {
|
|
return {
|
|
'AUTHORIZATION': `Token ${this.settings.token}`,
|
|
'Obsidian-Client': `${this.getObsidianClientID()}`,
|
|
'Readwise-Client-Version': pluginVersion,
|
|
};
|
|
}
|
|
downloadArtifact(artifactId, buttonContext) {
|
|
var _a;
|
|
return __awaiter(this, void 0, void 0, function* () {
|
|
// download archive from this endpoint
|
|
let artifactURL = `${baseURL}/api/v2/download_artifact/${artifactId}`;
|
|
let response, blob;
|
|
try {
|
|
response = yield fetch(artifactURL, { headers: this.getAuthHeaders() });
|
|
}
|
|
catch (e) {
|
|
console.log("Readwise Official plugin: fetch failed in downloadExport: ", e);
|
|
}
|
|
if (response && response.ok) {
|
|
blob = yield response.blob();
|
|
}
|
|
else {
|
|
console.log("Readwise Official plugin: bad response in downloadExport: ", response);
|
|
yield this.handleSyncError(buttonContext, this.getErrorMessageFromResponse(response));
|
|
throw new Error(`Readwise: error while fetching artifact ${artifactId}`);
|
|
}
|
|
this.fs = this.app.vault.adapter;
|
|
const blobReader = new BlobReader(blob);
|
|
const zipReader = new ZipReader(blobReader);
|
|
const entries = yield zipReader.getEntries();
|
|
if (entries.length) {
|
|
for (const entry of entries) {
|
|
// will be extracted from JSON data
|
|
let bookID;
|
|
let data;
|
|
/** Combo of file `readwiseDir` and book name.
|
|
* Example: `Readwise/Books/Name of Book.json` */
|
|
const processedFileName = obsidian.normalizePath(entry.filename
|
|
.replace(/^Readwise/, this.settings.readwiseDir)
|
|
.replace(/\.json$/, ".md"));
|
|
const isReadwiseSyncFile = processedFileName === `${this.settings.readwiseDir}/${READWISE_SYNC_FILENAME}.md`;
|
|
try {
|
|
const fileContent = yield entry.getData(new TextWriter());
|
|
if (isReadwiseSyncFile) {
|
|
data = {
|
|
append_only_content: fileContent,
|
|
};
|
|
}
|
|
else {
|
|
data = JSON.parse(fileContent);
|
|
}
|
|
bookID = this.encodeReadwiseBookId(data.book_id) || this.encodeReaderDocumentId(data.reader_document_id);
|
|
const undefinedBook = !bookID || !processedFileName;
|
|
if (undefinedBook && !isReadwiseSyncFile) {
|
|
console.error(`Error while processing entry: ${entry.filename}`);
|
|
}
|
|
// write the full document text file
|
|
if (data.full_document_text && data.full_document_text_path) {
|
|
const processedFullDocumentTextFileName = data.full_document_text_path.replace(/^Readwise/, this.settings.readwiseDir);
|
|
console.log("Writing full document text", processedFullDocumentTextFileName);
|
|
// track the book
|
|
this.settings.booksIDsMap[processedFullDocumentTextFileName] = bookID;
|
|
// ensure the directory exists
|
|
yield this.createDirForFile(processedFullDocumentTextFileName);
|
|
if (!(yield this.fs.exists(processedFullDocumentTextFileName))) {
|
|
// it's a new full document content file, just save it
|
|
yield this.fs.write(processedFullDocumentTextFileName, data.full_document_text);
|
|
}
|
|
else {
|
|
// full document content file already exists — overwrite it if it wasn't edited locally
|
|
const existingFullDocument = yield this.fs.read(processedFullDocumentTextFileName);
|
|
const existingFullDocumentHash = Md5.hashStr(existingFullDocument).toString();
|
|
if (existingFullDocumentHash === data.last_full_document_hash) {
|
|
yield this.fs.write(processedFullDocumentTextFileName, data.full_document_text);
|
|
}
|
|
}
|
|
}
|
|
// write the actual files
|
|
let contentToSave = (_a = data.full_content) !== null && _a !== void 0 ? _a : data.append_only_content;
|
|
if (contentToSave) {
|
|
// track the book
|
|
this.settings.booksIDsMap[processedFileName] = bookID;
|
|
// ensure the directory exists
|
|
yield this.createDirForFile(processedFileName);
|
|
if (yield this.fs.exists(processedFileName)) {
|
|
// if the file already exists we need to append content to existing one
|
|
const existingContent = yield this.fs.read(processedFileName);
|
|
const existingContentHash = Md5.hashStr(existingContent).toString();
|
|
if (existingContentHash !== data.last_content_hash) {
|
|
// content has been modified (it differs from the previously exported full document)
|
|
contentToSave = existingContent.trimEnd() + "\n" + data.append_only_content;
|
|
}
|
|
}
|
|
yield this.fs.write(processedFileName, contentToSave);
|
|
}
|
|
// save the entry in settings to ensure that it can be
|
|
// retried later when deleted files are re-synced if
|
|
// the user has `settings.refreshBooks` enabled
|
|
if (bookID)
|
|
yield this.saveSettings();
|
|
}
|
|
catch (e) {
|
|
console.log(`Readwise Official plugin: error writing ${processedFileName}:`, e);
|
|
this.notice(`Readwise: error while writing ${processedFileName}: ${e}`, true, 4, true);
|
|
if (bookID) {
|
|
// handles case where user doesn't have `settings.refreshBooks` enabled
|
|
yield this.addToFailedBooks(bookID);
|
|
yield this.saveSettings();
|
|
}
|
|
// communicate with readwise?
|
|
throw new Error(`Readwise: error while processing artifact ${artifactId}`);
|
|
}
|
|
if (data) {
|
|
yield this.removeBooksFromRefresh([this.encodeReadwiseBookId(data.book_id), this.encodeReaderDocumentId(data.reader_document_id)]);
|
|
yield this.removeBookFromFailedBooks([this.encodeReadwiseBookId(data.book_id), this.encodeReaderDocumentId(data.reader_document_id)]);
|
|
}
|
|
}
|
|
yield this.saveSettings();
|
|
}
|
|
// close the ZipReader
|
|
yield zipReader.close();
|
|
// wait for the metadata cache to process created/updated documents
|
|
yield new Promise((resolve) => {
|
|
const timeoutSeconds = 15;
|
|
console.log(`Readwise Official plugin: waiting for metadata cache processing for up to ${timeoutSeconds}s...`);
|
|
const timeout = setTimeout(() => {
|
|
this.app.metadataCache.offref(eventRef);
|
|
console.log("Readwise Official plugin: metadata cache processing timeout reached.");
|
|
resolve();
|
|
}, timeoutSeconds * 1000);
|
|
const eventRef = this.app.metadataCache.on("resolved", () => {
|
|
this.app.metadataCache.offref(eventRef);
|
|
clearTimeout(timeout);
|
|
console.log("Readwise Official plugin: metadata cache processing has finished.");
|
|
resolve();
|
|
});
|
|
});
|
|
});
|
|
}
|
|
acknowledgeSyncCompleted(buttonContext) {
|
|
return __awaiter(this, void 0, void 0, function* () {
|
|
let response;
|
|
try {
|
|
response = yield fetch(`${baseURL}/api/obsidian/sync_ack`, {
|
|
headers: Object.assign(Object.assign({}, this.getAuthHeaders()), { 'Content-Type': 'application/json' }),
|
|
method: "POST",
|
|
});
|
|
}
|
|
catch (e) {
|
|
console.log("Readwise Official plugin: fetch failed to acknowledged sync: ", e);
|
|
}
|
|
if (response && response.ok) {
|
|
return;
|
|
}
|
|
else {
|
|
console.log("Readwise Official plugin: bad response in acknowledge sync: ", response);
|
|
yield this.handleSyncError(buttonContext, this.getErrorMessageFromResponse(response));
|
|
return;
|
|
}
|
|
});
|
|
}
|
|
configureSchedule() {
|
|
return __awaiter(this, void 0, void 0, function* () {
|
|
const minutes = parseInt(this.settings.frequency);
|
|
let milliseconds = minutes * 60 * 1000; // minutes * seconds * milliseconds
|
|
console.log('Readwise Official plugin: setting interval to ', milliseconds, 'milliseconds');
|
|
window.clearInterval(this.scheduleInterval);
|
|
this.scheduleInterval = null;
|
|
if (!milliseconds) {
|
|
// user set frequency to manual
|
|
return;
|
|
}
|
|
this.scheduleInterval = window.setInterval(() => this.syncBookHighlights(undefined, true), milliseconds);
|
|
this.registerInterval(this.scheduleInterval);
|
|
});
|
|
}
|
|
/** Syncs provided book IDs, or uses the booksToRefresh list if none provided.
|
|
* ALL syncing starts with this function. */
|
|
syncBookHighlights(
|
|
/** optional list of specific book IDs to sync */
|
|
bookIds,
|
|
/** if true, was not initiated by user */
|
|
auto) {
|
|
return __awaiter(this, void 0, void 0, function* () {
|
|
if (!this.settings.token)
|
|
return;
|
|
let targetBookIds = [
|
|
// try to sync provided bookIds
|
|
...(bookIds || []),
|
|
// always try to sync failedBooks
|
|
...this.settings.failedBooks,
|
|
];
|
|
// only sync `booksToRefresh` items if "resync deleted files" enabled
|
|
if (this.settings.refreshBooks) {
|
|
targetBookIds = [
|
|
...targetBookIds,
|
|
...this.settings.booksToRefresh,
|
|
];
|
|
}
|
|
if (!targetBookIds.length) {
|
|
console.log('Readwise Official plugin: no targetBookIds, checking for new highlights');
|
|
// no need to hit refresh_book_export;
|
|
// just check if there's new highlights from the server
|
|
yield this.queueExport();
|
|
return;
|
|
}
|
|
console.log('Readwise Official plugin: refreshing books', { targetBookIds });
|
|
let requestBookIds = [];
|
|
let requestReaderDocumentIds = [];
|
|
targetBookIds.map(id => {
|
|
const readerDocumentId = this.decodeReaderDocumentId(id);
|
|
if (readerDocumentId) {
|
|
requestReaderDocumentIds.push(readerDocumentId);
|
|
}
|
|
else {
|
|
requestBookIds.push(id);
|
|
}
|
|
});
|
|
try {
|
|
const response = yield fetch(
|
|
// add books to next archive build from this endpoint
|
|
// NOTE: should only end up calling this endpoint when:
|
|
// 1. there are failedBooks
|
|
// 2. there are booksToRefresh
|
|
`${baseURL}/api/refresh_book_export`, {
|
|
headers: Object.assign(Object.assign({}, this.getAuthHeaders()), { 'Content-Type': 'application/json' }),
|
|
method: "POST",
|
|
body: JSON.stringify({
|
|
exportTarget: 'obsidian',
|
|
userBookIds: requestBookIds,
|
|
readerDocumentIds: requestReaderDocumentIds,
|
|
})
|
|
});
|
|
if (response && response.ok) {
|
|
yield this.queueExport();
|
|
return;
|
|
}
|
|
else {
|
|
console.log(`Readwise Official plugin: saving book id ${bookIds} to refresh later`);
|
|
const deduplicatedBookIds = new Set([...this.settings.booksToRefresh, ...bookIds]);
|
|
this.settings.booksToRefresh = Array.from(deduplicatedBookIds);
|
|
yield this.saveSettings();
|
|
return;
|
|
}
|
|
}
|
|
catch (e) {
|
|
console.log("Readwise Official plugin: fetch failed in syncBookHighlights: ", e);
|
|
}
|
|
});
|
|
}
|
|
addToFailedBooks(bookId) {
|
|
return __awaiter(this, void 0, void 0, function* () {
|
|
// NOTE: settings.failedBooks was added after initial settings schema,
|
|
// so not all users may have it, hence the fallback to DEFAULT_SETTINGS.failedBooks
|
|
let failedBooks = [...(this.settings.failedBooks || DEFAULT_SETTINGS.failedBooks)];
|
|
failedBooks.push(bookId);
|
|
console.log(`Readwise Official plugin: added book id ${bookId} to failed books`);
|
|
this.settings.failedBooks = failedBooks;
|
|
// don't forget to save after!
|
|
// but don't do that here; this allows batching when removing multiple books.
|
|
});
|
|
}
|
|
addBookToRefresh(bookId) {
|
|
return __awaiter(this, void 0, void 0, function* () {
|
|
let booksToRefresh = [...this.settings.booksToRefresh];
|
|
booksToRefresh.push(bookId);
|
|
console.log(`Readwise Official plugin: added book id ${bookId} to refresh list`);
|
|
this.settings.booksToRefresh = booksToRefresh;
|
|
yield this.saveSettings();
|
|
});
|
|
}
|
|
removeBooksFromRefresh(bookIds = []) {
|
|
return __awaiter(this, void 0, void 0, function* () {
|
|
if (!bookIds.length)
|
|
return;
|
|
console.log(`Readwise Official plugin: removing book ids ${bookIds.join(', ')} from refresh list`);
|
|
this.settings.booksToRefresh = this.settings.booksToRefresh.filter(n => !bookIds.includes(n));
|
|
// don't forget to save after!
|
|
// but don't do that here; this allows batching when removing multiple books.
|
|
});
|
|
}
|
|
removeBookFromFailedBooks(bookIds = []) {
|
|
return __awaiter(this, void 0, void 0, function* () {
|
|
if (!bookIds.length)
|
|
return;
|
|
console.log(`Readwise Official plugin: removing book ids ${bookIds.join(', ')} from failed list`);
|
|
this.settings.failedBooks = this.settings.failedBooks.filter(n => !bookIds.includes(n));
|
|
// don't forget to save after!
|
|
// but don't do that here; this allows batching when removing multiple books.
|
|
});
|
|
}
|
|
reimportFile(vault, fileName) {
|
|
return __awaiter(this, void 0, void 0, function* () {
|
|
try {
|
|
this.notice("Deleting and reimporting file...", true);
|
|
yield vault.delete(vault.getAbstractFileByPath(fileName));
|
|
const bookId = this.settings.booksIDsMap[fileName];
|
|
yield this.addBookToRefresh(bookId);
|
|
// specifically re-sync this one file (not this.settings.booksToRefresh)
|
|
// because the user may have `settings.refreshBooks` disabled
|
|
yield this.syncBookHighlights([bookId]);
|
|
}
|
|
catch (e) {
|
|
console.log("Readwise Official plugin: fetch failed in Reimport current file: ", e);
|
|
}
|
|
});
|
|
}
|
|
createDirForFile(filePath) {
|
|
return __awaiter(this, void 0, void 0, function* () {
|
|
const dirPath = filePath.replace(/\/*$/, '').replace(/^(.+)\/[^\/]*?$/, '$1');
|
|
const exists = yield this.fs.exists(dirPath);
|
|
if (!exists) {
|
|
yield this.fs.mkdir(dirPath);
|
|
}
|
|
});
|
|
}
|
|
onload() {
|
|
return __awaiter(this, void 0, void 0, function* () {
|
|
yield this.loadSettings();
|
|
// @ts-expect-error - no type for isMobile
|
|
if (!this.app.isMobile) {
|
|
this.statusBar = new StatusBar(this.addStatusBarItem());
|
|
this.registerInterval(window.setInterval(() => this.statusBar.display(), 1000));
|
|
}
|
|
this.app.vault.on("rename", (file, oldPath) => __awaiter(this, void 0, void 0, function* () {
|
|
const bookId = this.settings.booksIDsMap[oldPath];
|
|
if (!bookId) {
|
|
return;
|
|
}
|
|
delete this.settings.booksIDsMap[oldPath];
|
|
this.settings.booksIDsMap[file.path] = bookId;
|
|
yield this.saveSettings();
|
|
}));
|
|
this.addCommand({
|
|
id: 'readwise-official-sync',
|
|
name: 'Sync your data now',
|
|
callback: () => {
|
|
this.syncBookHighlights();
|
|
}
|
|
});
|
|
this.addCommand({
|
|
id: 'readwise-official-format',
|
|
name: 'Customize formatting',
|
|
callback: () => window.open(`${baseURL}/export/obsidian/preferences`)
|
|
});
|
|
this.addCommand({
|
|
id: 'readwise-official-reimport-file',
|
|
name: 'Delete and reimport this document',
|
|
checkCallback: (checking) => {
|
|
var _a;
|
|
const activeFilePath = (_a = this.app.workspace.getActiveFile()) === null || _a === void 0 ? void 0 : _a.path;
|
|
const isRWfile = activeFilePath && activeFilePath in this.settings.booksIDsMap;
|
|
if (checking) {
|
|
return isRWfile;
|
|
}
|
|
if (this.settings.reimportShowConfirmation) {
|
|
const modal = new obsidian.Modal(this.app);
|
|
modal.titleEl.setText("Delete and reimport this document?");
|
|
modal.contentEl.createEl('p', {
|
|
text: 'Warning: Proceeding will delete this file entirely (including any changes you made) ' +
|
|
'and then reimport a new copy of your highlights from Readwise.',
|
|
cls: 'rw-modal-warning-text',
|
|
});
|
|
const buttonsContainer = modal.contentEl.createEl('div', { "cls": "rw-modal-btns" });
|
|
const cancelBtn = buttonsContainer.createEl("button", { "text": "Cancel" });
|
|
const confirmBtn = buttonsContainer.createEl("button", { "text": "Proceed", 'cls': 'mod-warning' });
|
|
const showConfContainer = modal.contentEl.createEl('div', { 'cls': 'rw-modal-confirmation' });
|
|
showConfContainer.createEl("label", { "attr": { "for": "rw-ask-nl" }, "text": "Don't ask me in the future" });
|
|
const showConf = showConfContainer.createEl("input", { "type": "checkbox", "attr": { "name": "rw-ask-nl", "id": "rw-ask-nl" } });
|
|
showConf.addEventListener('change', (ev) => __awaiter(this, void 0, void 0, function* () {
|
|
// @ts-expect-error - target.checked is not typed (TODO add type narrowing)
|
|
this.settings.reimportShowConfirmation = !ev.target.checked;
|
|
yield this.saveSettings();
|
|
}));
|
|
cancelBtn.onClickEvent(() => {
|
|
modal.close();
|
|
});
|
|
confirmBtn.onClickEvent(() => {
|
|
this.reimportFile(this.app.vault, activeFilePath);
|
|
modal.close();
|
|
});
|
|
modal.open();
|
|
}
|
|
else {
|
|
this.reimportFile(this.app.vault, activeFilePath);
|
|
}
|
|
}
|
|
});
|
|
this.registerMarkdownPostProcessor((el, ctx) => {
|
|
if (!ctx.sourcePath.startsWith(this.settings.readwiseDir)) {
|
|
return;
|
|
}
|
|
let matches;
|
|
try {
|
|
// @ts-ignore
|
|
matches = [...ctx.getSectionInfo(el).text.matchAll(/__(.+)__/g)].map((a) => a[1]);
|
|
}
|
|
catch (TypeError) {
|
|
// failed interaction with a Dataview element
|
|
return;
|
|
}
|
|
const hypers = el.findAll("strong").filter(e => matches.contains(e.textContent));
|
|
hypers.forEach(strongEl => {
|
|
const replacement = el.createEl('span');
|
|
while (strongEl.firstChild) {
|
|
replacement.appendChild(strongEl.firstChild);
|
|
}
|
|
replacement.addClass("rw-hyper-highlight");
|
|
strongEl.replaceWith(replacement);
|
|
});
|
|
});
|
|
this.addSettingTab(new ReadwiseSettingTab(this.app, this));
|
|
// ensure workspace is settled; this ensures cache is loaded
|
|
this.app.workspace.onLayoutReady(() => __awaiter(this, void 0, void 0, function* () {
|
|
if (this.settings.isSyncing && this.settings.currentSyncStatusID) {
|
|
yield this.getExportStatus(this.settings.currentSyncStatusID);
|
|
}
|
|
else {
|
|
// we probably got some unhandled error...
|
|
this.settings.isSyncing = false;
|
|
yield this.saveSettings();
|
|
}
|
|
if (this.settings.triggerOnLoad) {
|
|
yield this.syncBookHighlights(undefined, true);
|
|
}
|
|
yield this.configureSchedule();
|
|
this.app.vault.on("delete", (file) => __awaiter(this, void 0, void 0, function* () {
|
|
const bookId = this.settings.booksIDsMap[file.path];
|
|
if (bookId) {
|
|
// NOTE: because `on(delete)` also adds to `booksToRefresh`,
|
|
// the ID will be duplicated in `booksToRefresh`.
|
|
yield this.addBookToRefresh(bookId);
|
|
}
|
|
delete this.settings.booksIDsMap[file.path];
|
|
// BUG: `on("delete")` events have no sequantial guarantees.
|
|
// meaning: if a user deletes many files at once,
|
|
// there is no guarantee that the event will be handled
|
|
// in any specific order. this can lead to reality
|
|
// drifting as book ID is deleted/saved as all the delete
|
|
// events compete to remove the book ID from the map and save.
|
|
yield this.saveSettings();
|
|
}));
|
|
}));
|
|
});
|
|
}
|
|
onunload() {
|
|
// we're not doing anything here for now...
|
|
return;
|
|
}
|
|
loadSettings() {
|
|
return __awaiter(this, void 0, void 0, function* () {
|
|
this.settings = Object.assign({}, DEFAULT_SETTINGS, yield this.loadData());
|
|
});
|
|
}
|
|
saveSettings() {
|
|
return __awaiter(this, void 0, void 0, function* () {
|
|
yield this.saveData(this.settings);
|
|
});
|
|
}
|
|
getObsidianClientID() {
|
|
let obsidianClientId = window.localStorage.getItem('rw-ObsidianClientId');
|
|
if (obsidianClientId) {
|
|
return obsidianClientId;
|
|
}
|
|
else {
|
|
obsidianClientId = Math.random().toString(36).substring(2, 15);
|
|
window.localStorage.setItem('rw-ObsidianClientId', obsidianClientId);
|
|
return obsidianClientId;
|
|
}
|
|
}
|
|
getUserAuthToken(button, attempt = 0) {
|
|
return __awaiter(this, void 0, void 0, function* () {
|
|
let uuid = this.getObsidianClientID();
|
|
if (attempt === 0) {
|
|
window.open(`${baseURL}/api_auth?token=${uuid}&service=obsidian`);
|
|
}
|
|
let response, data;
|
|
try {
|
|
response = yield fetch(`${baseURL}/api/auth?token=${uuid}`);
|
|
}
|
|
catch (e) {
|
|
console.log("Readwise Official plugin: fetch failed in getUserAuthToken: ", e);
|
|
}
|
|
if (response && response.ok) {
|
|
data = yield response.json();
|
|
}
|
|
else {
|
|
console.log("Readwise Official plugin: bad response in getUserAuthToken: ", response);
|
|
this.showInfoStatus(button.parentElement, "Authorization failed. Try again", "rw-error");
|
|
return;
|
|
}
|
|
if (data.userAccessToken) {
|
|
console.log("Readwise Official plugin: successfully authenticated with Readwise");
|
|
this.settings.token = data.userAccessToken;
|
|
yield this.saveSettings();
|
|
}
|
|
else {
|
|
if (attempt > 20) {
|
|
console.log('Readwise Official plugin: reached attempt limit in getUserAuthToken');
|
|
return;
|
|
}
|
|
console.log(`Readwise Official plugin: didn't get token data, retrying (attempt ${attempt + 1})`);
|
|
yield new Promise(resolve => setTimeout(resolve, 1000));
|
|
yield this.getUserAuthToken(button, attempt + 1);
|
|
}
|
|
yield this.saveSettings();
|
|
return true;
|
|
});
|
|
}
|
|
encodeReadwiseBookId(rawBookId) {
|
|
if (rawBookId) {
|
|
return rawBookId.toString();
|
|
}
|
|
return undefined;
|
|
}
|
|
encodeReaderDocumentId(rawReaderDocumentId) {
|
|
if (rawReaderDocumentId) {
|
|
return `readerdocument:${rawReaderDocumentId}`;
|
|
}
|
|
return undefined;
|
|
}
|
|
decodeReaderDocumentId(readerDocumentId) {
|
|
if (!readerDocumentId || !readerDocumentId.startsWith("readerdocument:")) {
|
|
return undefined;
|
|
}
|
|
return readerDocumentId.replace(/^readerdocument:/, "");
|
|
}
|
|
}
|
|
class ReadwiseSettingTab extends obsidian.PluginSettingTab {
|
|
constructor(app, plugin) {
|
|
super(app, plugin);
|
|
this.plugin = plugin;
|
|
}
|
|
display() {
|
|
let { containerEl } = this;
|
|
containerEl.empty();
|
|
containerEl.createEl('h1', { text: 'Readwise Official' });
|
|
containerEl.createEl('p', { text: 'Created by ' }).createEl('a', { text: 'Readwise', href: 'https://readwise.io' });
|
|
containerEl.getElementsByTagName('p')[0].appendText(' 📚');
|
|
containerEl.createEl('h2', { text: 'Settings' });
|
|
if (this.plugin.settings.token) {
|
|
new obsidian.Setting(containerEl)
|
|
.setName("Sync your Readwise data with Obsidian")
|
|
.setDesc("On first sync, the Readwise plugin will create a new folder containing all your highlights")
|
|
.setClass('rw-setting-sync')
|
|
.addButton((button) => {
|
|
button.setCta().setTooltip("Once the sync begins, you can close this plugin page")
|
|
.setButtonText('Initiate Sync')
|
|
.onClick(() => __awaiter(this, void 0, void 0, function* () {
|
|
if (this.plugin.settings.isSyncing) {
|
|
// NOTE: This is used to prevent multiple syncs at the same time. However, if a previous sync fails,
|
|
// it can stop new syncs from happening. Make sure to set isSyncing to false
|
|
// if there's ever errors/failures in previous sync attempts, so that
|
|
// we don't block syncing subsequent times.
|
|
new obsidian.Notice("Readwise sync already in progress");
|
|
}
|
|
else {
|
|
this.plugin.clearInfoStatus(containerEl);
|
|
yield this.plugin.syncBookHighlights();
|
|
}
|
|
}));
|
|
});
|
|
let el = containerEl.createEl("div", { cls: "rw-info-container" });
|
|
containerEl.find(".rw-setting-sync > .setting-item-control ").prepend(el);
|
|
new obsidian.Setting(containerEl)
|
|
.setName("Customize formatting options")
|
|
.setDesc("You can customize which items export to Obsidian and how they appear from the Readwise website")
|
|
.addButton((button) => {
|
|
button.setButtonText("Customize").onClick(() => {
|
|
window.open(`${baseURL}/export/obsidian/preferences`);
|
|
});
|
|
});
|
|
new obsidian.Setting(containerEl)
|
|
.setName('Customize base folder')
|
|
.setDesc("By default, the plugin will save all your highlights into a folder named Readwise")
|
|
// TODO: change this to search filed when the API is exposed (https://github.com/obsidianmd/obsidian-api/issues/22)
|
|
.addText(text => text
|
|
.setPlaceholder('Defaults to: Readwise')
|
|
.setValue(this.plugin.settings.readwiseDir)
|
|
.onChange((value) => __awaiter(this, void 0, void 0, function* () {
|
|
this.plugin.settings.readwiseDir = obsidian.normalizePath(value || "Readwise");
|
|
yield this.plugin.saveSettings();
|
|
})));
|
|
new obsidian.Setting(containerEl)
|
|
.setName('Configure resync frequency')
|
|
.setDesc("If not set to Manual, Readwise will automatically resync with Obsidian when the app is open at the specified interval")
|
|
.addDropdown(dropdown => {
|
|
dropdown.addOption("0", "Manual");
|
|
dropdown.addOption("60", "Every 1 hour");
|
|
dropdown.addOption((12 * 60).toString(), "Every 12 hours");
|
|
dropdown.addOption((24 * 60).toString(), "Every 24 hours");
|
|
dropdown.addOption((7 * 24 * 60).toString(), "Every week");
|
|
// select the currently-saved option
|
|
dropdown.setValue(this.plugin.settings.frequency);
|
|
dropdown.onChange((newValue) => __awaiter(this, void 0, void 0, function* () {
|
|
// update the plugin settings
|
|
this.plugin.settings.frequency = newValue;
|
|
yield this.plugin.saveSettings();
|
|
// destroy & re-create the scheduled task
|
|
this.plugin.configureSchedule();
|
|
}));
|
|
});
|
|
new obsidian.Setting(containerEl)
|
|
.setName("Sync automatically when Obsidian opens")
|
|
.setDesc("If enabled, Readwise will automatically resync with Obsidian each time you open the app")
|
|
.addToggle((toggle) => {
|
|
toggle.setValue(this.plugin.settings.triggerOnLoad);
|
|
toggle.onChange((val) => __awaiter(this, void 0, void 0, function* () {
|
|
this.plugin.settings.triggerOnLoad = val;
|
|
yield this.plugin.saveSettings();
|
|
}));
|
|
});
|
|
new obsidian.Setting(containerEl)
|
|
.setName("Resync deleted files")
|
|
.setDesc("If enabled, you can refresh individual items by deleting the file in Obsidian and initiating a resync")
|
|
.addToggle((toggle) => {
|
|
toggle.setValue(this.plugin.settings.refreshBooks);
|
|
toggle.onChange((val) => __awaiter(this, void 0, void 0, function* () {
|
|
this.plugin.settings.refreshBooks = val;
|
|
yield this.plugin.saveSettings();
|
|
if (val) {
|
|
yield this.plugin.syncBookHighlights();
|
|
}
|
|
}));
|
|
});
|
|
if (this.plugin.settings.lastSyncFailed) {
|
|
this.plugin.showInfoStatus(containerEl.find(".rw-setting-sync .rw-info-container").parentElement, "Last sync failed", "rw-error");
|
|
}
|
|
}
|
|
else {
|
|
new obsidian.Setting(containerEl)
|
|
.setName("Connect Obsidian to Readwise")
|
|
.setClass("rw-setting-connect")
|
|
.setDesc("The Readwise plugin enables automatic syncing of all your highlights from Kindle, Instapaper, Pocket, and more. Note: Requires Readwise account.")
|
|
.addButton((button) => {
|
|
button.setButtonText("Connect").setCta().onClick((evt) => __awaiter(this, void 0, void 0, function* () {
|
|
const success = yield this.plugin.getUserAuthToken(evt.target);
|
|
if (success) {
|
|
// re-render the settings
|
|
this.display();
|
|
this.plugin.notice("Readwise connected", true);
|
|
}
|
|
}));
|
|
});
|
|
let el = containerEl.createEl("div", { cls: "rw-info-container" });
|
|
containerEl.find(".rw-setting-connect > .setting-item-control ").prepend(el);
|
|
}
|
|
const help = containerEl.createEl('p');
|
|
help.innerHTML = "Question? Please see our <a href='https://help.readwise.io/article/125-how-does-the-readwise-to-obsidian-export-integration-work'>Documentation</a> or email us at <a href='mailto:hello@readwise.io'>hello@readwise.io</a> 🙂";
|
|
}
|
|
}
|
|
|
|
module.exports = ReadwisePlugin;
|
|
|
|
/* nosourcemap */ |