@zip.js/zip.js 2.14.1 → 2.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/BENCHMARKS.md +21 -11
- package/deno.json +1 -1
- package/dist/zip-core-external.js +217 -98
- package/dist/zip-core-external.min.js +1 -1
- package/dist/zip-core.js +217 -98
- package/dist/zip-core.min.js +1 -1
- package/dist/zip-fs-core-external.js +217 -98
- package/dist/zip-fs-core-external.min.js +1 -1
- package/dist/zip-fs-core.js +217 -98
- package/dist/zip-fs-core.min.js +1 -1
- package/dist/zip-fs-external.js +217 -98
- package/dist/zip-fs-external.min.js +1 -1
- package/dist/zip-fs-native.js +219 -100
- package/dist/zip-fs-native.min.js +1 -1
- package/dist/zip-fs.js +219 -100
- package/dist/zip-fs.min.js +1 -1
- package/dist/zip-legacy.js +219 -100
- package/dist/zip-legacy.min.js +1 -1
- package/dist/zip-native.js +219 -100
- package/dist/zip-native.min.js +1 -1
- package/dist/zip-web-worker-native.js +1 -1
- package/dist/zip-web-worker.js +1 -1
- package/dist/zip.js +219 -100
- package/dist/zip.min.js +1 -1
- package/index-native.cjs +219 -100
- package/index-native.min.js +1 -1
- package/index.cjs +219 -100
- package/index.d.cts +46 -13
- package/index.d.ts +46 -13
- package/index.min.js +1 -1
- package/lib/core/codec-pool.js +35 -19
- package/lib/core/codec-worker.js +4 -2
- package/lib/core/io.js +3 -2
- package/lib/core/streams/zip-entry-stream.js +151 -66
- package/lib/core/util/decode-text.js +15 -1
- package/lib/core/version.js +1 -1
- package/lib/core/web-worker-inline-native.js +1 -1
- package/lib/core/web-worker-inline-wasm.js +1 -1
- package/lib/core/zip-reader.js +12 -10
- package/lib/core/zlib-streams-inline.js +1 -1
- package/package.json +1 -1
package/BENCHMARKS.md
CHANGED
|
@@ -39,8 +39,11 @@ The page answers four questions, each from one or two scripts of the harness:
|
|
|
39
39
|
about 2 KB each, and the 8 × 8 MB and 256 MB workloads are text.
|
|
40
40
|
- **Isolation.** In `bench.js` and `bench-backends.js`, each (library, operation, workload)
|
|
41
41
|
combination runs in its own freshly spawned Node process under macOS's `/usr/bin/time -l`, so
|
|
42
|
-
the libraries never share a heap and peak memory is per library.
|
|
43
|
-
|
|
42
|
+
the libraries never share a heap and peak memory is per library. Every row of those two
|
|
43
|
+
scripts includes what a fresh process pays on its first operation: the JIT warm-up of each
|
|
44
|
+
library and, for the zip.js WebAssembly rows, the module instantiation, about 20 ms. The
|
|
45
|
+
codec, encryption and runtime scripts run in-process, with one warmup run before the timed
|
|
46
|
+
ones.
|
|
44
47
|
- **Timing.** `performance.now()` around the measured operation. Each combination runs 3 times
|
|
45
48
|
(5 in the encryption script) and the tables report the median. Differences of a few percent
|
|
46
49
|
are within run-to-run noise. A bold cell is the best number among the alternatives it is
|
|
@@ -59,6 +62,11 @@ The page answers four questions, each from one or two scripts of the harness:
|
|
|
59
62
|
where they exist; the bundled WebAssembly zlib; and the pure-JavaScript zlib port. The last two
|
|
60
63
|
ship with the library, like the codecs of jszip and fflate, so those rows compare the
|
|
61
64
|
libraries without the host's zlib in the picture.
|
|
65
|
+
- **Checks.** No decompression row verifies the CRC-32 of the entries: zip.js and jszip leave
|
|
66
|
+
the check off by default, and fflate has none on read. Turning it on in zip.js makes the
|
|
67
|
+
inflater verify the CRC-32 through a gzip trailer: about 7 ms per 20 MB on the WebAssembly
|
|
68
|
+
codec, within the noise on Node's `DecompressionStream`; the pure-JavaScript port keeps a
|
|
69
|
+
separate pass over the output, about 15 ms.
|
|
62
70
|
- **Units.** MB in the tables is 10^6 bytes. The workload sizes (20 MB, 8 MB, 256 MB) and the
|
|
63
71
|
MB/s throughputs use 2^20 bytes.
|
|
64
72
|
|
|
@@ -126,15 +134,17 @@ Peak memory for the same runs (Δ over baseline):
|
|
|
126
134
|
| fflate | fflate (JavaScript) | **92 MB** | **120 MB** |
|
|
127
135
|
|
|
128
136
|
On the 20 MB stream `DecompressionStream` takes 66 ms and the WebAssembly inflate 78 ms, then
|
|
129
|
-
fflate 116 ms, jszip 137 ms and the pure-JavaScript port 180 ms.
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
137
|
+
fflate 116 ms, jszip 137 ms and the pure-JavaScript port 180 ms. The WebAssembly row includes
|
|
138
|
+
the module instantiation a fresh process pays once, about 20 ms. Warm, the two inflates are
|
|
139
|
+
within 6 % of each other in the [Codecs](#codecs-at-equal-output-size) table. On 5,000 small
|
|
140
|
+
files the order reverses: fflate takes 102 ms, jszip 444 ms and the three zip.js rows 476 to
|
|
141
|
+
628 ms, with `DecompressionStream` the slowest of them, the same per-entry cost as in
|
|
142
|
+
compression. fflate uses the least memory on both workloads, 34 % of the `DecompressionStream`
|
|
143
|
+
row on the small files, and the WebAssembly and pure-JavaScript rows peak higher than
|
|
144
|
+
`DecompressionStream`. The three zip.js rows allocate the same 800 MB of stream objects over the
|
|
145
|
+
5,000 entries, about 160 KB per entry. The WebAssembly and pure-JavaScript codecs run on the
|
|
146
|
+
JavaScript thread, so V8's incremental marking keeps more of that garbage alive between
|
|
147
|
+
collections, and that is the difference between the rows.
|
|
138
148
|
|
|
139
149
|
### Streaming a 256 MB file, disk to disk
|
|
140
150
|
|
package/deno.json
CHANGED
|
@@ -1889,7 +1889,6 @@ const FORMAT_GZIP$1 = "gzip";
|
|
|
1889
1889
|
const GZIP_HEADER_LENGTH = 10;
|
|
1890
1890
|
const GZIP_TRAILER_LENGTH = 8;
|
|
1891
1891
|
const GZIP_HEADER_BYTES = [0x1f, 0x8b, 0x08];
|
|
1892
|
-
const GZIP_OUTPUT_STALL_TIMEOUT = 5000;
|
|
1893
1892
|
|
|
1894
1893
|
class DeflateStream extends TransformStream {
|
|
1895
1894
|
|
|
@@ -1900,8 +1899,8 @@ class DeflateStream extends TransformStream {
|
|
|
1900
1899
|
let crc32Stream, encryptionStream, gzipCrc32Stream;
|
|
1901
1900
|
let readable = super.readable;
|
|
1902
1901
|
const codecStreams = format && getCodecStreams(format);
|
|
1903
|
-
const
|
|
1904
|
-
|
|
1902
|
+
const GzipCompressionStream = getGzipCodecStream(useCompressionStream, CompressionStream, CompressionStreamFallback);
|
|
1903
|
+
const useGzipCrc32 = computeCrc32 && compressed && !deflate64 && !codecStreams && (!encrypted || zipCrypto) && Boolean(GzipCompressionStream);
|
|
1905
1904
|
if ((!encrypted || zipCrypto) && computeCrc32 && !useGzipCrc32) {
|
|
1906
1905
|
crc32Stream = new Crc32Stream();
|
|
1907
1906
|
readable = pipeThrough(readable, crc32Stream);
|
|
@@ -1911,12 +1910,15 @@ class DeflateStream extends TransformStream {
|
|
|
1911
1910
|
readable = pipeThroughBackpressured(readable, createCodecStream(codecStreams.CompressionStream, format, { level, chunkSize, compressionMethod, uncompressedSize: inputSize }));
|
|
1912
1911
|
} else if (useGzipCrc32) {
|
|
1913
1912
|
gzipCrc32Stream = new GzipToRawDeflateStream();
|
|
1914
|
-
readable = pipeThroughBackpressured(readable, new
|
|
1913
|
+
readable = pipeThroughBackpressured(readable, new GzipCompressionStream(FORMAT_GZIP$1, { level, chunkSize }));
|
|
1915
1914
|
readable = pipeThrough(readable, gzipCrc32Stream);
|
|
1916
1915
|
} else {
|
|
1917
1916
|
try {
|
|
1918
1917
|
readable = pipeThroughCompressionStream(readable, useCompressionStream, { level, chunkSize }, CompressionStream, CompressionStreamFallback);
|
|
1919
1918
|
} catch (error) {
|
|
1919
|
+
if (!useCompressionStream && CompressionStreamFallback) {
|
|
1920
|
+
throw error;
|
|
1921
|
+
}
|
|
1920
1922
|
let gzipStream;
|
|
1921
1923
|
try {
|
|
1922
1924
|
gzipStream = new CompressionStream(FORMAT_GZIP$1);
|
|
@@ -1985,82 +1987,144 @@ class GzipToRawDeflateStream extends TransformStream {
|
|
|
1985
1987
|
}
|
|
1986
1988
|
}
|
|
1987
1989
|
|
|
1988
|
-
function pipeThroughGzipDecompressionStream(readable, gzipStream, outputSize) {
|
|
1989
|
-
const
|
|
1990
|
+
function pipeThroughGzipDecompressionStream(readable, gzipStream, outputSize, crc32) {
|
|
1991
|
+
const writer = gzipStream.writable.getWriter();
|
|
1992
|
+
const reader = gzipStream.readable.getReader();
|
|
1993
|
+
const outputCrc32 = crc32 === UNDEFINED_VALUE ? new Crc32() : UNDEFINED_VALUE;
|
|
1990
1994
|
let outputLength = 0;
|
|
1991
1995
|
let inputDone = false;
|
|
1992
|
-
let
|
|
1996
|
+
let trailerWritten = false;
|
|
1997
|
+
let idleCheckArmed = false;
|
|
1998
|
+
let readCount = 0;
|
|
1999
|
+
let readPending = false;
|
|
1993
2000
|
let resolveTrailerReady, rejectTrailerReady;
|
|
1994
2001
|
const trailerReady = new Promise((resolve, reject) => {
|
|
1995
2002
|
resolveTrailerReady = resolve;
|
|
1996
2003
|
rejectTrailerReady = reject;
|
|
1997
2004
|
});
|
|
1998
2005
|
trailerReady.catch(() => { });
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2006
|
+
pump();
|
|
2007
|
+
return new ReadableStream({
|
|
2008
|
+
async pull(controller) {
|
|
2009
|
+
let result;
|
|
2010
|
+
try {
|
|
2011
|
+
result = await read();
|
|
2012
|
+
} catch (error) {
|
|
2013
|
+
throw trailerWritten ? getTrailerError(error) : error;
|
|
2014
|
+
}
|
|
2015
|
+
const { value, done } = result;
|
|
2016
|
+
if (done) {
|
|
2017
|
+
controller.close();
|
|
2018
|
+
} else {
|
|
2019
|
+
outputLength += value.length;
|
|
2020
|
+
if (outputLength > outputSize) {
|
|
2021
|
+
const error = new Error(ERR_INVALID_UNCOMPRESSED_SIZE);
|
|
2022
|
+
rejectTrailerReady(error);
|
|
2023
|
+
await cancel(reader, error);
|
|
2024
|
+
throw error;
|
|
2025
|
+
}
|
|
2026
|
+
if (outputCrc32) {
|
|
2027
|
+
outputCrc32.append(value);
|
|
2028
|
+
}
|
|
2029
|
+
controller.enqueue(value);
|
|
2030
|
+
}
|
|
2031
|
+
},
|
|
2032
|
+
cancel(reason) {
|
|
2033
|
+
rejectTrailerReady(reason);
|
|
2034
|
+
return reader.cancel(reason);
|
|
2035
|
+
}
|
|
2036
|
+
});
|
|
2037
|
+
|
|
2038
|
+
async function pump() {
|
|
2039
|
+
const inputReader = readable.getReader();
|
|
2040
|
+
try {
|
|
2004
2041
|
const header = new Uint8Array(GZIP_HEADER_LENGTH);
|
|
2005
2042
|
header.set(GZIP_HEADER_BYTES);
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2043
|
+
await writer.write(header);
|
|
2044
|
+
for (; ;) {
|
|
2045
|
+
await writer.ready;
|
|
2046
|
+
const { value, done } = await inputReader.read();
|
|
2047
|
+
if (done) {
|
|
2048
|
+
break;
|
|
2049
|
+
}
|
|
2050
|
+
await writer.write(value);
|
|
2051
|
+
}
|
|
2012
2052
|
inputDone = true;
|
|
2013
|
-
|
|
2014
|
-
|
|
2053
|
+
if (outputCrc32) {
|
|
2054
|
+
if (readPending) {
|
|
2055
|
+
armIdleCheck();
|
|
2056
|
+
}
|
|
2015
2057
|
await trailerReady;
|
|
2016
|
-
} finally {
|
|
2017
|
-
stopWatchdog();
|
|
2018
2058
|
}
|
|
2019
2059
|
const trailer = new Uint8Array(GZIP_TRAILER_LENGTH);
|
|
2020
2060
|
const dataView = getDataView(trailer);
|
|
2021
|
-
dataView.setUint32(0,
|
|
2061
|
+
dataView.setUint32(0, outputCrc32 ? outputCrc32.get() : crc32, true);
|
|
2022
2062
|
dataView.setUint32(4, outputSize, true);
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2063
|
+
trailerWritten = true;
|
|
2064
|
+
await writer.write(trailer);
|
|
2065
|
+
await writer.close();
|
|
2066
|
+
} catch (error) {
|
|
2067
|
+
await abort(writer, error);
|
|
2068
|
+
await cancel(inputReader, error);
|
|
2027
2069
|
}
|
|
2028
|
-
}
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
}
|
|
2038
|
-
controller.enqueue(chunk);
|
|
2039
|
-
},
|
|
2040
|
-
cancel(reason) {
|
|
2041
|
-
rejectTrailerReady(reason);
|
|
2070
|
+
}
|
|
2071
|
+
|
|
2072
|
+
function read() {
|
|
2073
|
+
readCount++;
|
|
2074
|
+
readPending = true;
|
|
2075
|
+
const result = reader.read();
|
|
2076
|
+
result.then(onReadSettled, onReadSettled);
|
|
2077
|
+
if (inputDone && outputCrc32) {
|
|
2078
|
+
armIdleCheck();
|
|
2042
2079
|
}
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
readable = pipeThroughBackpressured(readable, gzipStream);
|
|
2046
|
-
return pipeThrough(readable, outputStream);
|
|
2080
|
+
return result;
|
|
2081
|
+
}
|
|
2047
2082
|
|
|
2048
|
-
function
|
|
2049
|
-
|
|
2050
|
-
watchdogTimeout = setTimeout(() => rejectTrailerReady(new Error(ERR_INVALID_UNCOMPRESSED_SIZE)), GZIP_OUTPUT_STALL_TIMEOUT);
|
|
2083
|
+
function onReadSettled() {
|
|
2084
|
+
readPending = false;
|
|
2051
2085
|
}
|
|
2052
2086
|
|
|
2053
|
-
function
|
|
2054
|
-
|
|
2087
|
+
async function armIdleCheck() {
|
|
2088
|
+
if (!idleCheckArmed) {
|
|
2089
|
+
idleCheckArmed = true;
|
|
2090
|
+
const count = readCount;
|
|
2091
|
+
await nextTask();
|
|
2092
|
+
idleCheckArmed = false;
|
|
2093
|
+
if (readPending) {
|
|
2094
|
+
if (readCount == count) {
|
|
2095
|
+
resolveTrailerReady();
|
|
2096
|
+
} else {
|
|
2097
|
+
armIdleCheck();
|
|
2098
|
+
}
|
|
2099
|
+
}
|
|
2100
|
+
}
|
|
2101
|
+
}
|
|
2102
|
+
|
|
2103
|
+
function getTrailerError(error) {
|
|
2104
|
+
const trailerError = new Error(outputLength == outputSize ? ERR_INVALID_CRC32 : ERR_INVALID_UNCOMPRESSED_SIZE);
|
|
2105
|
+
trailerError.cause = error;
|
|
2106
|
+
return trailerError;
|
|
2055
2107
|
}
|
|
2056
2108
|
}
|
|
2057
2109
|
|
|
2110
|
+
function nextTask() {
|
|
2111
|
+
return new Promise(resolve => {
|
|
2112
|
+
const { port1, port2 } = new MessageChannel();
|
|
2113
|
+
port2.onmessage = () => {
|
|
2114
|
+
port1.close();
|
|
2115
|
+
port2.close();
|
|
2116
|
+
resolve();
|
|
2117
|
+
};
|
|
2118
|
+
port1.postMessage(UNDEFINED_VALUE);
|
|
2119
|
+
});
|
|
2120
|
+
}
|
|
2121
|
+
|
|
2058
2122
|
class InflateStream extends TransformStream {
|
|
2059
2123
|
|
|
2060
2124
|
constructor(options, { chunkSize, DecompressionStreamFallback, DecompressionStream }) {
|
|
2061
2125
|
super({});
|
|
2062
2126
|
const { zipCrypto, encrypted, checkCrc32, crc32, compressed, useCompressionStream, deflate64, format, compressionMethod, rawBitFlag, outputSize } = options;
|
|
2063
|
-
let crc32Stream, decryptionStream;
|
|
2127
|
+
let crc32Stream, decryptionStream, gzipCrc32;
|
|
2064
2128
|
let readable = super.readable;
|
|
2065
2129
|
if (encrypted) {
|
|
2066
2130
|
if (zipCrypto) {
|
|
@@ -2075,31 +2139,44 @@ class InflateStream extends TransformStream {
|
|
|
2075
2139
|
if (codecStreams) {
|
|
2076
2140
|
readable = pipeThroughBackpressured(readable, createCodecStream(codecStreams.DecompressionStream, format, { chunkSize, compressionMethod, rawBitFlag, uncompressedSize: outputSize }));
|
|
2077
2141
|
} else {
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
if (deflate64 || outputSize === UNDEFINED_VALUE) {
|
|
2082
|
-
throw error;
|
|
2083
|
-
}
|
|
2084
|
-
let gzipStream;
|
|
2142
|
+
let gzipStream;
|
|
2143
|
+
const GzipDecompressionStream = getGzipCodecStream(useCompressionStream, DecompressionStream, DecompressionStreamFallback);
|
|
2144
|
+
if (checkCrc32 && !deflate64 && crc32 !== UNDEFINED_VALUE && outputSize !== UNDEFINED_VALUE && GzipDecompressionStream) {
|
|
2085
2145
|
try {
|
|
2086
|
-
gzipStream = new
|
|
2146
|
+
gzipStream = new GzipDecompressionStream(FORMAT_GZIP$1, { chunkSize });
|
|
2087
2147
|
} catch {
|
|
2088
|
-
|
|
2148
|
+
gzipStream = UNDEFINED_VALUE;
|
|
2149
|
+
}
|
|
2150
|
+
}
|
|
2151
|
+
if (!gzipStream) {
|
|
2152
|
+
try {
|
|
2153
|
+
readable = pipeThroughCompressionStream(readable, useCompressionStream, { chunkSize, deflate64 }, DecompressionStream, DecompressionStreamFallback);
|
|
2154
|
+
} catch (error) {
|
|
2155
|
+
if (deflate64 || outputSize === UNDEFINED_VALUE || (!useCompressionStream && DecompressionStreamFallback)) {
|
|
2156
|
+
throw error;
|
|
2157
|
+
}
|
|
2158
|
+
try {
|
|
2159
|
+
gzipStream = new DecompressionStream(FORMAT_GZIP$1);
|
|
2160
|
+
} catch {
|
|
2161
|
+
throw error;
|
|
2162
|
+
}
|
|
2089
2163
|
}
|
|
2090
|
-
|
|
2164
|
+
}
|
|
2165
|
+
if (gzipStream) {
|
|
2166
|
+
gzipCrc32 = true;
|
|
2167
|
+
readable = pipeThroughGzipDecompressionStream(readable, gzipStream, outputSize, crc32);
|
|
2091
2168
|
}
|
|
2092
2169
|
}
|
|
2093
2170
|
readable = mapInflateStreamError(readable);
|
|
2094
2171
|
}
|
|
2095
|
-
if (checkCrc32) {
|
|
2172
|
+
if (checkCrc32 && !gzipCrc32) {
|
|
2096
2173
|
crc32Stream = new Crc32Stream();
|
|
2097
2174
|
readable = pipeThrough(readable, crc32Stream);
|
|
2098
2175
|
}
|
|
2099
2176
|
setReadable(this, readable, () => {
|
|
2100
|
-
if (
|
|
2101
|
-
const
|
|
2102
|
-
if (crc32 !=
|
|
2177
|
+
if (crc32Stream) {
|
|
2178
|
+
const computedCrc32 = new DataView(crc32Stream.value.buffer).getUint32(0, false);
|
|
2179
|
+
if (crc32 != computedCrc32) {
|
|
2103
2180
|
throw new Error(ERR_INVALID_CRC32);
|
|
2104
2181
|
}
|
|
2105
2182
|
}
|
|
@@ -2155,6 +2232,14 @@ function createCodecStream(CodecStreamClass, format, options) {
|
|
|
2155
2232
|
return new CodecStreamClass(format, options);
|
|
2156
2233
|
}
|
|
2157
2234
|
|
|
2235
|
+
function getGzipCodecStream(useCompressionStream, CodecStreamNative, CodecStreamFallback) {
|
|
2236
|
+
if (useCompressionStream && CodecStreamNative) {
|
|
2237
|
+
return CodecStreamNative;
|
|
2238
|
+
} else if (CodecStreamFallback && CodecStreamFallback.requiresModule) {
|
|
2239
|
+
return CodecStreamFallback;
|
|
2240
|
+
}
|
|
2241
|
+
}
|
|
2242
|
+
|
|
2158
2243
|
function pipeThroughCompressionStream(readable, useCompressionStream, options, CompressionStreamNative, CompressionStreamFallback) {
|
|
2159
2244
|
const Stream = useCompressionStream && CompressionStreamNative ?
|
|
2160
2245
|
CompressionStreamNative :
|
|
@@ -2527,10 +2612,12 @@ class CodecWorker {
|
|
|
2527
2612
|
workerData.terminated = true;
|
|
2528
2613
|
worker.terminate();
|
|
2529
2614
|
}
|
|
2530
|
-
terminateResolvers.forEach(resolve => resolve());
|
|
2531
2615
|
}
|
|
2532
2616
|
workerData.busy = false;
|
|
2533
|
-
onTaskFinished(workerData);
|
|
2617
|
+
const pendingTasks = onTaskFinished(workerData);
|
|
2618
|
+
if (terminateResolvers) {
|
|
2619
|
+
terminateResolvers.forEach(resolve => resolve(pendingTasks));
|
|
2620
|
+
}
|
|
2534
2621
|
}
|
|
2535
2622
|
}
|
|
2536
2623
|
});
|
|
@@ -3215,7 +3302,10 @@ async function runWorker(stream, workerOptions) {
|
|
|
3215
3302
|
|
|
3216
3303
|
function onTaskFinished(workerData) {
|
|
3217
3304
|
clearStarvationTimeout();
|
|
3218
|
-
if (
|
|
3305
|
+
if (workerData.terminated) {
|
|
3306
|
+
workerData.terminated = false;
|
|
3307
|
+
return runPendingRequestsInline();
|
|
3308
|
+
} else if (pendingRequests.length) {
|
|
3219
3309
|
const [{ resolve, stream, workerOptions }] = pendingRequests.splice(0, 1);
|
|
3220
3310
|
resolve(new CodecWorker(workerData, stream, workerOptions, onTaskFinished));
|
|
3221
3311
|
armStarvationTimeout();
|
|
@@ -3253,12 +3343,26 @@ function onWorkerStarvation() {
|
|
|
3253
3343
|
starvationTimeout = null;
|
|
3254
3344
|
if (pendingRequests.length) {
|
|
3255
3345
|
const [{ resolve, stream, workerOptions }] = pendingRequests.splice(0, 1);
|
|
3256
|
-
|
|
3257
|
-
resolve(new CodecWorker({}, stream, inlineWorkerOptions, onInlineTaskFinished));
|
|
3346
|
+
resolve(new CodecWorker({}, stream, getInlineWorkerOptions(workerOptions), onInlineTaskFinished));
|
|
3258
3347
|
armStarvationTimeout();
|
|
3259
3348
|
}
|
|
3260
3349
|
}
|
|
3261
3350
|
|
|
3351
|
+
function runPendingRequestsInline() {
|
|
3352
|
+
const tasks = pendingRequests.splice(0).map(({ resolve, stream, workerOptions }) => new Promise(resolveTask => {
|
|
3353
|
+
resolve(new CodecWorker({}, stream, getInlineWorkerOptions(workerOptions), () => {
|
|
3354
|
+
onInlineTaskFinished();
|
|
3355
|
+
resolveTask();
|
|
3356
|
+
}));
|
|
3357
|
+
}));
|
|
3358
|
+
clearStarvationTimeout();
|
|
3359
|
+
return Promise.all(tasks);
|
|
3360
|
+
}
|
|
3361
|
+
|
|
3362
|
+
function getInlineWorkerOptions(workerOptions) {
|
|
3363
|
+
return Object.assign({}, workerOptions, { useWebWorkers: false, workerURI: UNDEFINED_VALUE, createWorker: UNDEFINED_VALUE });
|
|
3364
|
+
}
|
|
3365
|
+
|
|
3262
3366
|
function onInlineTaskFinished() {
|
|
3263
3367
|
clearStarvationTimeout();
|
|
3264
3368
|
armStarvationTimeout();
|
|
@@ -3268,18 +3372,14 @@ function terminateWorker(workerData, workerOptions) {
|
|
|
3268
3372
|
const { config } = workerOptions;
|
|
3269
3373
|
const { terminateWorkerTimeout } = config;
|
|
3270
3374
|
if (Number.isFinite(terminateWorkerTimeout) && terminateWorkerTimeout >= 0) {
|
|
3271
|
-
|
|
3272
|
-
|
|
3273
|
-
|
|
3274
|
-
|
|
3275
|
-
|
|
3276
|
-
|
|
3277
|
-
|
|
3278
|
-
|
|
3279
|
-
// ignored
|
|
3280
|
-
}
|
|
3281
|
-
}, terminateWorkerTimeout);
|
|
3282
|
-
}
|
|
3375
|
+
workerData.terminateTimeout = setTimeout(async () => {
|
|
3376
|
+
pool = pool.filter(data => data != workerData);
|
|
3377
|
+
try {
|
|
3378
|
+
await workerData.terminate();
|
|
3379
|
+
} catch {
|
|
3380
|
+
// ignored
|
|
3381
|
+
}
|
|
3382
|
+
}, terminateWorkerTimeout);
|
|
3283
3383
|
}
|
|
3284
3384
|
}
|
|
3285
3385
|
|
|
@@ -3292,10 +3392,13 @@ function clearTerminateTimeout(workerData) {
|
|
|
3292
3392
|
}
|
|
3293
3393
|
|
|
3294
3394
|
async function terminateWorkers() {
|
|
3295
|
-
await Promise.allSettled(
|
|
3296
|
-
|
|
3297
|
-
|
|
3298
|
-
|
|
3395
|
+
await Promise.allSettled([
|
|
3396
|
+
runPendingRequestsInline(),
|
|
3397
|
+
...pool.map(workerData => {
|
|
3398
|
+
clearTerminateTimeout(workerData);
|
|
3399
|
+
return workerData.terminate();
|
|
3400
|
+
})
|
|
3401
|
+
]);
|
|
3299
3402
|
resetWebWorkerSupport();
|
|
3300
3403
|
}
|
|
3301
3404
|
|
|
@@ -3370,6 +3473,19 @@ function decodeText(value, encoding) {
|
|
|
3370
3473
|
return decode(value, encoding, true);
|
|
3371
3474
|
}
|
|
3372
3475
|
|
|
3476
|
+
function isUTF8Text(value) {
|
|
3477
|
+
if (value.some(byte => byte > 0x7f)) {
|
|
3478
|
+
try {
|
|
3479
|
+
new TextDecoder("utf-8", { fatal: true }).decode(value);
|
|
3480
|
+
return true;
|
|
3481
|
+
} catch {
|
|
3482
|
+
return false;
|
|
3483
|
+
}
|
|
3484
|
+
} else {
|
|
3485
|
+
return false;
|
|
3486
|
+
}
|
|
3487
|
+
}
|
|
3488
|
+
|
|
3373
3489
|
function decodeTextRemovingBOM(value, encoding) {
|
|
3374
3490
|
return decode(value, encoding, false);
|
|
3375
3491
|
}
|
|
@@ -3702,10 +3818,11 @@ class FetchReader extends Reader {
|
|
|
3702
3818
|
|
|
3703
3819
|
createReadable(options) {
|
|
3704
3820
|
const reader = this;
|
|
3705
|
-
const { useRangeHeader, forceRangeRequests, size } = reader;
|
|
3821
|
+
const { useRangeHeader, forceRangeRequests, size, eocdCache } = reader;
|
|
3706
3822
|
if ((useRangeHeader || forceRangeRequests) && size !== UNDEFINED_VALUE) {
|
|
3707
3823
|
const { offset = 0, size: readSize = size - offset } = options || {};
|
|
3708
|
-
|
|
3824
|
+
const cached = eocdCache && offset >= size - eocdCache.length;
|
|
3825
|
+
if (readSize > 0 && offset < size && !cached) {
|
|
3709
3826
|
return createRangeReadable(reader, offset, Math.min(readSize, size - offset));
|
|
3710
3827
|
}
|
|
3711
3828
|
}
|
|
@@ -4659,6 +4776,7 @@ const WARNING_MISMATCHED_LOCAL_FILE_HEADER_COMPRESSION_METHOD = "mismatched loca
|
|
|
4659
4776
|
const WARNING_MISMATCHED_LOCAL_FILE_HEADER_CRC32_OR_SIZES = "mismatched local file header (crc32 or sizes)";
|
|
4660
4777
|
const MAX_KNOWN_VERSION = 63;
|
|
4661
4778
|
const DRIVE_LETTER_REGEXP = /^[a-zA-Z]:/;
|
|
4779
|
+
const PARENT_DIRECTORY_REGEXP = /(^|[\\/])\.\.([\\/]|$)/;
|
|
4662
4780
|
const CHARSET_UTF8 = "utf-8";
|
|
4663
4781
|
const PROPERTY_NAME_UTF8_SUFFIX = "UTF8";
|
|
4664
4782
|
const CHARSET_CP437 = "cp437";
|
|
@@ -4911,12 +5029,13 @@ class ZipReader {
|
|
|
4911
5029
|
const versionMadeBy = getUint16$1(directoryView, offset + 4);
|
|
4912
5030
|
const msDosCompatible = versionMadeBy >> 8 == 0;
|
|
4913
5031
|
const unixCompatible = versionMadeBy >> 8 == 3;
|
|
4914
|
-
const rawFilename = directoryArray.subarray(filenameOffset, extraFieldOffset);
|
|
4915
5032
|
const commentLength = getUint16$1(directoryView, offset + 32);
|
|
4916
5033
|
const endOffset = commentOffset + commentLength;
|
|
4917
|
-
const
|
|
4918
|
-
const
|
|
4919
|
-
const
|
|
5034
|
+
const rawEntryData = new Uint8Array(directoryArray.subarray(filenameOffset, endOffset));
|
|
5035
|
+
const rawFilename = rawEntryData.subarray(0, fileEntry.filenameLength);
|
|
5036
|
+
const rawComment = rawEntryData.subarray(fileEntry.filenameLength + fileEntry.extraFieldLength);
|
|
5037
|
+
const filenameUTF8 = languageEncodingFlag || (!filenameEncoding && isUTF8Text(rawFilename));
|
|
5038
|
+
const commentUTF8 = languageEncodingFlag || (!commentEncoding && isUTF8Text(rawComment));
|
|
4920
5039
|
const externalFileAttributes = getUint32$1(directoryView, offset + 38);
|
|
4921
5040
|
const msdosAttributesRaw = externalFileAttributes & MAX_8_BITS;
|
|
4922
5041
|
const msdosAttributes = {
|
|
@@ -4967,7 +5086,7 @@ class ZipReader {
|
|
|
4967
5086
|
rawFilename,
|
|
4968
5087
|
filenameUTF8,
|
|
4969
5088
|
commentUTF8,
|
|
4970
|
-
rawExtraField:
|
|
5089
|
+
rawExtraField: rawEntryData.subarray(fileEntry.filenameLength, fileEntry.filenameLength + fileEntry.extraFieldLength),
|
|
4971
5090
|
rawComment,
|
|
4972
5091
|
filename,
|
|
4973
5092
|
comment
|
|
@@ -5475,7 +5594,7 @@ function readDigitalSignature(signatureRecordArray) {
|
|
|
5475
5594
|
if (getUint32$1(signatureRecordView, 0) == DIGITAL_SIGNATURE_RECORD_SIGNATURE) {
|
|
5476
5595
|
const signatureDataLength = getUint16$1(signatureRecordView, 4);
|
|
5477
5596
|
if (6 + signatureDataLength <= signatureRecordArray.length) {
|
|
5478
|
-
return signatureRecordArray.subarray(6, 6 + signatureDataLength);
|
|
5597
|
+
return new Uint8Array(signatureRecordArray.subarray(6, 6 + signatureDataLength));
|
|
5479
5598
|
}
|
|
5480
5599
|
}
|
|
5481
5600
|
}
|
|
@@ -5998,10 +6117,10 @@ function isUnsafeFilename(filename, filenameValidation) {
|
|
|
5998
6117
|
if (pathParts.length > 1 && pathParts[pathParts.length - 1] === "") {
|
|
5999
6118
|
pathParts.pop();
|
|
6000
6119
|
}
|
|
6001
|
-
if (
|
|
6120
|
+
if (PARENT_DIRECTORY_REGEXP.test(filename) || filename.startsWith("/") || filename.startsWith("\\") || DRIVE_LETTER_REGEXP.test(filename)) {
|
|
6002
6121
|
return true;
|
|
6003
6122
|
}
|
|
6004
|
-
return filenameValidation == STRICTNESS_STRICT && (pathParts.includes(".") || pathParts.includes(""));
|
|
6123
|
+
return filenameValidation == STRICTNESS_STRICT && (pathParts.includes(".") || pathParts.includes("") || filename.includes("\0"));
|
|
6005
6124
|
}
|
|
6006
6125
|
|
|
6007
6126
|
function getMaxAppendedDataSize(maxAppendedDataSize, strictness) {
|
|
@@ -6087,7 +6206,7 @@ async function* scanEndOfCentralDirectory(reader, scanLength) {
|
|
|
6087
6206
|
}
|
|
6088
6207
|
|
|
6089
6208
|
function getEndOfCentralDirectoryInfo(scanArray, indexByte, offset) {
|
|
6090
|
-
return { offset, buffer: scanArray.
|
|
6209
|
+
return { offset, buffer: new Uint8Array(scanArray.subarray(indexByte, indexByte + END_OF_CENTRAL_DIR_LENGTH)).buffer };
|
|
6091
6210
|
}
|
|
6092
6211
|
|
|
6093
6212
|
async function getCentralDirectoryReachability(reader, view, anchoredOffset, indexByte, offset, size, remoteProbeBudget) {
|
|
@@ -8734,7 +8853,7 @@ function formatSupported(StreamClass, format) {
|
|
|
8734
8853
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
8735
8854
|
*/
|
|
8736
8855
|
|
|
8737
|
-
const VERSION = "2.
|
|
8856
|
+
const VERSION = "2.16.0";
|
|
8738
8857
|
|
|
8739
8858
|
/*
|
|
8740
8859
|
Copyright (c) 2025 Gildas Lormeau. All rights reserved.
|