@zip.js/zip.js 2.7.64 → 2.7.66

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.
@@ -57,7 +57,7 @@ class CodecWorker {
57
57
  busy: true,
58
58
  readable: readable
59
59
  .pipeThrough(new ChunkStream(config.chunkSize))
60
- .pipeThrough(new ProgressWatcherStream(readable, streamOptions), { signal }),
60
+ .pipeThrough(new ProgressWatcherStream(streamOptions), { signal }),
61
61
  writable,
62
62
  options: Object.assign({}, options),
63
63
  scripts,
@@ -96,7 +96,7 @@ class CodecWorker {
96
96
 
97
97
  class ProgressWatcherStream extends TransformStream {
98
98
 
99
- constructor(readableSource, { onstart, onprogress, size, onend }) {
99
+ constructor({ onstart, onprogress, size, onend }) {
100
100
  let chunkOffset = 0;
101
101
  super({
102
102
  async start() {
@@ -112,7 +112,6 @@ class ProgressWatcherStream extends TransformStream {
112
112
  controller.enqueue(chunk);
113
113
  },
114
114
  async flush() {
115
- readableSource.size = chunkOffset;
116
115
  if (onend) {
117
116
  await callHandler(onend, chunkOffset);
118
117
  }
@@ -158,8 +157,9 @@ function createWebWorkerInterface(workerData, config) {
158
157
  }
159
158
 
160
159
  async function runWorker({ options, readable, writable, onTaskFinished }, config) {
160
+ let codecStream;
161
161
  try {
162
- const codecStream = new CodecStream(options, config);
162
+ codecStream = new CodecStream(options, config);
163
163
  await readable.pipeThrough(codecStream).pipeTo(writable, { preventClose: true, preventAbort: true });
164
164
  const {
165
165
  signature,
@@ -171,6 +171,11 @@ async function runWorker({ options, readable, writable, onTaskFinished }, config
171
171
  inputSize,
172
172
  outputSize
173
173
  };
174
+ } catch (error) {
175
+ if (codecStream) {
176
+ error.outputSize = codecStream.outputSize;
177
+ }
178
+ throw error;
174
179
  } finally {
175
180
  onTaskFinished();
176
181
  }
@@ -314,9 +319,9 @@ async function onMessage({ data }, workerData) {
314
319
  const { reader, writer, resolveResult, rejectResult, onTaskFinished } = workerData;
315
320
  try {
316
321
  if (error) {
317
- const { message, stack, code, name } = error;
322
+ const { message, stack, code, name, outputSize } = error;
318
323
  const responseError = new Error(message);
319
- Object.assign(responseError, { stack, code, name });
324
+ Object.assign(responseError, { stack, code, name, outputSize });
320
325
  close(responseError);
321
326
  } else {
322
327
  if (type == MESSAGE_PULL) {
@@ -53,13 +53,16 @@ const EXTRAFIELD_TYPE_UNICODE_PATH = 0x7075;
53
53
  const EXTRAFIELD_TYPE_UNICODE_COMMENT = 0x6375;
54
54
  const EXTRAFIELD_TYPE_USDZ = 0x1986;
55
55
 
56
- const BITFLAG_ENCRYPTED = 0x01;
57
- const BITFLAG_LEVEL = 0x06;
58
- const BITFLAG_DATA_DESCRIPTOR = 0x0008;
59
- const BITFLAG_LANG_ENCODING_FLAG = 0x0800;
60
- const FILE_ATTR_MSDOS_DIR_MASK = 0x10;
61
- const FILE_ATTR_UNIX_TYPE_MASK = 0o170000;
62
- const FILE_ATTR_UNIX_TYPE_DIR = 0o040000;
56
+ const BITFLAG_ENCRYPTED = 0b1;
57
+ const BITFLAG_LEVEL = 0b0110;
58
+ const BITFLAG_LEVEL_MAX_MASK = 0b010;
59
+ const BITFLAG_LEVEL_FAST_MASK = 0b100;
60
+ const BITFLAG_LEVEL_SUPER_FAST_MASK = 0b110;
61
+ const BITFLAG_DATA_DESCRIPTOR = 0b1000;
62
+ const BITFLAG_LANG_ENCODING_FLAG = 0b100000000000;
63
+ const FILE_ATTR_MSDOS_DIR_MASK = 0b10000;
64
+ const FILE_ATTR_UNIX_TYPE_MASK = 0o170000;
65
+ const FILE_ATTR_UNIX_TYPE_DIR = 0o040000;
63
66
  const FILE_ATTR_UNIX_EXECUTABLE_MASK = 0o111;
64
67
  const FILE_ATTR_UNIX_DEFAULT_MASK = 0o644;
65
68
 
@@ -70,6 +73,9 @@ const VERSION_AES = 0x33;
70
73
  const DIRECTORY_SIGNATURE = "/";
71
74
 
72
75
  const HEADER_SIZE = 26;
76
+ const HEADER_OFFSET_SIGNATURE = 10;
77
+ const HEADER_OFFSET_COMPRESSED_SIZE = 14;
78
+ const HEADER_OFFSET_UNCOMPRESSED_SIZE = 18;
73
79
 
74
80
  const MAX_DATE = new Date(2107, 11, 31);
75
81
  const MIN_DATE = new Date(1980, 0, 1);
@@ -105,6 +111,9 @@ export {
105
111
  ZIP64_END_OF_CENTRAL_DIR_TOTAL_LENGTH,
106
112
  BITFLAG_ENCRYPTED,
107
113
  BITFLAG_LEVEL,
114
+ BITFLAG_LEVEL_MAX_MASK,
115
+ BITFLAG_LEVEL_FAST_MASK,
116
+ BITFLAG_LEVEL_SUPER_FAST_MASK,
108
117
  BITFLAG_DATA_DESCRIPTOR,
109
118
  BITFLAG_LANG_ENCODING_FLAG,
110
119
  FILE_ATTR_MSDOS_DIR_MASK,
@@ -116,6 +125,9 @@ export {
116
125
  VERSION_ZIP64,
117
126
  VERSION_AES,
118
127
  HEADER_SIZE,
128
+ HEADER_OFFSET_SIGNATURE,
129
+ HEADER_OFFSET_COMPRESSED_SIZE,
130
+ HEADER_OFFSET_UNCOMPRESSED_SIZE,
119
131
  DIRECTORY_SIGNATURE,
120
132
  MIN_DATE,
121
133
  MAX_DATE,
package/lib/core/io.js CHANGED
@@ -141,10 +141,16 @@ class Data64URIReader extends Reader {
141
141
  const start = Math.floor(offset / 3) * 4;
142
142
  const bytes = atob(dataURI.substring(start + dataStart, Math.ceil((offset + length) / 3) * 4 + dataStart));
143
143
  const delta = offset - Math.floor(start / 4) * 3;
144
- for (let indexByte = delta; indexByte < delta + length; indexByte++) {
144
+ let effectiveLength = 0;
145
+ for (let indexByte = delta; indexByte < delta + length && indexByte < bytes.length; indexByte++) {
145
146
  dataArray[indexByte - delta] = bytes.charCodeAt(indexByte);
147
+ effectiveLength++;
148
+ }
149
+ if (effectiveLength < dataArray.length) {
150
+ return dataArray.subarray(0, effectiveLength);
151
+ } else {
152
+ return dataArray;
146
153
  }
147
- return dataArray;
148
154
  }
149
155
  }
150
156
 
@@ -582,19 +588,28 @@ class SplitDataReader extends Reader {
582
588
  currentDiskNumber = readers.length - 1;
583
589
  }
584
590
  let currentReaderOffset = offset;
585
- while (currentReaderOffset >= readers[currentDiskNumber].size) {
591
+ while (readers[currentDiskNumber] && currentReaderOffset >= readers[currentDiskNumber].size) {
586
592
  currentReaderOffset -= readers[currentDiskNumber].size;
587
593
  currentDiskNumber++;
588
594
  }
589
595
  const currentReader = readers[currentDiskNumber];
590
- const currentReaderSize = currentReader.size;
591
- if (currentReaderOffset + length <= currentReaderSize) {
592
- result = await readUint8Array(currentReader, currentReaderOffset, length);
596
+ if (currentReader) {
597
+ const currentReaderSize = currentReader.size;
598
+ if (currentReaderOffset + length <= currentReaderSize) {
599
+ result = await readUint8Array(currentReader, currentReaderOffset, length);
600
+ } else {
601
+ const chunkLength = currentReaderSize - currentReaderOffset;
602
+ result = new Uint8Array(length);
603
+ const firstPart = await readUint8Array(currentReader, currentReaderOffset, chunkLength);
604
+ result.set(firstPart, 0);
605
+ const secondPart = await reader.readUint8Array(offset + chunkLength, length - chunkLength, diskNumber);
606
+ result.set(secondPart, chunkLength);
607
+ if (firstPart.length + secondPart.length < length) {
608
+ result = result.subarray(0, firstPart.length + secondPart.length);
609
+ }
610
+ }
593
611
  } else {
594
- const chunkLength = currentReaderSize - currentReaderOffset;
595
- result = new Uint8Array(length);
596
- result.set(await readUint8Array(currentReader, currentReaderOffset, chunkLength));
597
- result.set(await reader.readUint8Array(offset + chunkLength, length - chunkLength, diskNumber), chunkLength);
612
+ result = new Uint8Array();
598
613
  }
599
614
  reader.lastDiskNumber = Math.max(currentDiskNumber, reader.lastDiskNumber);
600
615
  return result;
@@ -634,12 +649,12 @@ class SplitDataWriter extends Stream {
634
649
  }
635
650
  await this.write(chunk);
636
651
  } else if (chunk.length >= availableSize) {
637
- await writeChunk(chunk.slice(0, availableSize));
652
+ await writeChunk(chunk.subarray(0, availableSize));
638
653
  await closeDisk();
639
654
  writer.diskOffset += diskSourceWriter.size;
640
655
  writer.diskNumber++;
641
656
  diskWriter = null;
642
- await this.write(chunk.slice(availableSize));
657
+ await this.write(chunk.subarray(availableSize));
643
658
  } else {
644
659
  await writeChunk(chunk);
645
660
  }
@@ -667,12 +682,52 @@ class SplitDataWriter extends Stream {
667
682
  }
668
683
 
669
684
  async function closeDisk() {
670
- diskWritable.size = diskSourceWriter.size;
671
685
  await diskWriter.close();
672
686
  }
673
687
  }
674
688
  }
675
689
 
690
+ class GenericReader {
691
+
692
+ constructor(reader) {
693
+ if (Array.isArray(reader)) {
694
+ reader = new SplitDataReader(reader);
695
+ }
696
+ if (reader instanceof ReadableStream) {
697
+ reader = {
698
+ readable: reader
699
+ };
700
+ }
701
+ return reader;
702
+ }
703
+ }
704
+
705
+ class GenericWriter {
706
+
707
+ constructor(writer) {
708
+ if (writer.writable === UNDEFINED_VALUE && typeof writer.next == FUNCTION_TYPE) {
709
+ writer = new SplitDataWriter(writer);
710
+ }
711
+ if (writer instanceof WritableStream) {
712
+ writer = {
713
+ writable: writer
714
+ };
715
+ }
716
+ if (writer.size === UNDEFINED_VALUE) {
717
+ writer.size = 0;
718
+ }
719
+ if (!(writer instanceof SplitDataWriter)) {
720
+ Object.assign(writer, {
721
+ diskNumber: 0,
722
+ diskOffset: 0,
723
+ availableSize: Infinity,
724
+ maxSize: Infinity
725
+ });
726
+ }
727
+ return writer;
728
+ }
729
+ }
730
+
676
731
  function isHttpFamily(url) {
677
732
  const { baseURL } = getConfiguration();
678
733
  const { protocol } = new URL(url, baseURL);
@@ -687,42 +742,6 @@ async function initStream(stream, initSize) {
687
742
  }
688
743
  }
689
744
 
690
- function initReader(reader) {
691
- if (Array.isArray(reader)) {
692
- reader = new SplitDataReader(reader);
693
- }
694
- if (reader instanceof ReadableStream) {
695
- reader = {
696
- readable: reader
697
- };
698
- }
699
- return reader;
700
- }
701
-
702
- function initWriter(writer) {
703
- if (writer.writable === UNDEFINED_VALUE && typeof writer.next == FUNCTION_TYPE) {
704
- writer = new SplitDataWriter(writer);
705
- }
706
- if (writer instanceof WritableStream) {
707
- writer = {
708
- writable: writer
709
- };
710
- }
711
- const { writable } = writer;
712
- if (writable.size === UNDEFINED_VALUE) {
713
- writable.size = 0;
714
- }
715
- if (!(writer instanceof SplitDataWriter)) {
716
- Object.assign(writer, {
717
- diskNumber: 0,
718
- diskOffset: 0,
719
- availableSize: Infinity,
720
- maxSize: Infinity
721
- });
722
- }
723
- return writer;
724
- }
725
-
726
745
  function readUint8Array(reader, offset, size, diskNumber) {
727
746
  return reader.readUint8Array(offset, size, diskNumber);
728
747
  }
@@ -732,8 +751,8 @@ const SplitZipWriter = SplitDataWriter;
732
751
 
733
752
  export {
734
753
  initStream,
735
- initReader,
736
- initWriter,
754
+ GenericReader,
755
+ GenericWriter,
737
756
  readUint8Array,
738
757
  Reader,
739
758
  Writer,
@@ -81,7 +81,7 @@ class CodecStream extends TransformStream {
81
81
  } else if (codecType.startsWith(CODEC_INFLATE)) {
82
82
  Stream = InflateStream;
83
83
  }
84
- let outputSize = 0;
84
+ codec.outputSize = 0;
85
85
  let inputSize = 0;
86
86
  const stream = new Stream(options, config);
87
87
  const readable = super.readable;
@@ -101,15 +101,14 @@ class CodecStream extends TransformStream {
101
101
  const outputSizeStream = new TransformStream({
102
102
  transform(chunk, controller) {
103
103
  if (chunk && chunk.length) {
104
- outputSize += chunk.length;
105
104
  controller.enqueue(chunk);
105
+ codec.outputSize += chunk.length;
106
106
  }
107
107
  },
108
108
  flush() {
109
109
  const { signature } = stream;
110
110
  Object.assign(codec, {
111
111
  signature,
112
- outputSize,
113
112
  inputSize
114
113
  });
115
114
  }
@@ -71,6 +71,7 @@ addEventListener(MESSAGE_EVENT_TYPE, ({ data }) => {
71
71
  });
72
72
 
73
73
  async function init(message) {
74
+ let codecStream;
74
75
  try {
75
76
  const { options, scripts, config } = message;
76
77
  if (scripts && scripts.length) {
@@ -142,6 +143,7 @@ async function init(message) {
142
143
  }
143
144
  });
144
145
  } catch (error) {
146
+ error.outputSize = codecStream ? codecStream.outputSize : 0;
145
147
  sendErrorMessage(error);
146
148
  }
147
149
  }
@@ -173,6 +175,6 @@ function sendMessage(message) {
173
175
  }
174
176
 
175
177
  function sendErrorMessage(error = new Error("Unknown error")) {
176
- const { message, stack, code, name } = error;
177
- postMessage({ error: { message, stack, code, name } });
178
+ const { message, stack, code, name, outputSize } = error;
179
+ postMessage({ error: { message, stack, code, name, outputSize } });
178
180
  }
@@ -144,8 +144,8 @@ class ZipFileEntry extends ZipEntry {
144
144
  const reader = zipEntry.reader = new zipEntry.Reader(zipEntry.data, options);
145
145
  const uncompressedSize = zipEntry.data ? zipEntry.data.uncompressedSize : reader.size;
146
146
  await Promise.all([initStream(reader), initStream(writer, uncompressedSize)]);
147
- const readable = reader.readable;
148
- readable.size = zipEntry.uncompressedSize = reader.size;
147
+ const { readable } = reader;
148
+ zipEntry.uncompressedSize = reader.size;
149
149
  await readable.pipeTo(writer.writable);
150
150
  return writer.getData ? writer.getData() : writer.writable;
151
151
  }
@@ -195,6 +195,10 @@ class ZipFileEntry extends ZipEntry {
195
195
  return this.getData({ writable }, options);
196
196
  }
197
197
 
198
+ getArrayBuffer(options) {
199
+ return this.data.arrayBuffer(options);
200
+ }
201
+
198
202
  replaceBlob(blob) {
199
203
  Object.assign(this, {
200
204
  data: blob,
@@ -62,6 +62,9 @@ import {
62
62
  FILE_ATTR_UNIX_EXECUTABLE_MASK,
63
63
  DIRECTORY_SIGNATURE,
64
64
  HEADER_SIZE,
65
+ HEADER_OFFSET_SIGNATURE,
66
+ HEADER_OFFSET_COMPRESSED_SIZE,
67
+ HEADER_OFFSET_UNCOMPRESSED_SIZE,
65
68
  UNDEFINED_VALUE
66
69
  } from "./constants.js";
67
70
  import {
@@ -77,10 +80,10 @@ import {
77
80
  } from "./codec-pool.js";
78
81
  import {
79
82
  initStream,
80
- initReader,
81
- initWriter,
82
83
  readUint8Array,
83
- BlobReader
84
+ BlobReader,
85
+ GenericReader,
86
+ GenericWriter
84
87
  } from "./io.js";
85
88
  import { decodeText } from "./util/decode-text.js";
86
89
  import { Crc32 } from "./streams/codecs/crc32.js";
@@ -135,7 +138,7 @@ class ZipReader {
135
138
 
136
139
  constructor(reader, options = {}) {
137
140
  Object.assign(this, {
138
- reader: initReader(reader),
141
+ reader: new GenericReader(reader),
139
142
  options,
140
143
  config: getConfiguration()
141
144
  });
@@ -310,6 +313,13 @@ class ZipReader {
310
313
  fileEntry.zipCrypto = fileEntry.encrypted && !fileEntry.extraFieldAES;
311
314
  const entry = new Entry(fileEntry);
312
315
  entry.getData = (writer, options) => fileEntry.getData(writer, entry, options);
316
+ entry.arrayBuffer = async options => {
317
+ const writer = new TransformStream();
318
+ const [arrayBuffer] = await Promise.all([
319
+ new Response(writer.readable).arrayBuffer(),
320
+ fileEntry.getData(writer, entry, options)]);
321
+ return arrayBuffer;
322
+ };
313
323
  offset = endOffset;
314
324
  const { onprogress } = options;
315
325
  if (onprogress) {
@@ -470,7 +480,7 @@ class ZipEntry {
470
480
  if (checkPasswordOnly) {
471
481
  writer = new WritableStream();
472
482
  }
473
- writer = initWriter(writer);
483
+ writer = new GenericWriter(writer);
474
484
  await initStream(writer, passThrough ? compressedSize : uncompressedSize);
475
485
  const { writable } = writer;
476
486
  const { onstart, onprogress, onend } = options;
@@ -494,16 +504,18 @@ class ZipEntry {
494
504
  config,
495
505
  streamOptions: { signal, size, onstart, onprogress, onend }
496
506
  };
497
- let outputSize = 0;
498
507
  try {
499
- ({ outputSize } = (await runWorker({ readable, writable }, workerOptions)));
508
+ const { outputSize } = await runWorker({ readable, writable }, workerOptions);
509
+ writer.size += outputSize;
500
510
  } catch (error) {
511
+ if (error.outputSize !== UNDEFINED_VALUE) {
512
+ writer.size += error.outputSize;
513
+ }
501
514
  if (!checkPasswordOnly || error.message != ERR_ABORT_CHECK_PASSWORD) {
502
515
  throw error;
503
516
  }
504
517
  } finally {
505
518
  const preventClose = getOptionValue(zipEntry, options, "preventClose");
506
- writable.size += outputSize;
507
519
  if (!preventClose && !writable.locked) {
508
520
  await writable.getWriter().close();
509
521
  }
@@ -552,9 +564,9 @@ function readCommonFooter(fileEntry, directory, dataView, offset, localDirectory
552
564
  }
553
565
  const compressionMethod = getUint16(dataView, offset + 4);
554
566
  Object.assign(directory, {
555
- signature: getUint32(dataView, offset + 10),
556
- uncompressedSize: getUint32(dataView, offset + 18),
557
- compressedSize: getUint32(dataView, offset + 14)
567
+ signature: getUint32(dataView, offset + HEADER_OFFSET_SIGNATURE),
568
+ compressedSize: getUint32(dataView, offset + HEADER_OFFSET_COMPRESSED_SIZE),
569
+ uncompressedSize: getUint32(dataView, offset + HEADER_OFFSET_UNCOMPRESSED_SIZE)
558
570
  });
559
571
  const extraFieldZip64 = extraField.get(EXTRAFIELD_TYPE_ZIP64);
560
572
  if (extraFieldZip64) {