@zip.js/zip.js 2.6.5 → 2.6.8

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/lib/core/io.js CHANGED
@@ -519,7 +519,14 @@ function isHttpFamily(url) {
519
519
  return protocol == "http:" || protocol == "https:";
520
520
  }
521
521
 
522
+ async function initStream(stream) {
523
+ if (stream.init && !stream.initialized) {
524
+ await stream.init();
525
+ }
526
+ }
527
+
522
528
  export {
529
+ initStream,
523
530
  Reader,
524
531
  Writer,
525
532
  TextReader,
@@ -26,7 +26,10 @@
26
26
  EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
27
  */
28
28
 
29
+ /* global WritableStream */
30
+
29
31
  import {
32
+ initStream,
30
33
  Reader,
31
34
  TextReader,
32
35
  TextWriter,
@@ -38,10 +41,12 @@ import {
38
41
  BlobWriter,
39
42
  HttpReader
40
43
  } from "./io.js";
41
- import { ZipReader } from "./zip-reader.js";
42
- import { ZipWriter } from "./zip-writer.js";
43
-
44
- const CHUNK_SIZE = 512 * 1024;
44
+ import {
45
+ ZipReader
46
+ } from "./zip-reader.js";
47
+ import {
48
+ ZipWriter
49
+ } from "./zip-writer.js";
45
50
 
46
51
  class ZipEntry {
47
52
 
@@ -115,13 +120,13 @@ class ZipFileEntry extends ZipEntry {
115
120
  if (!writer || (writer.constructor == zipEntry.Writer && zipEntry.data)) {
116
121
  return zipEntry.data;
117
122
  } else {
118
- zipEntry.reader = new zipEntry.Reader(zipEntry.data, options);
119
- await zipEntry.reader.init();
120
- if (writer.init && !writer.initialized) {
121
- await writer.init();
122
- }
123
- zipEntry.uncompressedSize = zipEntry.reader.size;
124
- return pipe(zipEntry.reader, writer);
123
+ const reader = zipEntry.reader = new zipEntry.Reader(zipEntry.data, options);
124
+ await Promise.all([initStream(reader), initStream(writer)]);
125
+ zipEntry.uncompressedSize = reader.size;
126
+ const readable = reader.readable;
127
+ readable.size = () => reader.size;
128
+ await readable.pipeTo(writer.writable);
129
+ return writer.getData ? writer.getData() : writer.writable;
125
130
  }
126
131
  }
127
132
 
@@ -141,6 +146,10 @@ class ZipFileEntry extends ZipEntry {
141
146
  return this.getData(new Uint8ArrayWriter(), options);
142
147
  }
143
148
 
149
+ getWritable(writable = new WritableStream(), options) {
150
+ return this.getData({ writable }, options);
151
+ }
152
+
144
153
  replaceBlob(blob) {
145
154
  Object.assign(this, {
146
155
  data: blob,
@@ -176,6 +185,15 @@ class ZipFileEntry extends ZipEntry {
176
185
  reader: null
177
186
  });
178
187
  }
188
+
189
+ replaceReadable(readable) {
190
+ Object.assign(this, {
191
+ data: null,
192
+ Reader: function () { return { readable }; },
193
+ Writer: null,
194
+ reader: null
195
+ });
196
+ }
179
197
  }
180
198
 
181
199
  class ZipDirectoryEntry extends ZipEntry {
@@ -232,6 +250,12 @@ class ZipDirectoryEntry extends ZipEntry {
232
250
  });
233
251
  }
234
252
 
253
+ addReadable(name, readable) {
254
+ return addChild(this, name, {
255
+ Reader: function () { return { readable }; }
256
+ });
257
+ }
258
+
235
259
  addFileSystemEntry(fileSystemEntry) {
236
260
  return addFileSystemEntry(this, fileSystemEntry);
237
261
  }
@@ -256,6 +280,10 @@ class ZipDirectoryEntry extends ZipEntry {
256
280
  await this.importZip(new HttpReader(url, options), options);
257
281
  }
258
282
 
283
+ async importReadable(readable, options = {}) {
284
+ await this.importZip({ readable }, options);
285
+ }
286
+
259
287
  exportBlob(options = {}) {
260
288
  return this.exportZip(new BlobWriter("application/zip"), options);
261
289
  }
@@ -268,10 +296,13 @@ class ZipDirectoryEntry extends ZipEntry {
268
296
  return this.exportZip(new Uint8ArrayWriter(), options);
269
297
  }
270
298
 
299
+ async exportWritable(writable = new WritableStream(), options = {}) {
300
+ await this.exportZip({ writable }, options);
301
+ return writable;
302
+ }
303
+
271
304
  async importZip(reader, options) {
272
- if (!reader.initialized) {
273
- await reader.init();
274
- }
305
+ await initStream(reader);
275
306
  const zipReader = new ZipReader(reader, options);
276
307
  const entries = await zipReader.getEntries();
277
308
  entries.forEach((entry) => {
@@ -290,12 +321,11 @@ class ZipDirectoryEntry extends ZipEntry {
290
321
 
291
322
  async exportZip(writer, options) {
292
323
  const zipEntry = this;
293
- await initReaders(zipEntry);
294
- await writer.init();
324
+ await Promise.all([initReaders(zipEntry), initStream(writer)]);
295
325
  const zipWriter = new ZipWriter(writer, options);
296
326
  await exportZip(zipWriter, zipEntry, getTotalSize([zipEntry], "uncompressedSize"), options);
297
327
  await zipWriter.close();
298
- return writer.getData();
328
+ return writer.getData ? writer.getData() : writer.writable;
299
329
  }
300
330
 
301
331
  getChildByName(name) {
@@ -385,6 +415,10 @@ class FS {
385
415
  return this.root.addHttpContent(name, url, options);
386
416
  }
387
417
 
418
+ addReadable(name, readable) {
419
+ return this.root.addReadable(name, readable);
420
+ }
421
+
388
422
  addFileSystemEntry(fileSystemEntry) {
389
423
  return this.root.addFileSystemEntry(fileSystemEntry);
390
424
  }
@@ -408,6 +442,11 @@ class FS {
408
442
  await this.root.importHttpContent(url, options);
409
443
  }
410
444
 
445
+ async importReadable(readable, options) {
446
+ resetFS(this);
447
+ await this.root.importReadable(readable, options);
448
+ }
449
+
411
450
  exportBlob(options) {
412
451
  return this.root.exportBlob(options);
413
452
  }
@@ -415,6 +454,14 @@ class FS {
415
454
  exportData64URI(options) {
416
455
  return this.root.exportData64URI(options);
417
456
  }
457
+
458
+ exportUint8Array(options) {
459
+ return this.root.exportUint8Array(options);
460
+ }
461
+
462
+ exportWritable(writable, options) {
463
+ return this.root.exportWritable(writable, options);
464
+ }
418
465
  }
419
466
 
420
467
  const fs = { FS, ZipDirectoryEntry, ZipFileEntry };
@@ -443,6 +490,7 @@ function getZipBlobReader(options) {
443
490
  }
444
491
 
445
492
  async init() {
493
+ super.init();
446
494
  const zipBlobReader = this;
447
495
  zipBlobReader.size = zipBlobReader.entry.uncompressedSize;
448
496
  const data = await zipBlobReader.entry.getData(new BlobWriter(), Object.assign({}, zipBlobReader.options, options));
@@ -462,9 +510,9 @@ async function initReaders(entry) {
462
510
  if (child.directory) {
463
511
  await initReaders(child);
464
512
  } else {
465
- child.reader = new child.Reader(child.data);
466
- await child.reader.init();
467
- child.uncompressedSize = child.reader.size;
513
+ const reader = child.reader = new child.Reader(child.data);
514
+ await initStream(reader);
515
+ child.uncompressedSize = reader.size;
468
516
  }
469
517
  }
470
518
  }
@@ -573,21 +621,6 @@ function resetFS(fs) {
573
621
  fs.root = new ZipDirectoryEntry(fs);
574
622
  }
575
623
 
576
- function pipe(reader, writer) {
577
- return copyChunk();
578
-
579
- async function copyChunk(chunkIndex = 0) {
580
- const index = chunkIndex * CHUNK_SIZE;
581
- if (index < reader.size) {
582
- const array = await reader.readUint8Array(index, Math.min(CHUNK_SIZE, reader.size - index));
583
- await writer.writeUint8Array(array);
584
- return copyChunk(chunkIndex + 1);
585
- } else {
586
- return writer.getData();
587
- }
588
- }
589
- }
590
-
591
624
  function addChild(parent, name, params, directory) {
592
625
  if (parent.directory) {
593
626
  return directory ? new ZipDirectoryEntry(parent.fs, name, params, parent) : new ZipFileEntry(parent.fs, name, params, parent);
@@ -66,7 +66,10 @@ import {
66
66
  ERR_INVALID_SIGNATURE,
67
67
  ERR_INVALID_PASSWORD
68
68
  } from "./codec-pool.js";
69
- import { BlobReader } from "./io.js";
69
+ import {
70
+ initStream,
71
+ BlobReader
72
+ } from "./io.js";
70
73
  import decodeText from "./util/decode-text.js";
71
74
  import Crc32 from "./streams/codecs/crc32.js";
72
75
  import Entry from "./zip-entry.js";
@@ -99,9 +102,7 @@ class ZipReader {
99
102
  const zipReader = this;
100
103
  let { reader } = zipReader;
101
104
  const { config } = zipReader;
102
- if (!reader.initialized && reader.init) {
103
- await reader.init();
104
- }
105
+ await initStream(reader);
105
106
  if (reader.size === undefined || !reader.readUint8Array) {
106
107
  const blob = await new Response(reader.readable).blob();
107
108
  reader = new BlobReader(blob);
@@ -167,7 +168,7 @@ class ZipReader {
167
168
  throw new Error(ERR_BAD_FORMAT);
168
169
  }
169
170
  const filenameEncoding = getOptionValue(zipReader, options, "filenameEncoding");
170
- const commentEncoding = getOptionValue(zipReader, options, "commentEncoding");
171
+ const commentEncoding = getOptionValue(zipReader, options, "commentEncoding");
171
172
  for (let indexFile = 0; indexFile < filesLength; indexFile++) {
172
173
  const fileEntry = new ZipEntry(reader, config, zipReader.options);
173
174
  if (getUint32(directoryView, offset) != CENTRAL_FILE_HEADER_SIGNATURE) {
@@ -188,7 +189,7 @@ class ZipReader {
188
189
  commentLength: getUint16(directoryView, offset + 32),
189
190
  directory: msDosCompatible && ((getUint8(directoryView, offset + 38) & FILE_ATTR_MSDOS_DIR_MASK) == FILE_ATTR_MSDOS_DIR_MASK),
190
191
  offset: getUint32(directoryView, offset + 42) + prependedDataLength,
191
- internalFileAttribute: getUint32(directoryView, offset + 34),
192
+ internalFileAttribute: getUint16(directoryView, offset + 36),
192
193
  externalFileAttribute: getUint32(directoryView, offset + 38),
193
194
  rawFilename: directoryArray.subarray(filenameOffset, extraFieldOffset),
194
195
  filenameUTF8: languageEncodingFlag,
@@ -321,9 +322,7 @@ class ZipEntry {
321
322
  readable.size = size;
322
323
  const { writable } = writer;
323
324
  const signal = getOptionValue(zipEntry, options, "signal");
324
- if (writer.init && !writer.initialized) {
325
- await writer.init();
326
- }
325
+ await initStream(writer);
327
326
  const { onstart, onprogress, onend } = options;
328
327
  const workerOptions = {
329
328
  options: {
@@ -69,6 +69,7 @@ import {
69
69
  } from "./codec-pool.js";
70
70
  import encodeText from "./util/encode-text.js";
71
71
  import {
72
+ initStream,
72
73
  BlobWriter
73
74
  } from "./io.js";
74
75
  import Entry from "./zip-entry.js";
@@ -232,9 +233,7 @@ async function addFile(zipWriter, name, reader, options) {
232
233
  const internalFileAttribute = getOptionValue(zipWriter, options, "internalFileAttribute") || 0;
233
234
  const externalFileAttribute = getOptionValue(zipWriter, options, "externalFileAttribute") || 0;
234
235
  if (reader) {
235
- if (reader.init && !reader.initialized) {
236
- await reader.init();
237
- }
236
+ await initStream(reader);
238
237
  if (reader.size === undefined) {
239
238
  options.dataDescriptor = true;
240
239
  } else {
@@ -331,9 +330,7 @@ async function getFileEntry(zipWriter, name, reader, options) {
331
330
  bufferedWrite = true;
332
331
  } else {
333
332
  zipWriter.lockWriter = Promise.resolve();
334
- if (writer.init && !writer.initialized) {
335
- await writer.init();
336
- }
333
+ await initStream(writer);
337
334
  fileWriter = writer;
338
335
  }
339
336
  fileEntry = await createFileEntry(reader, fileEntry, fileWriter.writable, zipWriter.config, options);
@@ -359,7 +356,7 @@ async function getFileEntry(zipWriter, name, reader, options) {
359
356
  setUint32(arrayBufferView, 18, fileEntry.compressedSize);
360
357
  setUint32(arrayBufferView, 22, fileEntry.uncompressedSize);
361
358
  }
362
- await writeUint8Array(writable, new Uint8Array(arrayBuffer));
359
+ await writeData(writable, new Uint8Array(arrayBuffer));
363
360
  blob = blob.slice(headerLength);
364
361
  }
365
362
  await blob.stream().pipeTo(writable, { preventClose: true, signal });
@@ -479,6 +476,7 @@ async function createFileEntry(reader, pendingFileEntry, writable, config, optio
479
476
  rawExtraFieldNTFS = rawExtraFieldExtendedTimestamp = new Uint8Array();
480
477
  }
481
478
  const fileEntry = {
479
+ lock: pendingFileEntry.lock,
482
480
  version: version || VERSION_DEFLATE,
483
481
  versionMadeBy,
484
482
  zip64,
@@ -555,7 +553,7 @@ async function createFileEntry(reader, pendingFileEntry, writable, config, optio
555
553
  let compressedSize = 0;
556
554
  if (reader) {
557
555
  reader.chunkSize = getChunkSize(config);
558
- await writeUint8Array(writable, localHeaderArray);
556
+ await writeData(writable, localHeaderArray);
559
557
  fileEntry.dataWritten = pendingFileEntry.dataWritten = true;
560
558
  const size = () => reader.size;
561
559
  const readable = reader.readable;
@@ -582,7 +580,7 @@ async function createFileEntry(reader, pendingFileEntry, writable, config, optio
582
580
  uncompressedSize = fileEntry.uncompressedSize = reader.size = readable.size();
583
581
  compressedSize = result.size;
584
582
  } else {
585
- await writeUint8Array(writable, localHeaderArray);
583
+ await writeData(writable, localHeaderArray);
586
584
  fileEntry.dataWritten = pendingFileEntry.dataWritten = true;
587
585
  }
588
586
  let dataDescriptorArray = new Uint8Array();
@@ -626,7 +624,7 @@ async function createFileEntry(reader, pendingFileEntry, writable, config, optio
626
624
  }
627
625
  }
628
626
  if (dataDescriptor) {
629
- await writeUint8Array(writable, dataDescriptorArray);
627
+ await writeData(writable, dataDescriptorArray);
630
628
  }
631
629
  const length = localHeaderArray.length + compressedSize + dataDescriptorArray.length;
632
630
  Object.assign(fileEntry, {
@@ -701,7 +699,7 @@ async function closeFile(zipWriter, comment, options) {
701
699
  arraySet(directoryArray, headerArray, offset + 6);
702
700
  setUint16(directoryView, offset + 30, extraFieldLength);
703
701
  setUint16(directoryView, offset + 32, rawComment.length);
704
- setUint32(directoryView, offset + 34, internalFileAttribute);
702
+ setUint16(directoryView, offset + 36, internalFileAttribute);
705
703
  if (externalFileAttribute) {
706
704
  setUint32(directoryView, offset + 38, externalFileAttribute);
707
705
  } else if (directory && msDosCompatible) {
@@ -758,9 +756,9 @@ async function closeFile(zipWriter, comment, options) {
758
756
  }
759
757
  }
760
758
  const { writable } = zipWriter.writer;
761
- await writeUint8Array(writable, directoryArray);
759
+ await writeData(writable, directoryArray);
762
760
  if (comment && comment.length) {
763
- await writeUint8Array(writable, comment);
761
+ await writeData(writable, comment);
764
762
  }
765
763
  }
766
764
 
@@ -772,7 +770,7 @@ function sliceAsArrayBuffer(blob, start, end) {
772
770
  }
773
771
  }
774
772
 
775
- async function writeUint8Array(writable, array) {
773
+ async function writeData(writable, array) {
776
774
  const streamWriter = writable.getWriter();
777
775
  await streamWriter.ready;
778
776
  await streamWriter.write(array);
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "description": "A JavaScript library to zip and unzip files in the browser and Deno",
4
4
  "author": "Gildas Lormeau",
5
5
  "license": "BSD-3-Clause",
6
- "version": "2.6.5",
6
+ "version": "2.6.8",
7
7
  "type": "module",
8
8
  "keywords": [
9
9
  "zip",
@@ -17,12 +17,14 @@
17
17
  "encryption",
18
18
  "zip64",
19
19
  "web-streams",
20
+ "compression-streams",
20
21
  "web-crypto",
21
22
  "web-workers",
22
23
  "deno"
23
24
  ],
24
25
  "scripts": {
25
26
  "build": "./build.sh",
27
+ "dev": "npx rollup -c rollup.config.dev.js",
26
28
  "test": "cd ./tests && \"./run-tests.sh\""
27
29
  },
28
30
  "main": "index.js",
@@ -38,7 +40,8 @@
38
40
  "devDependencies": {
39
41
  "@rollup/plugin-node-resolve": "^13.3.0",
40
42
  "@rollup/plugin-replace": "^4.0.0",
41
- "rollup": "^2.77.0",
42
- "rollup-plugin-terser": "^7.0.2"
43
+ "rollup": "^2.77.2",
44
+ "rollup-plugin-terser": "^7.0.2",
45
+ "typedoc": "^0.23.10"
43
46
  }
44
47
  }
@@ -0,0 +1,22 @@
1
+ /* global Blob, TransformStream, Response */
2
+
3
+ import * as zip from "../../index.js";
4
+
5
+ const TEXT_CONTENT = "Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Typi non habent claritatem insitam; est usus legentis in iis qui facit eorum claritatem. Investigationes demonstraverunt lectores legere me lius quod ii legunt saepius. Claritas est etiam processus dynamicus, qui sequitur mutationem consuetudium lectorum. Mirum est notare quam littera gothica, quam nunc putamus parum claram, anteposuerit litterarum formas humanitatis per seacula quarta decima et quinta decima. Eodem modo typi, qui nunc nobis videntur parum clari, fiant sollemnes in futurum.";
6
+ const FILENAME = "lorem.txt";
7
+
8
+ export { test };
9
+
10
+ async function test() {
11
+ zip.configure({ chunkSize: 128, useWebWorkers: true });
12
+ const sourceFS = new zip.fs.FS();
13
+ sourceFS.addReadable(FILENAME, new Blob([TEXT_CONTENT]).stream());
14
+ let transformStream = new TransformStream();
15
+ const destinationFS = new zip.fs.FS();
16
+ await Promise.all([sourceFS.exportWritable(transformStream.writable), destinationFS.importReadable(transformStream.readable)]);
17
+ const firstEntry = destinationFS.children[0];
18
+ transformStream = new TransformStream();
19
+ const [text] = await Promise.all([new Response(transformStream.readable).text(), firstEntry.getWritable(transformStream.writable)]);
20
+ zip.terminateWorkers();
21
+ return text == TEXT_CONTENT && firstEntry.name == FILENAME && firstEntry.uncompressedSize == TEXT_CONTENT.length;
22
+ }
@@ -4,14 +4,14 @@ import * as zip from "../../index.js";
4
4
 
5
5
  const KB = 1024;
6
6
  const ENTRIES_DATA = [
7
- { name: "entry #1", blob: getBlob(8.5 * KB) }, { name: "entry #2", blob: getBlob(10.2 * KB) }, { name: "entry #3", blob: getBlob(64.7 * KB) },
8
- { name: "entry #4", blob: getBlob(2.8 * KB) }, { name: "entry #5", blob: getBlob(30.9 * KB) }, { name: "entry #6", blob: getBlob(76.2 * KB) },
9
- { name: "entry #7", blob: getBlob(5.1 * KB) }, { name: "entry #8", blob: getBlob(42.6 * KB) }, { name: "entry #9", blob: getBlob(3.1 * KB) }];
7
+ { name: "entry #1", blob: getBlob(8.5 * KB) }, { name: "entry #2", blob: getBlob(100.2 * KB) }, { name: "entry #3", blob: getBlob(640.7 * KB) },
8
+ { name: "entry #4", blob: getBlob(200.8 * KB) }, { name: "entry #5", blob: getBlob(3.9 * KB) }, { name: "entry #6", blob: getBlob(7.2 * KB) },
9
+ { name: "entry #7", blob: getBlob(5.1 * KB) }, { name: "entry #8", blob: getBlob(4.6 * KB) }, { name: "entry #9", blob: getBlob(3.1 * KB) }];
10
10
 
11
11
  export { test };
12
12
 
13
13
  async function test() {
14
- zip.configure({ chunkSize: 512, useWebWorkers: true });
14
+ zip.configure({ chunkSize: 512, useWebWorkers: true, maxWorkers: 4 });
15
15
  const blobWriter = new zip.BlobWriter("application/zip");
16
16
  const zipWriter = new zip.ZipWriter(blobWriter, { keepOrder: true });
17
17
  await Promise.all(ENTRIES_DATA.map(entryData => zipWriter.add(entryData.name, new zip.BlobReader(entryData.blob))));
@@ -19,6 +19,7 @@ export default ([
19
19
  { title: "Filesystem HTTP import", script: "./test-fs-http-import.js" },
20
20
  { title: "Filesystem HTTP reader", script: "./test-fs-http-reader.js" },
21
21
  { title: "Filesystem replace entry", script: "./test-fs-replace.js" },
22
+ { title: "Filesystem streams", script: "./test-fs-streams.js" },
22
23
  { title: "Filesystem text", script: "./test-fs-text.js" },
23
24
  { title: "Filesystem unzip uncompressed file", script: "./test-fs-unzip-store.js" },
24
25
  { title: "Filesystem test", script: "./test-fs.js" },
@@ -17,8 +17,8 @@ if (!location.search.startsWith("?keepTests")) {
17
17
  if (!result.error) {
18
18
  Array.from(document.querySelectorAll("tr")).find(row => row.dataset.script == result.script).remove();
19
19
  }
20
- indexTest++;
21
20
  const test = tests[indexTest];
21
+ indexTest++;
22
22
  if (test) {
23
23
  addTest(test);
24
24
  } else if (!document.querySelectorAll("tr").length) {
package/tsconfig.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "typedocOptions": {
3
+ "entryPoints": ["index.d.ts"],
4
+ "out": "../doc/api"
5
+ }
6
+ }