@zip.js/zip.js 2.5.16 → 2.5.19

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.
@@ -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 {
@@ -42,12 +41,11 @@ const MESSAGE_EVENT_TYPE = "message";
42
41
  const MESSAGE_START = "start";
43
42
  const MESSAGE_PULL = "pull";
44
43
  const MESSAGE_DATA = "data";
45
- const MESSAGE_ABORT = "abort";
46
44
  const MESSAGE_CLOSE = "close";
47
45
  const ERR_ABORT = "AbortError";
48
46
 
49
47
  export {
50
- createCodec,
48
+ Codec,
51
49
  CODEC_DEFLATE,
52
50
  CODEC_INFLATE,
53
51
  ERR_INVALID_SIGNATURE,
@@ -56,34 +54,25 @@ export {
56
54
  MESSAGE_START,
57
55
  MESSAGE_PULL,
58
56
  MESSAGE_DATA,
59
- MESSAGE_ABORT,
60
57
  MESSAGE_CLOSE,
61
58
  ERR_ABORT
62
59
  };
63
60
 
64
- function createCodec(codecConstructor, readable, writable, options, config) {
65
- const controller = new AbortController();
66
- const { signal } = controller;
67
- if (options.codecType.startsWith(CODEC_DEFLATE)) {
68
- return {
69
- run: () => run(DeflateStream),
70
- abort
71
- };
72
- } else if (options.codecType.startsWith(CODEC_INFLATE)) {
73
- return {
74
- run: () => run(InflateStream),
75
- abort
76
- };
77
- }
61
+ class Codec {
78
62
 
79
- async function run(StreamConstructor) {
80
- const stream = new StreamConstructor(codecConstructor, options, config);
81
- await readable.pipeThrough(stream, { signal }).pipeTo(writable, { preventClose: true });
82
- const { length, signature } = stream;
83
- return { length, signature };
84
- }
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
+ }
85
70
 
86
- function abort() {
87
- controller.abort();
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
+ }
88
77
  }
89
78
  }
@@ -29,62 +29,65 @@
29
29
  /* global Worker, URL, TransformStream */
30
30
 
31
31
  import {
32
- createCodec,
32
+ Codec,
33
33
  MESSAGE_EVENT_TYPE,
34
34
  MESSAGE_START,
35
35
  MESSAGE_PULL,
36
36
  MESSAGE_DATA,
37
- MESSAGE_ABORT,
38
37
  MESSAGE_CLOSE
39
38
  } from "./codec-interface.js";
40
39
 
41
40
  let classicWorkersSupported = true;
42
41
 
43
42
  export {
44
- getWorker
43
+ CodecWorker
45
44
  };
46
45
 
47
- function getWorker(workerData, stream, workerOptions, onTaskFinished) {
48
- const { readable, writable } = stream;
49
- const { options, config, streamOptions, webWorker, scripts, codecConstructor } = workerOptions;
50
- Object.assign(workerData, {
51
- busy: true,
52
- codecConstructor,
53
- readable,
54
- writable,
55
- options: Object.assign({}, options),
56
- scripts,
57
- terminate() {
58
- if (workerData.worker && !workerData.busy) {
59
- workerData.worker.terminate();
60
- workerData.interface = null;
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);
61
67
  }
62
- },
63
- onTaskFinished() {
64
- workerData.busy = false;
65
- onTaskFinished(workerData);
66
- }
67
- });
68
- const { signal, size, onstart, onprogress, onend } = streamOptions;
69
- if (signal || onstart || onprogress || onend) {
68
+ });
69
+ const { signal, onstart, onprogress, size, onend } = streamOptions;
70
70
  let chunkOffset = 0;
71
71
  const transformer = {};
72
72
  if (onstart) {
73
73
  transformer.start = () => callHandler(onstart, size());
74
74
  }
75
- if (onprogress) {
76
- transformer.transform = async (chunk, controller) => {
77
- chunkOffset += chunk.length;
75
+ transformer.transform = async (chunk, controller) => {
76
+ chunkOffset += chunk.length;
77
+ if (onprogress) {
78
78
  await callHandler(onprogress, chunkOffset, size());
79
- controller.enqueue(chunk);
80
- };
81
- }
82
- if (onend) {
83
- transformer.flush = () => callHandler(onend);
84
- }
79
+ }
80
+ controller.enqueue(chunk);
81
+ };
82
+ transformer.flush = () => {
83
+ readable.size = () => chunkOffset;
84
+ if (onend) {
85
+ callHandler(onend, chunkOffset);
86
+ }
87
+ };
85
88
  workerData.readable = readable.pipeThrough(new TransformStream(transformer, { highWaterMark: 1, size: () => config.chunkSize }), { signal });
89
+ return webWorker ? createWebWorkerInterface(workerData, config) : createWorkerInterface(workerData, config);
86
90
  }
87
- return webWorker ? createWebWorkerInterface(workerData, config) : createWorkerInterface(workerData, config);
88
91
  }
89
92
 
90
93
  async function callHandler(handler, ...parameters) {
@@ -96,17 +99,15 @@ async function callHandler(handler, ...parameters) {
96
99
  }
97
100
 
98
101
  function createWorkerInterface(workerData, config) {
99
- const interfaceCodec = createCodec(workerData.codecConstructor, workerData.readable, workerData.writable, workerData.options, config);
102
+ const interfaceCodec = new Codec(workerData.codecConstructor, workerData.readable, workerData.writable, workerData.options, config);
100
103
  const { onTaskFinished } = workerData;
101
104
  const codec = {
102
- abort() {
103
- interfaceCodec.abort();
104
- onTaskFinished();
105
- },
106
105
  async run() {
107
- const result = await interfaceCodec.run();
108
- onTaskFinished();
109
- return result;
106
+ try {
107
+ return await interfaceCodec.run();
108
+ } finally {
109
+ onTaskFinished();
110
+ }
110
111
  }
111
112
  };
112
113
  return codec;
@@ -121,8 +122,7 @@ function createWebWorkerInterface(workerData, { baseURL, chunkSize }) {
121
122
  result: new Promise((resolve, reject) => {
122
123
  workerData.resolveResult = resolve;
123
124
  workerData.rejectResult = reject;
124
- }),
125
- aborted: false
125
+ })
126
126
  });
127
127
  if (!workerData.interface) {
128
128
  if (!classicWorkersSupported) {
@@ -137,12 +137,6 @@ function createWebWorkerInterface(workerData, { baseURL, chunkSize }) {
137
137
  }
138
138
  workerData.worker.addEventListener(MESSAGE_EVENT_TYPE, onMessage, false);
139
139
  workerData.interface = {
140
- abort() {
141
- workerData.aborted = true;
142
- sendMessage({ type: MESSAGE_ABORT });
143
- workerData.writer.releaseLock();
144
- workerData.onTaskFinished();
145
- },
146
140
  run() {
147
141
  const { options } = workerData;
148
142
  const scripts = workerData.scripts.slice(1);
@@ -221,7 +215,7 @@ function createWebWorkerInterface(workerData, { baseURL, chunkSize }) {
221
215
  }
222
216
 
223
217
  function close(error, result) {
224
- if (error && !workerData.aborted) {
218
+ if (error) {
225
219
  rejectResult(error);
226
220
  } else {
227
221
  resolveResult(result);
@@ -35,7 +35,7 @@ import {
35
35
  ERR_INVALID_PASSWORD,
36
36
  ERR_ABORT
37
37
  } from "./codec-interface.js";
38
- import { getWorker } from "./codec-pool-worker.js";
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 codec;
63
+ let worker;
64
64
  if (pool.length < config.maxWorkers) {
65
65
  const workerData = { indexWorker };
66
66
  indexWorker++;
67
67
  pool.push(workerData);
68
- codec = getWorker(workerData, stream, workerOptions, onTaskFinished);
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
- codec = getWorker(workerData, stream, workerOptions, onTaskFinished);
73
+ worker = new CodecWorker(workerData, stream, workerOptions, onTaskFinished);
74
74
  } else {
75
- codec = await new Promise(resolve => pendingRequests.push({ resolve, stream, workerOptions }));
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 codec.run(signal);
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(getWorker(workerData, stream, workerOptions, onTaskFinished));
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
@@ -55,13 +55,14 @@ class Stream {
55
55
 
56
56
  class Reader extends Stream {
57
57
 
58
- getReadable({ offset, size, chunkSize } = { offset: 0, chunkSize: DEFAULT_CHUNK_SIZE }) {
58
+ get readable() {
59
59
  const reader = this;
60
- return new ReadableStream({
60
+ const readable = new ReadableStream({
61
61
  start() {
62
62
  this.chunkOffset = 0;
63
63
  },
64
64
  async pull(controller) {
65
+ const { offset = 0, chunkSize = DEFAULT_CHUNK_SIZE, size } = readable;
65
66
  const { chunkOffset } = this;
66
67
  controller.enqueue(await reader.readUint8Array(offset + chunkOffset, Math.min(chunkSize, size() - chunkOffset)));
67
68
  if (chunkOffset + chunkSize > size()) {
@@ -71,6 +72,7 @@ class Reader extends Stream {
71
72
  }
72
73
  }
73
74
  });
75
+ return readable;
74
76
  }
75
77
  }
76
78
 
@@ -247,30 +249,13 @@ function flushArrayBuffers(blobWriter) {
247
249
  blobWriter.arrayBuffers = [];
248
250
  }
249
251
 
250
- class ReadableStreamReader {
252
+ class ReadableStreamReader extends Stream {
251
253
 
252
254
  constructor(readable) {
253
- const reader = this;
255
+ super();
254
256
  if (!readable) {
255
- readable = new ReadableStream({});
257
+ this.readable = new ReadableStream({});
256
258
  }
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
259
  }
275
260
  }
276
261
 
@@ -288,15 +273,6 @@ class WritableStreamWriter extends Writer {
288
273
  }
289
274
  });
290
275
  }
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
276
  }
301
277
 
302
278
  class FetchReader extends Reader {
@@ -29,14 +29,13 @@
29
29
  /* global self, importScripts, addEventListener, postMessage, ReadableStream, WritableStream */
30
30
 
31
31
  import {
32
- createCodec,
32
+ Codec,
33
33
  CODEC_DEFLATE,
34
34
  CODEC_INFLATE,
35
35
  MESSAGE_EVENT_TYPE,
36
36
  MESSAGE_START,
37
37
  MESSAGE_PULL,
38
38
  MESSAGE_DATA,
39
- MESSAGE_ABORT,
40
39
  MESSAGE_CLOSE
41
40
  } from "./codec-interface.js";
42
41
 
@@ -56,9 +55,6 @@ addEventListener(MESSAGE_EVENT_TYPE, async event => {
56
55
  pendingMessages.delete(messageId);
57
56
  resolve({ value: new Uint8Array(data), done });
58
57
  }
59
- if (type == MESSAGE_ABORT) {
60
- codec.abort();
61
- }
62
58
  } catch (error) {
63
59
  postMessage({ error: { message: error.message, stack: error.stack } });
64
60
  }
@@ -98,7 +94,7 @@ async function init(message) {
98
94
  sendMessage({ type: MESSAGE_DATA, data });
99
95
  }
100
96
  }, strategy);
101
- codec = createCodec(codecConstructor, readable, writable, options, config);
97
+ codec = new Codec(codecConstructor, readable, writable, options, config);
102
98
  const result = await codec.run();
103
99
  sendMessage({ type: MESSAGE_CLOSE, result });
104
100
 
@@ -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;
@@ -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.getReadable({ offset: dataOffset, size, chunkSize: getChunkSize(config) });
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
- return writer.getData();
330
+ if (!writer.preventClose) {
331
+ await writable.getWriter().close();
332
+ }
333
+ return writer.getData ? writer.getData() : writable;
331
334
  }
332
335
  }
333
336
 
@@ -126,11 +126,16 @@ class ZipWriter {
126
126
  }
127
127
 
128
128
  async close(comment = new Uint8Array(), options = {}) {
129
- while (this.pendingAddFileCalls.size) {
130
- await Promise.all(Array.from(this.pendingAddFileCalls));
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
- return this.writer.getData();
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
- uncompressedSize = reader.size;
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;
@@ -305,7 +314,7 @@ async function getFileEntry(zipWriter, name, reader, options) {
305
314
  bufferedWrite = true;
306
315
  } else {
307
316
  zipWriter.lockWrite = new Promise(resolve => resolveLockUnbufferedWrite = resolve);
308
- if (!writer.initialized) {
317
+ if (writer.init && !writer.initialized) {
309
318
  await writer.init();
310
319
  }
311
320
  fileWriter = writer;
@@ -524,7 +533,9 @@ async function createFileEntry(reader, writable, config, options) {
524
533
  await writeUint8Array(writable, localHeaderArray);
525
534
  fileEntry.dataWritten = true;
526
535
  const size = () => reader.size;
527
- const readable = reader.getReadable({ offset: 0, size, chunkSize: getChunkSize(config) });
536
+ const readable = reader.readable;
537
+ readable.size = size;
538
+ readable.chunkSize = getChunkSize(config);
528
539
  const workerOptions = {
529
540
  options: {
530
541
  codecType: CODEC_DEFLATE,
@@ -544,7 +555,7 @@ async function createFileEntry(reader, writable, config, options) {
544
555
  codecConstructor: config.Deflate
545
556
  };
546
557
  result = await runWorker({ readable, writable }, workerOptions);
547
- uncompressedSize = fileEntry.uncompressedSize = reader.size;
558
+ uncompressedSize = fileEntry.uncompressedSize = reader.size = readable.size();
548
559
  compressedSize = result.length;
549
560
  } else {
550
561
  await writeUint8Array(writable, localHeaderArray);