@zip.js/zip.js 2.5.17 → 2.5.20
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/cli-deno/mc-zip.js +29 -13
- package/dist/z-worker-fflate.js +1 -1
- package/dist/z-worker-pako.js +1 -1
- package/dist/z-worker.js +1 -1
- package/dist/zip-fs-full.js +127 -145
- package/dist/zip-fs-full.min.js +1 -1
- package/dist/zip-fs.js +127 -145
- package/dist/zip-fs.min.js +1 -1
- package/dist/zip-full.js +126 -144
- package/dist/zip-full.min.js +1 -1
- package/dist/zip-no-worker-deflate.min.js +1 -1
- package/dist/zip-no-worker-inflate.min.js +1 -1
- package/dist/zip-no-worker.min.js +1 -1
- package/dist/zip.js +126 -144
- package/dist/zip.min.js +1 -1
- package/index.d.ts +42 -24
- package/lib/core/codec-interface.js +15 -24
- package/lib/core/codec-pool-worker.js +44 -46
- package/lib/core/codec-pool.js +8 -9
- package/lib/core/io.js +21 -41
- package/lib/core/streams/zip-entry-stream.js +2 -4
- package/lib/core/z-worker-core.js +2 -2
- package/lib/core/zip-fs-core.js +1 -1
- package/lib/core/zip-reader.js +9 -6
- package/lib/core/zip-writer.js +32 -18
- package/lib/z-worker-inline.js +1 -1
- package/package.json +1 -1
- package/tests/all/test-abort-signal-read.js +5 -6
- package/tests/all/test-abort-signal-write.js +4 -3
- package/tests/all/test-readable-stream.js +3 -1
- package/tests/all/test-writable-stream.js +12 -9
- package/tests/web-runner.js +23 -13
|
@@ -26,7 +26,6 @@
|
|
|
26
26
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
27
27
|
*/
|
|
28
28
|
|
|
29
|
-
/* global AbortController */
|
|
30
29
|
// deno-lint-ignore-file no-this-alias
|
|
31
30
|
|
|
32
31
|
import {
|
|
@@ -46,7 +45,7 @@ const MESSAGE_CLOSE = "close";
|
|
|
46
45
|
const ERR_ABORT = "AbortError";
|
|
47
46
|
|
|
48
47
|
export {
|
|
49
|
-
|
|
48
|
+
Codec,
|
|
50
49
|
CODEC_DEFLATE,
|
|
51
50
|
CODEC_INFLATE,
|
|
52
51
|
ERR_INVALID_SIGNATURE,
|
|
@@ -59,29 +58,21 @@ export {
|
|
|
59
58
|
ERR_ABORT
|
|
60
59
|
};
|
|
61
60
|
|
|
62
|
-
|
|
63
|
-
const controller = new AbortController();
|
|
64
|
-
const { signal } = controller;
|
|
65
|
-
if (options.codecType.startsWith(CODEC_DEFLATE)) {
|
|
66
|
-
return {
|
|
67
|
-
run: () => run(DeflateStream),
|
|
68
|
-
abort
|
|
69
|
-
};
|
|
70
|
-
} else if (options.codecType.startsWith(CODEC_INFLATE)) {
|
|
71
|
-
return {
|
|
72
|
-
run: () => run(InflateStream),
|
|
73
|
-
abort
|
|
74
|
-
};
|
|
75
|
-
}
|
|
61
|
+
class Codec {
|
|
76
62
|
|
|
77
|
-
|
|
78
|
-
const
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
63
|
+
constructor(codecConstructor, readable, writable, options, config) {
|
|
64
|
+
const { codecType } = options;
|
|
65
|
+
if (codecType.startsWith(CODEC_DEFLATE)) {
|
|
66
|
+
this.run = () => run(DeflateStream);
|
|
67
|
+
} else if (codecType.startsWith(CODEC_INFLATE)) {
|
|
68
|
+
this.run = () => run(InflateStream);
|
|
69
|
+
}
|
|
83
70
|
|
|
84
|
-
|
|
85
|
-
|
|
71
|
+
async function run(StreamConstructor) {
|
|
72
|
+
const stream = new StreamConstructor(codecConstructor, options, config);
|
|
73
|
+
await readable.pipeThrough(stream).pipeTo(writable, { preventClose: true });
|
|
74
|
+
const { length, signature } = stream;
|
|
75
|
+
return { length, signature };
|
|
76
|
+
}
|
|
86
77
|
}
|
|
87
78
|
}
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
/* global Worker, URL, TransformStream */
|
|
30
30
|
|
|
31
31
|
import {
|
|
32
|
-
|
|
32
|
+
Codec,
|
|
33
33
|
MESSAGE_EVENT_TYPE,
|
|
34
34
|
MESSAGE_START,
|
|
35
35
|
MESSAGE_PULL,
|
|
@@ -40,50 +40,54 @@ import {
|
|
|
40
40
|
let classicWorkersSupported = true;
|
|
41
41
|
|
|
42
42
|
export {
|
|
43
|
-
|
|
43
|
+
CodecWorker
|
|
44
44
|
};
|
|
45
45
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
workerData.
|
|
46
|
+
class CodecWorker {
|
|
47
|
+
|
|
48
|
+
constructor(workerData, stream, workerOptions, onTaskFinished) {
|
|
49
|
+
const { readable, writable } = stream;
|
|
50
|
+
const { options, config, streamOptions, webWorker, scripts, codecConstructor } = workerOptions;
|
|
51
|
+
Object.assign(workerData, {
|
|
52
|
+
busy: true,
|
|
53
|
+
codecConstructor,
|
|
54
|
+
readable,
|
|
55
|
+
writable,
|
|
56
|
+
options: Object.assign({}, options),
|
|
57
|
+
scripts,
|
|
58
|
+
terminate() {
|
|
59
|
+
if (workerData.worker && !workerData.busy) {
|
|
60
|
+
workerData.worker.terminate();
|
|
61
|
+
workerData.interface = null;
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
onTaskFinished() {
|
|
65
|
+
workerData.busy = false;
|
|
66
|
+
onTaskFinished(workerData);
|
|
60
67
|
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
workerData.busy = false;
|
|
64
|
-
onTaskFinished(workerData);
|
|
65
|
-
}
|
|
66
|
-
});
|
|
67
|
-
const { signal, size, onstart, onprogress, onend } = streamOptions;
|
|
68
|
-
if (signal || onstart || onprogress || onend) {
|
|
68
|
+
});
|
|
69
|
+
const { signal, onstart, onprogress, size, onend } = streamOptions;
|
|
69
70
|
let chunkOffset = 0;
|
|
70
71
|
const transformer = {};
|
|
71
72
|
if (onstart) {
|
|
72
73
|
transformer.start = () => callHandler(onstart, size());
|
|
73
74
|
}
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
75
|
+
transformer.transform = async (chunk, controller) => {
|
|
76
|
+
chunkOffset += chunk.length;
|
|
77
|
+
if (onprogress) {
|
|
77
78
|
await callHandler(onprogress, chunkOffset, size());
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
79
|
+
}
|
|
80
|
+
controller.enqueue(chunk);
|
|
81
|
+
};
|
|
82
|
+
transformer.flush = () => {
|
|
83
|
+
readable.size = () => chunkOffset;
|
|
84
|
+
if (onend) {
|
|
85
|
+
callHandler(onend, chunkOffset);
|
|
86
|
+
}
|
|
87
|
+
};
|
|
84
88
|
workerData.readable = readable.pipeThrough(new TransformStream(transformer, { highWaterMark: 1, size: () => config.chunkSize }), { signal });
|
|
89
|
+
return webWorker ? createWebWorkerInterface(workerData, config) : createWorkerInterface(workerData, config);
|
|
85
90
|
}
|
|
86
|
-
return webWorker ? createWebWorkerInterface(workerData, config) : createWorkerInterface(workerData, config);
|
|
87
91
|
}
|
|
88
92
|
|
|
89
93
|
async function callHandler(handler, ...parameters) {
|
|
@@ -95,17 +99,15 @@ async function callHandler(handler, ...parameters) {
|
|
|
95
99
|
}
|
|
96
100
|
|
|
97
101
|
function createWorkerInterface(workerData, config) {
|
|
98
|
-
const interfaceCodec =
|
|
102
|
+
const interfaceCodec = new Codec(workerData.codecConstructor, workerData.readable, workerData.writable, workerData.options, config);
|
|
99
103
|
const { onTaskFinished } = workerData;
|
|
100
104
|
const codec = {
|
|
101
|
-
abort() {
|
|
102
|
-
interfaceCodec.abort();
|
|
103
|
-
onTaskFinished();
|
|
104
|
-
},
|
|
105
105
|
async run() {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
106
|
+
try {
|
|
107
|
+
return await interfaceCodec.run();
|
|
108
|
+
} finally {
|
|
109
|
+
onTaskFinished();
|
|
110
|
+
}
|
|
109
111
|
}
|
|
110
112
|
};
|
|
111
113
|
return codec;
|
|
@@ -135,10 +137,6 @@ function createWebWorkerInterface(workerData, { baseURL, chunkSize }) {
|
|
|
135
137
|
}
|
|
136
138
|
workerData.worker.addEventListener(MESSAGE_EVENT_TYPE, onMessage, false);
|
|
137
139
|
workerData.interface = {
|
|
138
|
-
abort() {
|
|
139
|
-
workerData.writer.releaseLock();
|
|
140
|
-
workerData.onTaskFinished();
|
|
141
|
-
},
|
|
142
140
|
run() {
|
|
143
141
|
const { options } = workerData;
|
|
144
142
|
const scripts = workerData.scripts.slice(1);
|
package/lib/core/codec-pool.js
CHANGED
|
@@ -35,7 +35,7 @@ import {
|
|
|
35
35
|
ERR_INVALID_PASSWORD,
|
|
36
36
|
ERR_ABORT
|
|
37
37
|
} from "./codec-interface.js";
|
|
38
|
-
import {
|
|
38
|
+
import { CodecWorker } from "./codec-pool-worker.js";
|
|
39
39
|
|
|
40
40
|
let pool = [];
|
|
41
41
|
const pendingRequests = [];
|
|
@@ -60,27 +60,26 @@ async function runWorker(stream, workerOptions) {
|
|
|
60
60
|
workerOptions.webWorker = !streamCopy && (useWebWorkers || (useWebWorkers === undefined && config.useWebWorkers));
|
|
61
61
|
workerOptions.scripts = workerOptions.webWorker && workerScripts ? workerScripts[codecType] : [];
|
|
62
62
|
options.useCompressionStream = useCompressionStream === undefined ? config.useCompressionStream : useCompressionStream;
|
|
63
|
-
let
|
|
63
|
+
let worker;
|
|
64
64
|
if (pool.length < config.maxWorkers) {
|
|
65
65
|
const workerData = { indexWorker };
|
|
66
66
|
indexWorker++;
|
|
67
67
|
pool.push(workerData);
|
|
68
|
-
|
|
68
|
+
worker = new CodecWorker(workerData, stream, workerOptions, onTaskFinished);
|
|
69
69
|
} else {
|
|
70
70
|
const workerData = pool.find(workerData => !workerData.busy);
|
|
71
71
|
if (workerData) {
|
|
72
72
|
clearTerminateTimeout(workerData);
|
|
73
|
-
|
|
73
|
+
worker = new CodecWorker(workerData, stream, workerOptions, onTaskFinished);
|
|
74
74
|
} else {
|
|
75
|
-
|
|
75
|
+
worker = await new Promise(resolve => pendingRequests.push({ resolve, stream, workerOptions }));
|
|
76
76
|
}
|
|
77
77
|
}
|
|
78
|
-
const { signal } = streamOptions;
|
|
79
78
|
try {
|
|
80
|
-
return await
|
|
79
|
+
return await worker.run();
|
|
81
80
|
} catch (error) {
|
|
81
|
+
const { signal } = streamOptions;
|
|
82
82
|
if (signal && signal.aborted && (signal.reason == error || error.name == ERR_ABORT)) {
|
|
83
|
-
codec.abort();
|
|
84
83
|
throw new Error(ERR_ABORT);
|
|
85
84
|
} else {
|
|
86
85
|
throw error;
|
|
@@ -90,7 +89,7 @@ async function runWorker(stream, workerOptions) {
|
|
|
90
89
|
function onTaskFinished(workerData) {
|
|
91
90
|
if (pendingRequests.length) {
|
|
92
91
|
const [{ resolve, stream, workerOptions }] = pendingRequests.splice(0, 1);
|
|
93
|
-
resolve(
|
|
92
|
+
resolve(new CodecWorker(workerData, stream, workerOptions, onTaskFinished));
|
|
94
93
|
} else if (workerData.worker) {
|
|
95
94
|
const { terminateWorkerTimeout } = config;
|
|
96
95
|
clearTerminateTimeout(workerData);
|
package/lib/core/io.js
CHANGED
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
27
27
|
*/
|
|
28
28
|
|
|
29
|
-
/* global Blob, atob, btoa, XMLHttpRequest,
|
|
29
|
+
/* global Blob, atob, btoa, XMLHttpRequest, URL, fetch, ReadableStream, WritableStream */
|
|
30
30
|
|
|
31
31
|
const ERR_HTTP_STATUS = "HTTP error ";
|
|
32
32
|
const ERR_HTTP_RANGE = "HTTP Range not supported";
|
|
@@ -42,6 +42,8 @@ const HTTP_METHOD_GET = "GET";
|
|
|
42
42
|
const HTTP_RANGE_UNIT = "bytes";
|
|
43
43
|
const DEFAULT_CHUNK_SIZE = 64 * 1024;
|
|
44
44
|
|
|
45
|
+
import { getConfiguration } from "./configuration.js";
|
|
46
|
+
|
|
45
47
|
class Stream {
|
|
46
48
|
|
|
47
49
|
constructor() {
|
|
@@ -55,13 +57,14 @@ class Stream {
|
|
|
55
57
|
|
|
56
58
|
class Reader extends Stream {
|
|
57
59
|
|
|
58
|
-
|
|
60
|
+
get readable() {
|
|
59
61
|
const reader = this;
|
|
60
|
-
|
|
62
|
+
const readable = new ReadableStream({
|
|
61
63
|
start() {
|
|
62
64
|
this.chunkOffset = 0;
|
|
63
65
|
},
|
|
64
66
|
async pull(controller) {
|
|
67
|
+
const { offset = 0, chunkSize = DEFAULT_CHUNK_SIZE, size } = readable;
|
|
65
68
|
const { chunkOffset } = this;
|
|
66
69
|
controller.enqueue(await reader.readUint8Array(offset + chunkOffset, Math.min(chunkSize, size() - chunkOffset)));
|
|
67
70
|
if (chunkOffset + chunkSize > size()) {
|
|
@@ -71,18 +74,25 @@ class Reader extends Stream {
|
|
|
71
74
|
}
|
|
72
75
|
}
|
|
73
76
|
});
|
|
77
|
+
return readable;
|
|
74
78
|
}
|
|
75
79
|
}
|
|
76
80
|
|
|
77
81
|
class WriterStream extends Stream {
|
|
78
82
|
|
|
79
|
-
|
|
83
|
+
constructor() {
|
|
84
|
+
super();
|
|
80
85
|
const writer = this;
|
|
81
|
-
|
|
86
|
+
const writable = new WritableStream({
|
|
82
87
|
write(chunk) {
|
|
83
88
|
return writer.writeUint8Array(chunk);
|
|
84
89
|
}
|
|
85
90
|
});
|
|
91
|
+
Object.defineProperty(this, "writable", {
|
|
92
|
+
get() {
|
|
93
|
+
return writable;
|
|
94
|
+
}
|
|
95
|
+
});
|
|
86
96
|
}
|
|
87
97
|
}
|
|
88
98
|
|
|
@@ -247,30 +257,13 @@ function flushArrayBuffers(blobWriter) {
|
|
|
247
257
|
blobWriter.arrayBuffers = [];
|
|
248
258
|
}
|
|
249
259
|
|
|
250
|
-
class ReadableStreamReader {
|
|
260
|
+
class ReadableStreamReader extends Stream {
|
|
251
261
|
|
|
252
262
|
constructor(readable) {
|
|
253
|
-
|
|
263
|
+
super();
|
|
254
264
|
if (!readable) {
|
|
255
|
-
readable = new ReadableStream({});
|
|
265
|
+
this.readable = new ReadableStream({});
|
|
256
266
|
}
|
|
257
|
-
reader.readable = readable.pipeThrough(new TransformStream({
|
|
258
|
-
transform(chunk, controller) {
|
|
259
|
-
if (chunk) {
|
|
260
|
-
reader.size += chunk.length;
|
|
261
|
-
controller.enqueue(chunk);
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
}));
|
|
265
|
-
reader.size = 0;
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
init() {
|
|
269
|
-
this.initialized = true;
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
getReadable() {
|
|
273
|
-
return this.readable;
|
|
274
267
|
}
|
|
275
268
|
}
|
|
276
269
|
|
|
@@ -288,15 +281,6 @@ class WritableStreamWriter extends Writer {
|
|
|
288
281
|
}
|
|
289
282
|
});
|
|
290
283
|
}
|
|
291
|
-
|
|
292
|
-
async getData() {
|
|
293
|
-
const writer = this;
|
|
294
|
-
const { writable } = writer;
|
|
295
|
-
if (!writer.preventClose) {
|
|
296
|
-
await writable.getWriter().close();
|
|
297
|
-
}
|
|
298
|
-
return writable;
|
|
299
|
-
}
|
|
300
284
|
}
|
|
301
285
|
|
|
302
286
|
class FetchReader extends Reader {
|
|
@@ -547,13 +531,9 @@ class Uint8ArrayWriter extends Writer {
|
|
|
547
531
|
}
|
|
548
532
|
|
|
549
533
|
function isHttpFamily(url) {
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
return anchor.protocol == "http:" || anchor.protocol == "https:";
|
|
554
|
-
} else {
|
|
555
|
-
return /^https?:\/\//i.test(url);
|
|
556
|
-
}
|
|
534
|
+
const { baseURL } = getConfiguration();
|
|
535
|
+
const { protocol } = new URL(url, baseURL);
|
|
536
|
+
return protocol == "http:" || protocol == "https:";
|
|
557
537
|
}
|
|
558
538
|
|
|
559
539
|
export {
|
|
@@ -52,11 +52,10 @@ class DeflateStream extends TransformStream {
|
|
|
52
52
|
|
|
53
53
|
constructor(codecConstructor, options, { chunkSize }, ...strategies) {
|
|
54
54
|
super({}, ...strategies);
|
|
55
|
-
const { compressed, useCompressionStream, password, passwordVerification, encryptionStrength, zipCrypto, signed } = options;
|
|
55
|
+
const { compressed, encrypted, useCompressionStream, password, passwordVerification, encryptionStrength, zipCrypto, signed } = options;
|
|
56
56
|
const stream = this;
|
|
57
57
|
let crc32Stream, encryptionStream;
|
|
58
58
|
let readable = filterEmptyChunks(super.readable);
|
|
59
|
-
const encrypted = Boolean(password);
|
|
60
59
|
if ((!encrypted || zipCrypto) && signed) {
|
|
61
60
|
[readable, crc32Stream] = readable.tee();
|
|
62
61
|
crc32Stream = crc32Stream.pipeThrough(new Crc32Stream());
|
|
@@ -99,11 +98,10 @@ class InflateStream extends TransformStream {
|
|
|
99
98
|
|
|
100
99
|
constructor(codecConstructor, options, { chunkSize }, ...strategies) {
|
|
101
100
|
super({}, ...strategies);
|
|
102
|
-
const { zipCrypto, password, passwordVerification, signed, encryptionStrength, compressed, useCompressionStream } = options;
|
|
101
|
+
const { zipCrypto, encrypted, password, passwordVerification, signed, encryptionStrength, compressed, useCompressionStream } = options;
|
|
103
102
|
const stream = this;
|
|
104
103
|
let crc32Stream, decryptionStream;
|
|
105
104
|
let readable = filterEmptyChunks(super.readable);
|
|
106
|
-
const encrypted = Boolean(password);
|
|
107
105
|
if (encrypted) {
|
|
108
106
|
if (zipCrypto) {
|
|
109
107
|
readable = readable.pipeThrough(new ZipCryptoDecryptionStream(password, passwordVerification));
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
/* global self, importScripts, addEventListener, postMessage, ReadableStream, WritableStream */
|
|
30
30
|
|
|
31
31
|
import {
|
|
32
|
-
|
|
32
|
+
Codec,
|
|
33
33
|
CODEC_DEFLATE,
|
|
34
34
|
CODEC_INFLATE,
|
|
35
35
|
MESSAGE_EVENT_TYPE,
|
|
@@ -94,7 +94,7 @@ async function init(message) {
|
|
|
94
94
|
sendMessage({ type: MESSAGE_DATA, data });
|
|
95
95
|
}
|
|
96
96
|
}, strategy);
|
|
97
|
-
codec =
|
|
97
|
+
codec = new Codec(codecConstructor, readable, writable, options, config);
|
|
98
98
|
const result = await codec.run();
|
|
99
99
|
sendMessage({ type: MESSAGE_CLOSE, result });
|
|
100
100
|
|
package/lib/core/zip-fs-core.js
CHANGED
|
@@ -117,7 +117,7 @@ class ZipFileEntry extends ZipEntry {
|
|
|
117
117
|
} else {
|
|
118
118
|
zipEntry.reader = new zipEntry.Reader(zipEntry.data, options);
|
|
119
119
|
await zipEntry.reader.init();
|
|
120
|
-
if (!writer.initialized) {
|
|
120
|
+
if (writer.init && !writer.initialized) {
|
|
121
121
|
await writer.init();
|
|
122
122
|
}
|
|
123
123
|
zipEntry.uncompressedSize = zipEntry.reader.size;
|
package/lib/core/zip-reader.js
CHANGED
|
@@ -266,9 +266,6 @@ class ZipEntry {
|
|
|
266
266
|
compressedSize
|
|
267
267
|
} = zipEntry;
|
|
268
268
|
const localDirectory = zipEntry.localDirectory = {};
|
|
269
|
-
if (!reader.initialized) {
|
|
270
|
-
await reader.init();
|
|
271
|
-
}
|
|
272
269
|
let dataArray = await readUint8Array(reader, offset, 30);
|
|
273
270
|
const dataView = getDataView(dataArray);
|
|
274
271
|
let password = getOptionValue(zipEntry, options, "password");
|
|
@@ -301,10 +298,13 @@ class ZipEntry {
|
|
|
301
298
|
}
|
|
302
299
|
const dataOffset = offset + 30 + localDirectory.filenameLength + localDirectory.extraFieldLength;
|
|
303
300
|
const size = () => compressedSize;
|
|
304
|
-
const readable = reader.
|
|
301
|
+
const readable = reader.readable;
|
|
302
|
+
readable.offset = dataOffset;
|
|
303
|
+
readable.size = size;
|
|
304
|
+
readable.chunkSize = getChunkSize(config);
|
|
305
305
|
const { writable } = writer;
|
|
306
306
|
const signal = getOptionValue(zipEntry, options, "signal");
|
|
307
|
-
if (!writer.initialized) {
|
|
307
|
+
if (writer.init && !writer.initialized) {
|
|
308
308
|
await writer.init();
|
|
309
309
|
}
|
|
310
310
|
const { onstart, onprogress, onend } = options;
|
|
@@ -327,7 +327,10 @@ class ZipEntry {
|
|
|
327
327
|
codecConstructor: config.Inflate
|
|
328
328
|
};
|
|
329
329
|
await runWorker({ readable, writable }, workerOptions);
|
|
330
|
-
|
|
330
|
+
if (!writer.preventClose) {
|
|
331
|
+
await writable.getWriter().close();
|
|
332
|
+
}
|
|
333
|
+
return writer.getData ? writer.getData() : writable;
|
|
331
334
|
}
|
|
332
335
|
}
|
|
333
336
|
|
package/lib/core/zip-writer.js
CHANGED
|
@@ -94,7 +94,7 @@ class ZipWriter {
|
|
|
94
94
|
options,
|
|
95
95
|
config: getConfiguration(),
|
|
96
96
|
files: new Map(),
|
|
97
|
-
offset: writer.size,
|
|
97
|
+
offset: writer.size || 0,
|
|
98
98
|
pendingCompressedSize: 0,
|
|
99
99
|
pendingEntries: [],
|
|
100
100
|
pendingAddFileCalls: new Set()
|
|
@@ -126,11 +126,16 @@ class ZipWriter {
|
|
|
126
126
|
}
|
|
127
127
|
|
|
128
128
|
async close(comment = new Uint8Array(), options = {}) {
|
|
129
|
-
|
|
130
|
-
|
|
129
|
+
const { pendingAddFileCalls, writer } = this;
|
|
130
|
+
const { writable } = writer;
|
|
131
|
+
while (pendingAddFileCalls.size) {
|
|
132
|
+
await Promise.all(Array.from(pendingAddFileCalls));
|
|
131
133
|
}
|
|
132
134
|
await closeFile(this, comment, options);
|
|
133
|
-
|
|
135
|
+
if (!writer.preventClose) {
|
|
136
|
+
await writable.getWriter().close();
|
|
137
|
+
}
|
|
138
|
+
return writer.getData ? writer.getData() : writable;
|
|
134
139
|
}
|
|
135
140
|
}
|
|
136
141
|
|
|
@@ -220,10 +225,14 @@ async function addFile(zipWriter, name, reader, options) {
|
|
|
220
225
|
const internalFileAttribute = getOptionValue(zipWriter, options, "internalFileAttribute") || 0;
|
|
221
226
|
const externalFileAttribute = getOptionValue(zipWriter, options, "externalFileAttribute") || 0;
|
|
222
227
|
if (reader) {
|
|
223
|
-
if (!reader.initialized) {
|
|
228
|
+
if (reader.init && !reader.initialized) {
|
|
224
229
|
await reader.init();
|
|
225
230
|
}
|
|
226
|
-
|
|
231
|
+
if (reader.size === undefined) {
|
|
232
|
+
options.dataDescriptor = true;
|
|
233
|
+
} else {
|
|
234
|
+
uncompressedSize = reader.size;
|
|
235
|
+
}
|
|
227
236
|
maximumCompressedSize = getMaximumCompressedSize(uncompressedSize);
|
|
228
237
|
}
|
|
229
238
|
let zip64 = options.zip64 || zipWriter.options.zip64 || false;
|
|
@@ -304,8 +313,8 @@ async function getFileEntry(zipWriter, name, reader, options) {
|
|
|
304
313
|
fileWriter.init();
|
|
305
314
|
bufferedWrite = true;
|
|
306
315
|
} else {
|
|
307
|
-
zipWriter.lockWrite =
|
|
308
|
-
if (!writer.initialized) {
|
|
316
|
+
zipWriter.lockWrite = Promise.resolve();
|
|
317
|
+
if (writer.init && !writer.initialized) {
|
|
309
318
|
await writer.init();
|
|
310
319
|
}
|
|
311
320
|
fileWriter = writer;
|
|
@@ -316,14 +325,8 @@ async function getFileEntry(zipWriter, name, reader, options) {
|
|
|
316
325
|
if (bufferedWrite) {
|
|
317
326
|
let indexWrittenData = 0;
|
|
318
327
|
const blob = fileWriter.getData();
|
|
319
|
-
await
|
|
320
|
-
|
|
321
|
-
do {
|
|
322
|
-
pendingFileEntry = Array.from(files.values()).find(fileEntry => fileEntry.writingBufferedData);
|
|
323
|
-
if (pendingFileEntry) {
|
|
324
|
-
await pendingFileEntry.lock;
|
|
325
|
-
}
|
|
326
|
-
} while (pendingFileEntry && pendingFileEntry.lock);
|
|
328
|
+
await lockPreviousFileEntry;
|
|
329
|
+
await lockWriterAccess();
|
|
327
330
|
fileEntry.writingBufferedData = true;
|
|
328
331
|
const { writable } = writer;
|
|
329
332
|
if (!options.dataDescriptor) {
|
|
@@ -370,6 +373,15 @@ async function getFileEntry(zipWriter, name, reader, options) {
|
|
|
370
373
|
resolveLockUnbufferedWrite();
|
|
371
374
|
}
|
|
372
375
|
}
|
|
376
|
+
|
|
377
|
+
async function lockWriterAccess() {
|
|
378
|
+
if (zipWriter.lockWrite) {
|
|
379
|
+
await zipWriter.lockWrite.then(() => delete zipWriter.lockWrite);
|
|
380
|
+
await lockWriterAccess();
|
|
381
|
+
} else {
|
|
382
|
+
zipWriter.lockWrite = new Promise(resolve => resolveLockUnbufferedWrite = resolve);
|
|
383
|
+
}
|
|
384
|
+
}
|
|
373
385
|
}
|
|
374
386
|
|
|
375
387
|
async function createFileEntry(reader, writable, config, options) {
|
|
@@ -524,7 +536,9 @@ async function createFileEntry(reader, writable, config, options) {
|
|
|
524
536
|
await writeUint8Array(writable, localHeaderArray);
|
|
525
537
|
fileEntry.dataWritten = true;
|
|
526
538
|
const size = () => reader.size;
|
|
527
|
-
const readable = reader.
|
|
539
|
+
const readable = reader.readable;
|
|
540
|
+
readable.size = size;
|
|
541
|
+
readable.chunkSize = getChunkSize(config);
|
|
528
542
|
const workerOptions = {
|
|
529
543
|
options: {
|
|
530
544
|
codecType: CODEC_DEFLATE,
|
|
@@ -544,7 +558,7 @@ async function createFileEntry(reader, writable, config, options) {
|
|
|
544
558
|
codecConstructor: config.Deflate
|
|
545
559
|
};
|
|
546
560
|
result = await runWorker({ readable, writable }, workerOptions);
|
|
547
|
-
uncompressedSize = fileEntry.uncompressedSize = reader.size;
|
|
561
|
+
uncompressedSize = fileEntry.uncompressedSize = reader.size = readable.size();
|
|
548
562
|
compressedSize = result.length;
|
|
549
563
|
} else {
|
|
550
564
|
await writeUint8Array(writable, localHeaderArray);
|