@zip.js/zip.js 2.8.36 → 2.8.38
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/deno.json +4 -2
- package/dist/zip-core.js +356 -63
- package/dist/zip-core.min.js +1 -1
- package/dist/zip-fs-core.js +301 -63
- package/dist/zip-fs-core.min.js +1 -1
- package/dist/zip-fs-native.js +359 -66
- package/dist/zip-fs-native.min.js +1 -1
- package/dist/zip-fs.js +357 -64
- package/dist/zip-fs.min.js +1 -1
- package/dist/zip-legacy.js +358 -65
- package/dist/zip-legacy.min.js +1 -1
- package/dist/zip-native.js +359 -66
- 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 +357 -64
- package/dist/zip.min.js +1 -1
- package/index-native.cjs +359 -66
- package/index-native.min.js +1 -1
- package/index.cjs +357 -64
- package/index.d.cts +126 -4
- package/index.d.ts +126 -4
- package/index.min.js +1 -1
- package/lib/core/codec-pool.js +21 -4
- package/lib/core/codec-registry.js +116 -0
- package/lib/core/codec-worker.js +94 -18
- package/lib/core/configuration.js +2 -0
- package/lib/core/constants.js +5 -1
- package/lib/core/options.js +2 -0
- package/lib/core/streams/codec-stream.js +6 -2
- package/lib/core/streams/zip-entry-stream.js +50 -16
- package/lib/core/streams/zlib-js/zlib-streams.min.js +1 -1
- package/lib/core/web-worker-base.js +30 -8
- 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 +29 -3
- package/lib/core/zip-writer.js +68 -25
- package/lib/zip-core-base.js +7 -0
- package/lib/zip-core-reader.js +2 -1
- package/lib/zip-core-writer.js +1 -0
- package/package.json +1 -1
- package/worker-message-property-names.js +1 -1
package/lib/core/codec-pool.js
CHANGED
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
27
27
|
*/
|
|
28
28
|
|
|
29
|
-
/* global setTimeout, clearTimeout */
|
|
29
|
+
/* global setTimeout, clearTimeout, URL */
|
|
30
30
|
|
|
31
31
|
import { UNDEFINED_VALUE } from "./constants.js";
|
|
32
32
|
import {
|
|
@@ -38,7 +38,8 @@ import {
|
|
|
38
38
|
ERR_INVALID_COMPRESSED_DATA,
|
|
39
39
|
ERR_ABORT_CHECK_PASSWORD
|
|
40
40
|
} from "./streams/codec-stream.js";
|
|
41
|
-
import {
|
|
41
|
+
import { ensureCodecStreams } from "./codec-registry.js";
|
|
42
|
+
import { CodecWorker, resetWebWorkerSupport } from "./codec-worker.js";
|
|
42
43
|
|
|
43
44
|
let pool = [];
|
|
44
45
|
const pendingRequests = [];
|
|
@@ -61,11 +62,18 @@ let indexWorker = 0;
|
|
|
61
62
|
|
|
62
63
|
async function runWorker(stream, workerOptions) {
|
|
63
64
|
const { options, config } = workerOptions;
|
|
64
|
-
const { transferStreams, useWebWorkers, useCompressionStream, compressed, signed, encrypted } = options;
|
|
65
|
+
const { transferStreams, useWebWorkers, useCompressionStream, compressed, signed, encrypted, format, codecURI } = options;
|
|
65
66
|
const { workerURI, maxWorkers } = config;
|
|
67
|
+
if (format) {
|
|
68
|
+
if (codecURI) {
|
|
69
|
+
options.codecURI = resolveCodecURI(codecURI, config.baseURI);
|
|
70
|
+
}
|
|
71
|
+
await ensureCodecStreams(format, options.codecURI);
|
|
72
|
+
}
|
|
66
73
|
workerOptions.transferStreams = transferStreams || (transferStreams === UNDEFINED_VALUE && config.transferStreams);
|
|
67
74
|
const streamCopy = !compressed && !signed && !encrypted;
|
|
68
|
-
|
|
75
|
+
const workerSupported = format === UNDEFINED_VALUE || Boolean(options.codecURI);
|
|
76
|
+
workerOptions.useWebWorkers = !streamCopy && workerSupported && (useWebWorkers || (useWebWorkers === UNDEFINED_VALUE && config.useWebWorkers));
|
|
69
77
|
workerOptions.workerURI = workerOptions.useWebWorkers && workerURI ? workerURI : UNDEFINED_VALUE;
|
|
70
78
|
options.useCompressionStream = useCompressionStream || (useCompressionStream === UNDEFINED_VALUE && config.useCompressionStream);
|
|
71
79
|
return (await getWorker()).run();
|
|
@@ -105,6 +113,14 @@ async function runWorker(stream, workerOptions) {
|
|
|
105
113
|
}
|
|
106
114
|
}
|
|
107
115
|
|
|
116
|
+
function resolveCodecURI(codecURI, baseURI) {
|
|
117
|
+
try {
|
|
118
|
+
return new URL(codecURI, baseURI).toString();
|
|
119
|
+
} catch {
|
|
120
|
+
return codecURI;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
108
124
|
function armStarvationTimeout() {
|
|
109
125
|
if (!starvationTimeout && pendingRequests.length && Number.isFinite(starvationDelay) && starvationDelay >= 0) {
|
|
110
126
|
starvationTimeout = setTimeout(onWorkerStarvation, starvationDelay);
|
|
@@ -165,4 +181,5 @@ async function terminateWorkers() {
|
|
|
165
181
|
clearTerminateTimeout(workerData);
|
|
166
182
|
return workerData.terminate();
|
|
167
183
|
}));
|
|
184
|
+
resetWebWorkerSupport();
|
|
168
185
|
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright (c) 2025 Gildas Lormeau. All rights reserved.
|
|
3
|
+
|
|
4
|
+
Redistribution and use in source and binary forms, with or without
|
|
5
|
+
modification, are permitted provided that the following conditions are met:
|
|
6
|
+
|
|
7
|
+
1. Redistributions of source code must retain the above copyright notice,
|
|
8
|
+
this list of conditions and the following disclaimer.
|
|
9
|
+
|
|
10
|
+
2. Redistributions in binary form must reproduce the above copyright
|
|
11
|
+
notice, this list of conditions and the following disclaimer in
|
|
12
|
+
the documentation and/or other materials provided with the distribution.
|
|
13
|
+
|
|
14
|
+
3. The names of the authors may not be used to endorse or promote products
|
|
15
|
+
derived from this software without specific prior written permission.
|
|
16
|
+
|
|
17
|
+
THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
|
18
|
+
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
|
19
|
+
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
|
20
|
+
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
21
|
+
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
22
|
+
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
|
23
|
+
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
24
|
+
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
25
|
+
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
|
26
|
+
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
import {
|
|
30
|
+
MAX_16_BITS,
|
|
31
|
+
COMPRESSION_METHOD_STORE,
|
|
32
|
+
COMPRESSION_METHOD_DEFLATE,
|
|
33
|
+
COMPRESSION_METHOD_DEFLATE_64,
|
|
34
|
+
COMPRESSION_METHOD_AES,
|
|
35
|
+
FUNCTION_TYPE
|
|
36
|
+
} from "./constants.js";
|
|
37
|
+
|
|
38
|
+
const ERR_INVALID_CODEC_DEFINITION = "Invalid codec definition";
|
|
39
|
+
const ERR_RESERVED_COMPRESSION_METHOD = "Reserved compression method";
|
|
40
|
+
const ERR_INVALID_CODEC_MODULE = "Invalid codec module";
|
|
41
|
+
|
|
42
|
+
const STRING_TYPE = "string";
|
|
43
|
+
const RESERVED_COMPRESSION_METHODS = [
|
|
44
|
+
COMPRESSION_METHOD_STORE,
|
|
45
|
+
COMPRESSION_METHOD_DEFLATE,
|
|
46
|
+
COMPRESSION_METHOD_DEFLATE_64,
|
|
47
|
+
COMPRESSION_METHOD_AES
|
|
48
|
+
];
|
|
49
|
+
|
|
50
|
+
const registeredCodecs = new Map();
|
|
51
|
+
const codecStreams = new Map();
|
|
52
|
+
|
|
53
|
+
export {
|
|
54
|
+
ERR_INVALID_CODEC_DEFINITION,
|
|
55
|
+
ERR_RESERVED_COMPRESSION_METHOD,
|
|
56
|
+
ERR_INVALID_CODEC_MODULE,
|
|
57
|
+
registerCodec,
|
|
58
|
+
unregisterCodec,
|
|
59
|
+
getRegisteredCodec,
|
|
60
|
+
getCodecStreams,
|
|
61
|
+
setCodecStreams,
|
|
62
|
+
ensureCodecStreams
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
function registerCodec(codec = {}) {
|
|
66
|
+
const { compressionMethod, format, codecURI, CompressionStream, DecompressionStream, versionNeeded } = codec;
|
|
67
|
+
if (!Number.isInteger(compressionMethod) || compressionMethod < 0 || compressionMethod > MAX_16_BITS ||
|
|
68
|
+
typeof format != STRING_TYPE || !format.length) {
|
|
69
|
+
throw new Error(ERR_INVALID_CODEC_DEFINITION);
|
|
70
|
+
}
|
|
71
|
+
if (RESERVED_COMPRESSION_METHODS.includes(compressionMethod)) {
|
|
72
|
+
throw new Error(ERR_RESERVED_COMPRESSION_METHOD);
|
|
73
|
+
}
|
|
74
|
+
const hasStreams = typeof CompressionStream == FUNCTION_TYPE || typeof DecompressionStream == FUNCTION_TYPE;
|
|
75
|
+
if (!hasStreams && (typeof codecURI != STRING_TYPE || !codecURI.length)) {
|
|
76
|
+
throw new Error(ERR_INVALID_CODEC_DEFINITION);
|
|
77
|
+
}
|
|
78
|
+
registeredCodecs.set(compressionMethod, { compressionMethod, format, codecURI, versionNeeded });
|
|
79
|
+
if (hasStreams) {
|
|
80
|
+
setCodecStreams(format, { CompressionStream, DecompressionStream });
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function unregisterCodec(compressionMethod) {
|
|
85
|
+
const codec = registeredCodecs.get(compressionMethod);
|
|
86
|
+
if (codec) {
|
|
87
|
+
registeredCodecs.delete(compressionMethod);
|
|
88
|
+
let formatUsed;
|
|
89
|
+
registeredCodecs.forEach(otherCodec => formatUsed = formatUsed || otherCodec.format == codec.format);
|
|
90
|
+
if (!formatUsed) {
|
|
91
|
+
codecStreams.delete(codec.format);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function getRegisteredCodec(compressionMethod) {
|
|
97
|
+
return registeredCodecs.get(compressionMethod);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function getCodecStreams(format) {
|
|
101
|
+
return codecStreams.get(format);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function setCodecStreams(format, streams) {
|
|
105
|
+
const { CompressionStream, DecompressionStream } = streams;
|
|
106
|
+
if (typeof CompressionStream != FUNCTION_TYPE && typeof DecompressionStream != FUNCTION_TYPE) {
|
|
107
|
+
throw new Error(ERR_INVALID_CODEC_MODULE);
|
|
108
|
+
}
|
|
109
|
+
codecStreams.set(format, { CompressionStream, DecompressionStream });
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
async function ensureCodecStreams(format, codecURI) {
|
|
113
|
+
if (!codecStreams.has(format) && codecURI) {
|
|
114
|
+
setCodecStreams(format, await import(codecURI));
|
|
115
|
+
}
|
|
116
|
+
}
|
package/lib/core/codec-worker.js
CHANGED
|
@@ -39,6 +39,7 @@ import {
|
|
|
39
39
|
CODEC_DEFLATE,
|
|
40
40
|
CodecStream,
|
|
41
41
|
ChunkStream,
|
|
42
|
+
supportsDeflateRaw,
|
|
42
43
|
MESSAGE_EVENT_TYPE,
|
|
43
44
|
MESSAGE_START,
|
|
44
45
|
MESSAGE_PULL,
|
|
@@ -50,6 +51,7 @@ import {
|
|
|
50
51
|
const MODULE_WORKER_OPTIONS = { type: "module" };
|
|
51
52
|
const ERROR_EVENT_TYPE = "error";
|
|
52
53
|
const MESSAGE_ERROR_EVENT_TYPE = "messageerror";
|
|
54
|
+
const ERR_WORKER_STARTUP_TIMEOUT = "Worker startup timeout";
|
|
53
55
|
|
|
54
56
|
let webWorkerSupported, webWorkerSource, webWorkerURI, webWorkerOptions;
|
|
55
57
|
let transferStreamsSupported = true;
|
|
@@ -62,13 +64,18 @@ let initModule = () => { };
|
|
|
62
64
|
|
|
63
65
|
export {
|
|
64
66
|
CodecWorker,
|
|
65
|
-
configureWorker
|
|
67
|
+
configureWorker,
|
|
68
|
+
resetWebWorkerSupport
|
|
66
69
|
};
|
|
67
70
|
|
|
68
71
|
function configureWorker({ initModule: initModuleFunction }) {
|
|
69
72
|
initModule = initModuleFunction;
|
|
70
73
|
}
|
|
71
74
|
|
|
75
|
+
function resetWebWorkerSupport() {
|
|
76
|
+
webWorkerSupported = UNDEFINED_VALUE;
|
|
77
|
+
}
|
|
78
|
+
|
|
72
79
|
class CodecWorker {
|
|
73
80
|
|
|
74
81
|
constructor(workerData, { readable, writable }, { options, config, streamOptions, useWebWorkers, transferStreams, workerURI }, onTaskFinished) {
|
|
@@ -162,7 +169,7 @@ function createWorkerInterface(workerData, config) {
|
|
|
162
169
|
}
|
|
163
170
|
|
|
164
171
|
function createWebWorkerInterface(workerData, config) {
|
|
165
|
-
const { baseURI, chunkSize } = config;
|
|
172
|
+
const { baseURI, chunkSize, workerStartupTimeout } = config;
|
|
166
173
|
let { wasmURI } = config;
|
|
167
174
|
|
|
168
175
|
if (!workerData.interface) {
|
|
@@ -179,9 +186,26 @@ function createWebWorkerInterface(workerData, config) {
|
|
|
179
186
|
}
|
|
180
187
|
Object.assign(workerData, {
|
|
181
188
|
worker,
|
|
189
|
+
workerAlive: false,
|
|
182
190
|
terminated: false,
|
|
183
191
|
interface: {
|
|
184
|
-
run: () =>
|
|
192
|
+
run: async () => {
|
|
193
|
+
try {
|
|
194
|
+
return await runWebWorker(workerData, { chunkSize, wasmURI, baseURI, workerStartupTimeout });
|
|
195
|
+
} catch (error) {
|
|
196
|
+
if (error && error.workerStartupFailed) {
|
|
197
|
+
webWorkerSupported = false;
|
|
198
|
+
const { reader } = workerData;
|
|
199
|
+
if (reader) {
|
|
200
|
+
reader.releaseLock();
|
|
201
|
+
}
|
|
202
|
+
workerData.reader = null;
|
|
203
|
+
workerData.writer = null;
|
|
204
|
+
return runWorker(workerData, config);
|
|
205
|
+
}
|
|
206
|
+
throw error;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
185
209
|
}
|
|
186
210
|
});
|
|
187
211
|
}
|
|
@@ -191,15 +215,23 @@ function createWebWorkerInterface(workerData, config) {
|
|
|
191
215
|
async function runWorker({ options, readable, writable, onTaskFinished }, config) {
|
|
192
216
|
let codecStream;
|
|
193
217
|
try {
|
|
194
|
-
if (!options.
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
config
|
|
201
|
-
|
|
202
|
-
|
|
218
|
+
if (options.compressed && !options.format) {
|
|
219
|
+
const deflate = options.codecType.startsWith(CODEC_DEFLATE);
|
|
220
|
+
const ZlibStream = deflate ? config.CompressionStreamZlib : config.DecompressionStreamZlib;
|
|
221
|
+
const NativeStream = deflate ? config.CompressionStream : config.DecompressionStream;
|
|
222
|
+
if (!options.useCompressionStream) {
|
|
223
|
+
try {
|
|
224
|
+
await initModule(config);
|
|
225
|
+
} catch {
|
|
226
|
+
if (!ZlibStream || ZlibStream.requiresModule) {
|
|
227
|
+
options.useCompressionStream = true;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
} else if (ZlibStream && ZlibStream.requiresModule && !supportsDeflateRaw(NativeStream)) {
|
|
231
|
+
try {
|
|
232
|
+
await initModule(config);
|
|
233
|
+
} catch {
|
|
234
|
+
// ignored
|
|
203
235
|
}
|
|
204
236
|
}
|
|
205
237
|
}
|
|
@@ -268,6 +300,10 @@ async function runWebWorker(workerData, config) {
|
|
|
268
300
|
writer: writable.getWriter()
|
|
269
301
|
});
|
|
270
302
|
}
|
|
303
|
+
const { workerStartupTimeout } = config;
|
|
304
|
+
if (!workerData.workerAlive && Number.isFinite(workerStartupTimeout) && workerStartupTimeout >= 0) {
|
|
305
|
+
workerData.startupTimeout = setTimeout(() => onStartupTimeout(workerData), workerStartupTimeout);
|
|
306
|
+
}
|
|
271
307
|
try {
|
|
272
308
|
const resultValue = await result;
|
|
273
309
|
await closeWritable();
|
|
@@ -380,28 +416,68 @@ function getWebWorker(url, baseURI, workerData, isModuleType, useBlobURI = true)
|
|
|
380
416
|
} else {
|
|
381
417
|
worker = new Worker(webWorkerURI, webWorkerOptions);
|
|
382
418
|
}
|
|
383
|
-
worker.addEventListener(MESSAGE_EVENT_TYPE, event =>
|
|
419
|
+
worker.addEventListener(MESSAGE_EVENT_TYPE, event => {
|
|
420
|
+
workerData.workerAlive = true;
|
|
421
|
+
clearStartupTimeout(workerData);
|
|
422
|
+
onMessage(event, workerData);
|
|
423
|
+
});
|
|
384
424
|
worker.addEventListener(ERROR_EVENT_TYPE, event => onWorkerError(event, workerData));
|
|
385
425
|
worker.addEventListener(MESSAGE_ERROR_EVENT_TYPE, event => onWorkerError(event, workerData));
|
|
386
426
|
return worker;
|
|
387
427
|
}
|
|
388
428
|
|
|
429
|
+
function onStartupTimeout(workerData) {
|
|
430
|
+
workerData.startupTimeout = null;
|
|
431
|
+
if (workerData.workerAlive) {
|
|
432
|
+
return;
|
|
433
|
+
}
|
|
434
|
+
const { rejectResult, writer } = workerData;
|
|
435
|
+
terminateWorker(workerData);
|
|
436
|
+
workerData.worker = null;
|
|
437
|
+
if (rejectResult) {
|
|
438
|
+
const error = new Error(ERR_WORKER_STARTUP_TIMEOUT);
|
|
439
|
+
error.workerStartupFailed = true;
|
|
440
|
+
rejectResult(error);
|
|
441
|
+
if (writer) {
|
|
442
|
+
writer.releaseLock();
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
function clearStartupTimeout(workerData) {
|
|
448
|
+
const { startupTimeout } = workerData;
|
|
449
|
+
if (startupTimeout) {
|
|
450
|
+
clearTimeout(startupTimeout);
|
|
451
|
+
workerData.startupTimeout = null;
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
|
|
389
455
|
function onWorkerError(event, workerData) {
|
|
390
456
|
if (event.preventDefault) {
|
|
391
457
|
event.preventDefault();
|
|
392
458
|
}
|
|
393
|
-
|
|
459
|
+
clearStartupTimeout(workerData);
|
|
460
|
+
const { workerAlive, rejectResult, writer, onTaskFinished } = workerData;
|
|
394
461
|
terminateWorker(workerData);
|
|
462
|
+
if (!workerAlive) {
|
|
463
|
+
workerData.worker = null;
|
|
464
|
+
}
|
|
395
465
|
if (rejectResult) {
|
|
396
|
-
|
|
466
|
+
let error = event.error || new Error(event.message || ERROR_EVENT_TYPE);
|
|
467
|
+
if (!workerAlive) {
|
|
468
|
+
error = Object.assign(new Error(error.message || ERROR_EVENT_TYPE), { workerStartupFailed: true });
|
|
469
|
+
}
|
|
470
|
+
rejectResult(error);
|
|
397
471
|
if (writer) {
|
|
398
472
|
writer.releaseLock();
|
|
399
473
|
}
|
|
400
|
-
|
|
474
|
+
if (workerAlive) {
|
|
475
|
+
onTaskFinished();
|
|
476
|
+
}
|
|
401
477
|
}
|
|
402
478
|
}
|
|
403
479
|
|
|
404
|
-
function sendMessage(message, { worker, writer, transferStreams }) {
|
|
480
|
+
function sendMessage(message, { worker, writer, transferStreams, workerAlive }) {
|
|
405
481
|
try {
|
|
406
482
|
const { value, readable, writable } = message;
|
|
407
483
|
const transferables = [];
|
|
@@ -409,7 +485,7 @@ function sendMessage(message, { worker, writer, transferStreams }) {
|
|
|
409
485
|
message.value = toExactUint8Array(value);
|
|
410
486
|
transferables.push(message.value.buffer);
|
|
411
487
|
}
|
|
412
|
-
if (transferStreams && transferStreamsSupported) {
|
|
488
|
+
if (transferStreams && transferStreamsSupported && workerAlive) {
|
|
413
489
|
if (readable) {
|
|
414
490
|
transferables.push(readable);
|
|
415
491
|
}
|
|
@@ -49,6 +49,7 @@ const DEFAULT_CONFIGURATION = {
|
|
|
49
49
|
maxWorkers,
|
|
50
50
|
terminateWorkerTimeout: 5000,
|
|
51
51
|
workerStarvationTimeout: 5000,
|
|
52
|
+
workerStartupTimeout: 5000,
|
|
52
53
|
useWebWorkers: true,
|
|
53
54
|
useCompressionStream: true,
|
|
54
55
|
transferStreams: true,
|
|
@@ -64,6 +65,7 @@ const CONFIGURABLE_PROPERTY_NAMES = [
|
|
|
64
65
|
"maxWorkers",
|
|
65
66
|
"terminateWorkerTimeout",
|
|
66
67
|
"workerStarvationTimeout",
|
|
68
|
+
"workerStartupTimeout",
|
|
67
69
|
"useCompressionStream",
|
|
68
70
|
"useWebWorkers",
|
|
69
71
|
"transferStreams",
|
package/lib/core/constants.js
CHANGED
|
@@ -37,6 +37,7 @@ const COMPRESSION_METHOD_AES = 0x63;
|
|
|
37
37
|
const LOCAL_FILE_HEADER_SIGNATURE = 0x04034b50;
|
|
38
38
|
const SPLIT_ZIP_FILE_SIGNATURE = 0x08074b50;
|
|
39
39
|
const DATA_DESCRIPTOR_RECORD_SIGNATURE = SPLIT_ZIP_FILE_SIGNATURE;
|
|
40
|
+
const ARCHIVE_EXTRA_DATA_SIGNATURE = 0x08064b50;
|
|
40
41
|
const CENTRAL_FILE_HEADER_SIGNATURE = 0x02014b50;
|
|
41
42
|
const END_OF_CENTRAL_DIR_SIGNATURE = 0x06054b50;
|
|
42
43
|
const ZIP64_END_OF_CENTRAL_DIR_SIGNATURE = 0x06064b50;
|
|
@@ -68,6 +69,7 @@ const BITFLAG_LEVEL_MAX_MASK = 0b010;
|
|
|
68
69
|
const BITFLAG_LEVEL_FAST_MASK = 0b100;
|
|
69
70
|
const BITFLAG_LEVEL_SUPER_FAST_MASK = 0b110;
|
|
70
71
|
const BITFLAG_DATA_DESCRIPTOR = 0b1000;
|
|
72
|
+
const BITFLAG_STRONG_ENCRYPTION = 0b1000000;
|
|
71
73
|
const BITFLAG_LANG_ENCODING_FLAG = 0b100000000000;
|
|
72
74
|
const FILE_ATTR_MSDOS_DIR_MASK = 0b10000;
|
|
73
75
|
const FILE_ATTR_MSDOS_READONLY_MASK = 0x01;
|
|
@@ -95,7 +97,7 @@ const HEADER_OFFSET_COMPRESSED_SIZE = 14;
|
|
|
95
97
|
const HEADER_OFFSET_UNCOMPRESSED_SIZE = 18;
|
|
96
98
|
const LOCAL_HEADER_COMMON_OFFSET = 4;
|
|
97
99
|
|
|
98
|
-
const MAX_DATE = new Date(2107, 11, 31);
|
|
100
|
+
const MAX_DATE = new Date(2107, 11, 31, 23, 59, 58);
|
|
99
101
|
const MIN_DATE = new Date(1980, 0, 1);
|
|
100
102
|
|
|
101
103
|
const UNDEFINED_VALUE = undefined;
|
|
@@ -116,6 +118,7 @@ export {
|
|
|
116
118
|
COMPRESSION_METHOD_STORE,
|
|
117
119
|
COMPRESSION_METHOD_AES,
|
|
118
120
|
SPLIT_ZIP_FILE_SIGNATURE,
|
|
121
|
+
ARCHIVE_EXTRA_DATA_SIGNATURE,
|
|
119
122
|
LOCAL_FILE_HEADER_SIGNATURE,
|
|
120
123
|
DATA_DESCRIPTOR_RECORD_SIGNATURE,
|
|
121
124
|
CENTRAL_FILE_HEADER_SIGNATURE,
|
|
@@ -146,6 +149,7 @@ export {
|
|
|
146
149
|
BITFLAG_LEVEL_FAST_MASK,
|
|
147
150
|
BITFLAG_LEVEL_SUPER_FAST_MASK,
|
|
148
151
|
BITFLAG_DATA_DESCRIPTOR,
|
|
152
|
+
BITFLAG_STRONG_ENCRYPTION,
|
|
149
153
|
BITFLAG_LANG_ENCODING_FLAG,
|
|
150
154
|
FILE_ATTR_MSDOS_DIR_MASK,
|
|
151
155
|
FILE_ATTR_MSDOS_READONLY_MASK,
|
package/lib/core/options.js
CHANGED
|
@@ -46,6 +46,7 @@ const OPTION_TRANSFER_STREAMS = "transferStreams";
|
|
|
46
46
|
const OPTION_PREVENT_CLOSE = "preventClose";
|
|
47
47
|
const OPTION_ENCRYPTION_STRENGTH = "encryptionStrength";
|
|
48
48
|
const OPTION_EXTENDED_TIMESTAMP = "extendedTimestamp";
|
|
49
|
+
const OPTION_NTFS_TIMESTAMP = "ntfsTimestamp";
|
|
49
50
|
const OPTION_KEEP_ORDER = "keepOrder";
|
|
50
51
|
const OPTION_LEVEL = "level";
|
|
51
52
|
const OPTION_BUFFERED_WRITE = "bufferedWrite";
|
|
@@ -85,6 +86,7 @@ export {
|
|
|
85
86
|
OPTION_PREVENT_CLOSE,
|
|
86
87
|
OPTION_ENCRYPTION_STRENGTH,
|
|
87
88
|
OPTION_EXTENDED_TIMESTAMP,
|
|
89
|
+
OPTION_NTFS_TIMESTAMP,
|
|
88
90
|
OPTION_KEEP_ORDER,
|
|
89
91
|
OPTION_LEVEL,
|
|
90
92
|
OPTION_BUFFERED_WRITE,
|
|
@@ -44,7 +44,8 @@ import {
|
|
|
44
44
|
ERR_INVALID_COMPRESSED_DATA,
|
|
45
45
|
ERR_ABORT_CHECK_PASSWORD,
|
|
46
46
|
InflateStream,
|
|
47
|
-
DeflateStream
|
|
47
|
+
DeflateStream,
|
|
48
|
+
supportsDeflateRaw
|
|
48
49
|
} from "./zip-entry-stream.js";
|
|
49
50
|
|
|
50
51
|
const DEFAULT_CHUNK_SIZE = 64 * 1024;
|
|
@@ -54,6 +55,7 @@ const MESSAGE_PULL = "pull";
|
|
|
54
55
|
const MESSAGE_DATA = "data";
|
|
55
56
|
const MESSAGE_ACK_DATA = "ack";
|
|
56
57
|
const MESSAGE_CLOSE = "close";
|
|
58
|
+
const MESSAGE_READY = "ready";
|
|
57
59
|
const CODEC_DEFLATE = "deflate";
|
|
58
60
|
const CODEC_INFLATE = "inflate";
|
|
59
61
|
|
|
@@ -66,13 +68,15 @@ export {
|
|
|
66
68
|
MESSAGE_DATA,
|
|
67
69
|
MESSAGE_ACK_DATA,
|
|
68
70
|
MESSAGE_CLOSE,
|
|
71
|
+
MESSAGE_READY,
|
|
69
72
|
ERR_INVALID_PASSWORD,
|
|
70
73
|
ERR_INVALID_SIGNATURE,
|
|
71
74
|
ERR_INVALID_UNCOMPRESSED_SIZE,
|
|
72
75
|
ERR_INVALID_COMPRESSED_DATA,
|
|
73
76
|
ERR_ABORT_CHECK_PASSWORD,
|
|
74
77
|
CodecStream,
|
|
75
|
-
ChunkStream
|
|
78
|
+
ChunkStream,
|
|
79
|
+
supportsDeflateRaw
|
|
76
80
|
};
|
|
77
81
|
|
|
78
82
|
class CodecStream extends TransformStream {
|
|
@@ -43,10 +43,13 @@ import {
|
|
|
43
43
|
ERR_INVALID_SIGNATURE,
|
|
44
44
|
ERR_ABORT_CHECK_PASSWORD
|
|
45
45
|
} from "./common-crypto.js";
|
|
46
|
+
import { UNDEFINED_VALUE } from "../constants.js";
|
|
46
47
|
import { concat, getDataView } from "../util/array.js";
|
|
48
|
+
import { getCodecStreams } from "../codec-registry.js";
|
|
47
49
|
|
|
48
50
|
const ERR_INVALID_UNCOMPRESSED_SIZE = "Invalid uncompressed size";
|
|
49
51
|
const ERR_INVALID_COMPRESSED_DATA = "Invalid compressed data";
|
|
52
|
+
const ERR_UNSUPPORTED_COMPRESSION = "Compression method not supported";
|
|
50
53
|
const FORMAT_DEFLATE_RAW = "deflate-raw";
|
|
51
54
|
const FORMAT_DEFLATE64_RAW = "deflate64-raw";
|
|
52
55
|
const FORMAT_GZIP = "gzip";
|
|
@@ -57,23 +60,26 @@ class DeflateStream extends TransformStream {
|
|
|
57
60
|
|
|
58
61
|
constructor(options, { chunkSize, CompressionStreamZlib, CompressionStream }) {
|
|
59
62
|
super({});
|
|
60
|
-
const { compressed, encrypted, useCompressionStream, zipCrypto, signed, level, deflate64 } = options;
|
|
63
|
+
const { compressed, encrypted, useCompressionStream, zipCrypto, signed, level, deflate64, format } = options;
|
|
61
64
|
const stream = this;
|
|
62
65
|
let crc32Stream, encryptionStream, gzipCrc32Stream;
|
|
63
66
|
let readable = super.readable;
|
|
64
|
-
const
|
|
67
|
+
const codecStreams = format && getCodecStreams(format);
|
|
68
|
+
const useGzipCrc32 = signed && compressed && !deflate64 && !codecStreams && (!encrypted || zipCrypto) &&
|
|
65
69
|
Boolean(useCompressionStream && CompressionStream);
|
|
66
70
|
if ((!encrypted || zipCrypto) && signed && !useGzipCrc32) {
|
|
67
71
|
crc32Stream = new Crc32Stream();
|
|
68
72
|
readable = pipeThrough(readable, crc32Stream);
|
|
69
73
|
}
|
|
70
74
|
if (compressed) {
|
|
71
|
-
if (
|
|
75
|
+
if (codecStreams) {
|
|
76
|
+
readable = pipeThroughBackpressured(readable, createCodecStream(codecStreams.CompressionStream, format, { level, chunkSize }));
|
|
77
|
+
} else if (useGzipCrc32) {
|
|
72
78
|
gzipCrc32Stream = new GzipToRawDeflateStream();
|
|
73
79
|
readable = pipeThroughBackpressured(readable, new CompressionStream(FORMAT_GZIP));
|
|
74
80
|
readable = pipeThrough(readable, gzipCrc32Stream);
|
|
75
81
|
} else {
|
|
76
|
-
readable =
|
|
82
|
+
readable = pipeThroughCompressionStream(readable, useCompressionStream, { level, chunkSize }, CompressionStream, CompressionStreamZlib);
|
|
77
83
|
}
|
|
78
84
|
}
|
|
79
85
|
if (encrypted) {
|
|
@@ -142,7 +148,7 @@ class InflateStream extends TransformStream {
|
|
|
142
148
|
|
|
143
149
|
constructor(options, { chunkSize, DecompressionStreamZlib, DecompressionStream }) {
|
|
144
150
|
super({});
|
|
145
|
-
const { zipCrypto, encrypted, signed, signature, compressed, useCompressionStream, deflate64 } = options;
|
|
151
|
+
const { zipCrypto, encrypted, signed, signature, compressed, useCompressionStream, deflate64, format } = options;
|
|
146
152
|
let crc32Stream, decryptionStream;
|
|
147
153
|
let readable = super.readable;
|
|
148
154
|
if (encrypted) {
|
|
@@ -154,7 +160,12 @@ class InflateStream extends TransformStream {
|
|
|
154
160
|
}
|
|
155
161
|
}
|
|
156
162
|
if (compressed) {
|
|
157
|
-
|
|
163
|
+
const codecStreams = format && getCodecStreams(format);
|
|
164
|
+
if (codecStreams) {
|
|
165
|
+
readable = pipeThroughBackpressured(readable, createCodecStream(codecStreams.DecompressionStream, format, { chunkSize }));
|
|
166
|
+
} else {
|
|
167
|
+
readable = pipeThroughCompressionStream(readable, useCompressionStream, { chunkSize, deflate64 }, DecompressionStream, DecompressionStreamZlib);
|
|
168
|
+
}
|
|
158
169
|
readable = mapInflateStreamError(readable);
|
|
159
170
|
}
|
|
160
171
|
if ((!encrypted || zipCrypto) && signed) {
|
|
@@ -172,9 +183,29 @@ class InflateStream extends TransformStream {
|
|
|
172
183
|
}
|
|
173
184
|
}
|
|
174
185
|
|
|
186
|
+
const deflateRawSupportByStream = new Map();
|
|
187
|
+
|
|
188
|
+
function supportsDeflateRaw(StreamClass) {
|
|
189
|
+
if (!StreamClass) {
|
|
190
|
+
return false;
|
|
191
|
+
}
|
|
192
|
+
let supported = deflateRawSupportByStream.get(StreamClass);
|
|
193
|
+
if (supported === UNDEFINED_VALUE) {
|
|
194
|
+
try {
|
|
195
|
+
new StreamClass(FORMAT_DEFLATE_RAW);
|
|
196
|
+
supported = true;
|
|
197
|
+
} catch {
|
|
198
|
+
supported = false;
|
|
199
|
+
}
|
|
200
|
+
deflateRawSupportByStream.set(StreamClass, supported);
|
|
201
|
+
}
|
|
202
|
+
return supported;
|
|
203
|
+
}
|
|
204
|
+
|
|
175
205
|
export {
|
|
176
206
|
DeflateStream,
|
|
177
207
|
InflateStream,
|
|
208
|
+
supportsDeflateRaw,
|
|
178
209
|
ERR_INVALID_PASSWORD,
|
|
179
210
|
ERR_INVALID_SIGNATURE,
|
|
180
211
|
ERR_INVALID_UNCOMPRESSED_SIZE,
|
|
@@ -191,21 +222,24 @@ function setReadable(stream, readable, flush) {
|
|
|
191
222
|
});
|
|
192
223
|
}
|
|
193
224
|
|
|
194
|
-
function
|
|
195
|
-
|
|
225
|
+
function createCodecStream(CodecStreamClass, format, options) {
|
|
226
|
+
if (!CodecStreamClass) {
|
|
227
|
+
throw new Error(ERR_UNSUPPORTED_COMPRESSION);
|
|
228
|
+
}
|
|
229
|
+
return new CodecStreamClass(format, options);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
function pipeThroughCompressionStream(readable, useCompressionStream, options, CompressionStreamNative, CompressionStreamZlib) {
|
|
233
|
+
const Stream = useCompressionStream && CompressionStreamNative ?
|
|
234
|
+
CompressionStreamNative :
|
|
235
|
+
CompressionStreamZlib || CompressionStreamNative;
|
|
196
236
|
const format = options.deflate64 ? FORMAT_DEFLATE64_RAW : FORMAT_DEFLATE_RAW;
|
|
197
237
|
let codecStream;
|
|
198
238
|
try {
|
|
199
239
|
codecStream = new Stream(format, options);
|
|
200
240
|
} catch (error) {
|
|
201
|
-
if (useCompressionStream) {
|
|
202
|
-
|
|
203
|
-
codecStream = new CompressionStreamZlib(format, options);
|
|
204
|
-
} else if (CompressionStream) {
|
|
205
|
-
codecStream = new CompressionStream(format, options);
|
|
206
|
-
} else {
|
|
207
|
-
throw error;
|
|
208
|
-
}
|
|
241
|
+
if (useCompressionStream && CompressionStreamZlib && Stream != CompressionStreamZlib) {
|
|
242
|
+
codecStream = new CompressionStreamZlib(format, options);
|
|
209
243
|
} else {
|
|
210
244
|
throw error;
|
|
211
245
|
}
|