@zip.js/zip.js 2.8.57 → 2.8.58

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.
@@ -100,6 +100,7 @@
100
100
  const FILE_ATTR_UNIX_SETGID_MASK = 0o2000;
101
101
  const FILE_ATTR_UNIX_STICKY_MASK = 0o1000;
102
102
 
103
+ const VERSION_STORE = 0x0A;
103
104
  const VERSION_DEFLATE = 0x14;
104
105
  const VERSION_ZIP64 = 0x2D;
105
106
  const VERSION_AES = 0x33;
@@ -3608,6 +3609,8 @@
3608
3609
  EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3609
3610
  */
3610
3611
 
3612
+
3613
+ const ERR_WORKER_STARTUP_TIMEOUT = "Worker startup timeout";
3611
3614
  let initModule = () => { };
3612
3615
 
3613
3616
  async function supportsDeflate(config) {
@@ -4341,6 +4344,10 @@
4341
4344
  const commentEncoding = getOptionValue$1(zipReader, options, OPTION_COMMENT_ENCODING);
4342
4345
  const filenames = checkAmbiguity ? new Set() : UNDEFINED_VALUE;
4343
4346
  let duplicateFilename;
4347
+ const recoverWrappedFilesLength = !checkAmbiguity && !zip64EndOfDirectory;
4348
+ if (!filesLength && recoverWrappedFilesLength) {
4349
+ filesLength = getWrappedFilesLength(directoryView, directoryArray, offset);
4350
+ }
4344
4351
  for (let indexFile = 0; indexFile < filesLength; indexFile++) {
4345
4352
  const fileEntry = new ZipEntry$1(reader, zipReader.options);
4346
4353
  if (offset + CENTRAL_FILE_HEADER_LENGTH > directoryArray.length || getUint32$1(directoryView, offset) != CENTRAL_FILE_HEADER_SIGNATURE) {
@@ -4450,7 +4457,7 @@
4450
4457
  internalFileAttribute: fileEntry.internalFileAttributes,
4451
4458
  externalFileAttribute: fileEntry.externalFileAttributes,
4452
4459
  executable,
4453
- directory: modeIsDir || upperIsDir || (msDosCompatible && msdosAttributes.directory) || (fileEntry.filename.endsWith(DIRECTORY_SIGNATURE) && !fileEntry.uncompressedSize),
4460
+ directory: modeIsDir || upperIsDir || (msDosCompatible && msdosAttributes.directory) || fileEntry.filename.endsWith(DIRECTORY_SIGNATURE),
4454
4461
  zipCrypto: fileEntry.encrypted && !fileEntry.extraFieldAES
4455
4462
  });
4456
4463
  const entry = new Entry(fileEntry);
@@ -4463,6 +4470,9 @@
4463
4470
  return arrayBufferPromise;
4464
4471
  };
4465
4472
  offset = endOffset;
4473
+ if (indexFile == filesLength - 1 && recoverWrappedFilesLength) {
4474
+ filesLength += getWrappedFilesLength(directoryView, directoryArray, offset);
4475
+ }
4466
4476
  const { onprogress } = options;
4467
4477
  if (onprogress) {
4468
4478
  try {
@@ -4528,6 +4538,46 @@
4528
4538
  }
4529
4539
  }
4530
4540
 
4541
+ class ZipReaderStream {
4542
+
4543
+ constructor(options = {}) {
4544
+ const { readable, writable } = new TransformStream();
4545
+ const gen = new ZipReader(readable, options).getEntriesGenerator();
4546
+ this.readable = new ReadableStream({
4547
+ async pull(controller) {
4548
+ const { done, value } = await gen.next();
4549
+ if (done)
4550
+ return controller.close();
4551
+ const chunk = {
4552
+ ...value,
4553
+ readable: (function () {
4554
+ const { readable, writable } = new TransformStream();
4555
+ if (value.getData) {
4556
+ getData();
4557
+ return readable;
4558
+ }
4559
+
4560
+ async function getData() {
4561
+ try {
4562
+ await value.getData(writable);
4563
+ } catch (error) {
4564
+ try {
4565
+ await writable.abort(error);
4566
+ } catch {
4567
+ // ignored
4568
+ }
4569
+ }
4570
+ }
4571
+ })()
4572
+ };
4573
+ delete chunk.getData;
4574
+ controller.enqueue(chunk);
4575
+ }
4576
+ });
4577
+ this.writable = writable;
4578
+ }
4579
+ }
4580
+
4531
4581
  let ZipEntry$1 = class ZipEntry {
4532
4582
 
4533
4583
  constructor(reader, options) {
@@ -4581,6 +4631,7 @@
4581
4631
  extraFieldLength,
4582
4632
  filenameLength
4583
4633
  } = localDirectory;
4634
+ const dataOffset = localDirectory.dataOffset = localHeaderOffset + HEADER_SIZE + filenameLength + extraFieldLength;
4584
4635
  const checkLocalDirectoryOption = getOptionValue$1(zipEntry, options, OPTION_CHECK_LOCAL_DIRECTORY);
4585
4636
  const entryStrictness = getStrictness(options, zipEntry.options);
4586
4637
  const checkLocalDirectory = getCheckLocalDirectory(checkLocalDirectoryOption, entryStrictness);
@@ -4634,7 +4685,6 @@
4634
4685
  throw new Error(ERR_ENCRYPTED);
4635
4686
  }
4636
4687
  }
4637
- const dataOffset = localHeaderOffset + HEADER_SIZE + filenameLength + extraFieldLength;
4638
4688
  if (dataOffset + compressedSize > reader.size) {
4639
4689
  throw new Error(ERR_ENTRY_DATA_OUT_OF_BOUNDS);
4640
4690
  }
@@ -4754,6 +4804,16 @@
4754
4804
  return false;
4755
4805
  }
4756
4806
 
4807
+ function getWrappedFilesLength(directoryView, directoryArray, offset) {
4808
+ let wrappedFilesLength = 0;
4809
+ while (offset + CENTRAL_FILE_HEADER_LENGTH <= directoryArray.length && getUint32$1(directoryView, offset) == CENTRAL_FILE_HEADER_SIGNATURE) {
4810
+ offset += CENTRAL_FILE_HEADER_LENGTH +
4811
+ getUint16$1(directoryView, offset + 28) + getUint16$1(directoryView, offset + 30) + getUint16$1(directoryView, offset + 32);
4812
+ wrappedFilesLength++;
4813
+ }
4814
+ return wrappedFilesLength % (MAX_16_BITS + 1) ? 0 : wrappedFilesLength;
4815
+ }
4816
+
4757
4817
  function readDigitalSignature(signatureRecordArray) {
4758
4818
  if (signatureRecordArray.length >= 6) {
4759
4819
  const signatureRecordView = getDataView(signatureRecordArray);
@@ -4926,10 +4986,11 @@
4926
4986
  const computedCrc32View = getDataView(new Uint8Array(4));
4927
4987
  computedCrc32View.setUint32(0, computedCrc32.get(), true);
4928
4988
  const nameCrc32 = getUint32$1(extraFieldView, 1);
4989
+ const version = getUint8(extraFieldView, 0);
4929
4990
  Object.assign(extraFieldUnicode, {
4930
- version: getUint8(extraFieldView, 0),
4991
+ version,
4931
4992
  [propertyName]: decodeText(extraFieldUnicode.data.subarray(5)),
4932
- valid: !fileEntry.bitFlag.languageEncodingFlag && nameCrc32 == getUint32$1(computedCrc32View, 0)
4993
+ valid: version == 1 && !fileEntry.bitFlag.languageEncodingFlag && nameCrc32 == getUint32$1(computedCrc32View, 0)
4933
4994
  });
4934
4995
  if (extraFieldUnicode.valid) {
4935
4996
  directory[propertyName] = extraFieldUnicode[propertyName];
@@ -5398,7 +5459,8 @@
5398
5459
 
5399
5460
  function getDate(timeRaw) {
5400
5461
  const date = (timeRaw & 0xffff0000) >> 16, time = timeRaw & MAX_16_BITS;
5401
- return new Date(1980 + ((date & 0xFE00) >> 9), ((date & 0x01E0) >> 5) - 1, date & 0x001F, (time & 0xF800) >> 11, (time & 0x07E0) >> 5, (time & 0x001F) * 2, 0);
5462
+ const result = new Date(1980 + ((date & 0xFE00) >> 9), ((date & 0x01E0) >> 5) - 1, date & 0x001F, (time & 0xF800) >> 11, (time & 0x07E0) >> 5, (time & 0x001F) * 2, 0);
5463
+ return result < MIN_DATE ? MIN_DATE : result;
5402
5464
  }
5403
5465
 
5404
5466
  function getDateNTFS(timeRaw) {
@@ -5452,7 +5514,9 @@
5452
5514
  ERR_UNSUPPORTED_COMPRESSION: ERR_UNSUPPORTED_COMPRESSION$1,
5453
5515
  ERR_UNSUPPORTED_ENCRYPTION: ERR_UNSUPPORTED_ENCRYPTION,
5454
5516
  ERR_UNSUPPORTED_UINT64: ERR_UNSUPPORTED_UINT64,
5455
- ZipReader: ZipReader
5517
+ ERR_WORKER_STARTUP_TIMEOUT: ERR_WORKER_STARTUP_TIMEOUT,
5518
+ ZipReader: ZipReader,
5519
+ ZipReaderStream: ZipReaderStream
5456
5520
  });
5457
5521
 
5458
5522
  /*
@@ -5549,153 +5613,150 @@
5549
5613
  offset: options[OPTION_OFFSET] === UNDEFINED_VALUE ? writer.size || writer.writable.size || 0 : options[OPTION_OFFSET],
5550
5614
  initialOffset: options[OPTION_OFFSET] === UNDEFINED_VALUE ? 0 : options[OPTION_OFFSET] - (writer.size || writer.writable.size || 0),
5551
5615
  pendingAddFileCalls: new Set(),
5616
+ pendingErrors: [],
5552
5617
  bufferedWrites: 0,
5553
5618
  lastFileEntry: UNDEFINED_VALUE
5554
5619
  });
5555
5620
  }
5556
5621
 
5557
- async prependZip(reader) {
5558
- if (this.filenames.size) {
5559
- throw new Error(ERR_ZIP_NOT_EMPTY);
5560
- }
5561
- reader = new GenericReader(reader);
5562
- await initStream(reader);
5563
- if (reader.size === UNDEFINED_VALUE || !reader.readUint8Array) {
5564
- reader = new BlobReader(await streamToBlob(reader.readable));
5565
- await initStream(reader);
5566
- }
5567
- const { ZipReader } = await Promise.resolve().then(function () { return zipReader; });
5568
- const zipReader$1 = new ZipReader(reader);
5569
- const entries = await zipReader$1.getEntries();
5570
- await zipReader$1.close();
5571
- await initStream(this.writer);
5572
- const { directoryOffset } = zipReader$1;
5573
- if (this.addSplitZipSignature) {
5574
- delete this.addSplitZipSignature;
5575
- if (!await startsWithSplitZipSignature(reader)) {
5576
- await writeData(this.writer, getSplitZipSignatureArray());
5577
- this.offset += SPLIT_ZIP_FILE_SIGNATURE_LENGTH;
5578
- }
5579
- }
5580
- const entryPositions = await copyZipData(this, reader, entries, directoryOffset);
5581
- this.filenames = new Set(entries.map(entry => entry.filename));
5582
- this.fileEntries = new Map(entries.map(entry => {
5583
- const {
5584
- version,
5585
- rawLastModDate,
5586
- lastAccessDate,
5587
- creationDate,
5588
- rawFilename,
5589
- bitFlag,
5590
- encrypted,
5591
- uncompressedSize,
5592
- compressedSize,
5593
- extraFieldZip64
5594
- } = entry;
5595
- let {
5596
- compressionMethod,
5597
- rawExtraFieldZip64,
5598
- rawExtraFieldAES,
5599
- rawExtraFieldExtendedTimestamp,
5600
- rawExtraFieldNTFS,
5601
- rawExtraFieldUnix,
5602
- rawExtraField,
5603
- } = entry;
5604
- const { level, languageEncodingFlag, dataDescriptor } = bitFlag;
5605
- rawExtraFieldZip64 = rawExtraFieldZip64 || EMPTY_UINT8_ARRAY;
5606
- rawExtraFieldAES = rawExtraFieldAES || EMPTY_UINT8_ARRAY;
5607
- rawExtraFieldExtendedTimestamp = rawExtraFieldExtendedTimestamp || EMPTY_UINT8_ARRAY;
5608
- rawExtraFieldNTFS = rawExtraFieldNTFS || EMPTY_UINT8_ARRAY;
5609
- rawExtraFieldUnix = rawExtraFieldUnix || EMPTY_UINT8_ARRAY;
5610
- rawExtraField = removeExtraFieldZip64(rawExtraField || EMPTY_UINT8_ARRAY);
5611
- if (entry.extraFieldAES) {
5612
- compressionMethod = COMPRESSION_METHOD_AES;
5613
- }
5614
- const extraFieldLength = getLength(rawExtraFieldZip64, rawExtraFieldAES, rawExtraFieldExtendedTimestamp, rawExtraFieldNTFS, rawExtraFieldUnix, rawExtraField);
5615
- const zip64UncompressedSize = Boolean(extraFieldZip64) && extraFieldZip64.uncompressedSize !== UNDEFINED_VALUE;
5616
- const zip64CompressedSize = Boolean(extraFieldZip64) && extraFieldZip64.compressedSize !== UNDEFINED_VALUE;
5617
- const bitFlagValue = (getBitFlag(level, languageEncodingFlag, dataDescriptor, encrypted, compressionMethod) & ~BITFLAG_LEVEL) | (level << 1);
5618
- const {
5619
- headerArray,
5620
- headerView
5621
- } = getHeaderArrayData({
5622
- version,
5623
- bitFlag: bitFlagValue,
5624
- compressionMethod,
5625
- uncompressedSize,
5626
- compressedSize,
5627
- rawLastModDate,
5628
- rawFilename,
5629
- zip64CompressedSize,
5630
- zip64UncompressedSize,
5631
- extraFieldLength
5632
- });
5633
- const { crc32 } = entry;
5634
- if (crc32 !== UNDEFINED_VALUE) {
5635
- setUint32(headerView, HEADER_OFFSET_SIGNATURE, crc32);
5636
- }
5637
- const { offset, diskNumberStart } = entryPositions.get(entry);
5638
- Object.assign(entry, {
5639
- zip64UncompressedSize,
5640
- zip64CompressedSize,
5641
- offset,
5642
- diskNumberStart,
5643
- zip64DiskNumberStart: false,
5644
- rawExtraFieldZip64,
5645
- rawExtraFieldAES,
5646
- rawExtraFieldExtendedTimestamp,
5647
- rawExtraFieldNTFS,
5648
- rawExtraFieldUnix,
5649
- rawExtraField,
5650
- extendedTimestamp: rawExtraFieldExtendedTimestamp.length > 0 || rawExtraFieldNTFS.length > 0,
5651
- extraFieldExtendedTimestampFlag: 0x1 + (lastAccessDate ? 0x2 : 0) + (creationDate ? 0x4 : 0),
5652
- headerArray,
5653
- headerView
5654
- });
5655
- return [entry.filename, entry];
5656
- }));
5622
+ prependZip(reader) {
5623
+ return watchPromiseError(this, prependZipEntries(this, reader));
5624
+ }
5625
+
5626
+ appendZip(reader) {
5627
+ return watchPromiseError(this, this.appendZipEntries(reader));
5657
5628
  }
5658
5629
 
5659
- async add(name = "", reader, options = {}) {
5630
+ async appendZipEntries(reader) {
5660
5631
  const zipWriter = this;
5661
- options = Object.assign({}, options);
5662
- const { pendingAddFileCalls } = zipWriter;
5663
- if (workers < getConfiguration().maxWorkers) {
5664
- workers++;
5665
- } else {
5666
- await new Promise(resolve => pendingEntries.push(resolve));
5632
+ const { pendingAddFileCalls, filenames, fileEntries } = zipWriter;
5633
+ while (pendingAddFileCalls.size) {
5634
+ await Promise.allSettled(Array.from(pendingAddFileCalls));
5667
5635
  }
5668
- let promiseAddFile;
5669
- let nameAdded;
5636
+ let resolveAppendZip;
5637
+ const promiseAppendZip = new Promise(resolve => resolveAppendZip = resolve);
5638
+ pendingAddFileCalls.add(promiseAppendZip);
5639
+ const appendedFilenames = [];
5640
+ let releaseLockWriter;
5670
5641
  try {
5671
- name = name.trim();
5672
- if (getOptionValue(zipWriter, options, PROPERTY_NAME_DIRECTORY) && !name.endsWith(DIRECTORY_SIGNATURE)) {
5673
- name += DIRECTORY_SIGNATURE;
5674
- }
5675
- if (zipWriter.filenames.has(name)) {
5676
- throw new Error(ERR_DUPLICATED_NAME);
5677
- }
5678
- zipWriter.filenames.add(name);
5679
- nameAdded = true;
5680
- promiseAddFile = addFile(zipWriter, name, reader, options);
5681
- pendingAddFileCalls.add(promiseAddFile);
5682
- return await promiseAddFile;
5683
- } catch (error) {
5684
- if (nameAdded) {
5685
- zipWriter.filenames.delete(name);
5642
+ reader = new GenericReader(reader);
5643
+ await initStream(reader);
5644
+ if (reader.size === UNDEFINED_VALUE || !reader.readUint8Array) {
5645
+ reader = new BlobReader(await streamToBlob(reader.readable));
5646
+ await initStream(reader);
5647
+ }
5648
+ const { ZipReader } = await Promise.resolve().then(function () { return zipReader; });
5649
+ const zipReader$1 = new ZipReader(reader);
5650
+ const entries = await zipReader$1.getEntries();
5651
+ await zipReader$1.close();
5652
+ await initStream(zipWriter.writer);
5653
+ const { directoryOffset } = zipReader$1;
5654
+ entries.forEach(({ filename }) => {
5655
+ if (filenames.has(filename)) {
5656
+ throw new Error(ERR_DUPLICATED_NAME);
5657
+ }
5658
+ filenames.add(filename);
5659
+ appendedFilenames.push(filename);
5660
+ });
5661
+ zipWriter.writerLocked = true;
5662
+ const { lockWriter } = zipWriter;
5663
+ zipWriter.lockWriter = new Promise(resolve => releaseLockWriter = () => {
5664
+ zipWriter.writerLocked = false;
5665
+ resolve();
5666
+ });
5667
+ await lockWriter;
5668
+ if (zipWriter.addSplitZipSignature) {
5669
+ delete zipWriter.addSplitZipSignature;
5670
+ if (!await startsWithSplitZipSignature(reader)) {
5671
+ await writeData(zipWriter.writer, getSplitZipSignatureArray());
5672
+ zipWriter.offset += SPLIT_ZIP_FILE_SIGNATURE_LENGTH;
5673
+ }
5686
5674
  }
5675
+ const entryPositions = await copyZipData(zipWriter, reader, entries, directoryOffset);
5676
+ entries.forEach(entry => {
5677
+ const {
5678
+ version,
5679
+ rawLastModDate,
5680
+ rawFilename,
5681
+ bitFlag,
5682
+ encrypted,
5683
+ uncompressedSize,
5684
+ compressedSize,
5685
+ extraFieldZip64
5686
+ } = entry;
5687
+ let {
5688
+ compressionMethod,
5689
+ rawExtraField,
5690
+ } = entry;
5691
+ const { level, languageEncodingFlag, dataDescriptor } = bitFlag;
5692
+ rawExtraField = removeExtraFieldZip64(rawExtraField || EMPTY_UINT8_ARRAY);
5693
+ if (entry.extraFieldAES) {
5694
+ compressionMethod = COMPRESSION_METHOD_AES;
5695
+ }
5696
+ const extraFieldLength = getLength(rawExtraField);
5697
+ const zip64UncompressedSize = Boolean(extraFieldZip64) && extraFieldZip64.uncompressedSize !== UNDEFINED_VALUE;
5698
+ const zip64CompressedSize = Boolean(extraFieldZip64) && extraFieldZip64.compressedSize !== UNDEFINED_VALUE;
5699
+ const bitFlagValue = (getBitFlag(level, languageEncodingFlag, dataDescriptor, encrypted, compressionMethod) & ~BITFLAG_LEVEL) | (level << 1);
5700
+ const {
5701
+ headerArray,
5702
+ headerView
5703
+ } = getHeaderArrayData({
5704
+ version,
5705
+ bitFlag: bitFlagValue,
5706
+ compressionMethod,
5707
+ uncompressedSize,
5708
+ compressedSize,
5709
+ rawLastModDate,
5710
+ rawFilename,
5711
+ zip64CompressedSize,
5712
+ zip64UncompressedSize,
5713
+ extraFieldLength
5714
+ });
5715
+ const { crc32 } = entry;
5716
+ if (crc32 !== UNDEFINED_VALUE) {
5717
+ setUint32(headerView, HEADER_OFFSET_SIGNATURE, crc32);
5718
+ }
5719
+ const { offset, diskNumberStart } = entryPositions.get(entry);
5720
+ Object.assign(entry, {
5721
+ zip64UncompressedSize,
5722
+ zip64CompressedSize,
5723
+ offset,
5724
+ diskNumberStart,
5725
+ zip64DiskNumberStart: false,
5726
+ rawExtraFieldZip64: EMPTY_UINT8_ARRAY,
5727
+ rawExtraFieldAES: EMPTY_UINT8_ARRAY,
5728
+ rawExtraFieldExtendedTimestamp: EMPTY_UINT8_ARRAY,
5729
+ rawExtraFieldNTFS: EMPTY_UINT8_ARRAY,
5730
+ rawExtraFieldUnix: EMPTY_UINT8_ARRAY,
5731
+ rawExtraField,
5732
+ extendedTimestamp: false,
5733
+ headerArray,
5734
+ headerView
5735
+ });
5736
+ fileEntries.set(entry.filename, entry);
5737
+ });
5738
+ } catch (error) {
5739
+ appendedFilenames.forEach(filename => filenames.delete(filename));
5687
5740
  throw error;
5688
5741
  } finally {
5689
- pendingAddFileCalls.delete(promiseAddFile);
5690
- const pendingEntry = pendingEntries.shift();
5691
- if (pendingEntry) {
5692
- pendingEntry();
5693
- } else {
5694
- workers--;
5742
+ resolveAppendZip();
5743
+ pendingAddFileCalls.delete(promiseAppendZip);
5744
+ if (releaseLockWriter) {
5745
+ releaseLockWriter();
5695
5746
  }
5696
5747
  }
5697
5748
  }
5698
5749
 
5750
+ add(name = "", reader, options = {}) {
5751
+ const zipWriter = this;
5752
+ const { pendingAddFileCalls } = zipWriter;
5753
+ const promiseAddFile = addFileEntry(zipWriter, name, reader, options);
5754
+ pendingAddFileCalls.add(promiseAddFile);
5755
+ const deletePendingAddFileCall = () => pendingAddFileCalls.delete(promiseAddFile);
5756
+ Promise.prototype.then.call(promiseAddFile, deletePendingAddFileCall, deletePendingAddFileCall);
5757
+ return watchPromiseError(zipWriter, promiseAddFile);
5758
+ }
5759
+
5699
5760
  remove(entry) {
5700
5761
  const { filenames, fileEntries } = this;
5701
5762
  // deno-lint-ignore valid-typeof
@@ -5726,6 +5787,19 @@
5726
5787
  while (pendingAddFileCalls.size) {
5727
5788
  await Promise.allSettled(Array.from(pendingAddFileCalls));
5728
5789
  }
5790
+ await Promise.allSettled(zipWriter.pendingErrors.map(watcher => watcher.recorded));
5791
+ const unobservedWatchers = zipWriter.pendingErrors.filter(watcher => watcher.error && !watcher.observed);
5792
+ if (unobservedWatchers.length) {
5793
+ const unobservedErrors = unobservedWatchers.map(watcher => watcher.error);
5794
+ unobservedWatchers.forEach(watcher => watcher.observed = true);
5795
+ const [error] = unobservedErrors;
5796
+ try {
5797
+ error.entryErrors = unobservedErrors;
5798
+ } catch {
5799
+ // ignored
5800
+ }
5801
+ throw error;
5802
+ }
5729
5803
  await closeFile(zipWriter, comment, options);
5730
5804
  const preventClose = !ownsWritable(writer) && getOptionValue(zipWriter, options, OPTION_PREVENT_CLOSE);
5731
5805
  if (!preventClose) {
@@ -5735,6 +5809,63 @@
5735
5809
  }
5736
5810
  }
5737
5811
 
5812
+ class WatchedPromise extends Promise {
5813
+
5814
+ then(onFulfilled, onRejected) {
5815
+ const { watcher } = this;
5816
+ if (watcher) {
5817
+ watcher.observed = true;
5818
+ }
5819
+ return super.then(onFulfilled, onRejected);
5820
+ }
5821
+ }
5822
+
5823
+ function watchPromiseError(zipWriter, promise) {
5824
+ const watchedPromise = new WatchedPromise((resolve, reject) => Promise.prototype.then.call(promise, resolve, reject));
5825
+ const watcher = {};
5826
+ watchedPromise.watcher = watcher;
5827
+ watcher.recorded = Promise.prototype.then.call(watchedPromise, UNDEFINED_VALUE, error => watcher.error = error);
5828
+ zipWriter.pendingErrors.push(watcher);
5829
+ return watchedPromise;
5830
+ }
5831
+
5832
+ async function prependZipEntries(zipWriter, reader) {
5833
+ if (zipWriter.filenames.size) {
5834
+ throw new Error(ERR_ZIP_NOT_EMPTY);
5835
+ }
5836
+ await zipWriter.appendZipEntries(reader);
5837
+ }
5838
+
5839
+ async function addFileEntry(zipWriter, name, reader, options) {
5840
+ options = Object.assign({}, options);
5841
+ name = name.trim();
5842
+ if (getOptionValue(zipWriter, options, PROPERTY_NAME_DIRECTORY) && !name.endsWith(DIRECTORY_SIGNATURE)) {
5843
+ name += DIRECTORY_SIGNATURE;
5844
+ }
5845
+ if (zipWriter.filenames.has(name)) {
5846
+ throw new Error(ERR_DUPLICATED_NAME);
5847
+ }
5848
+ zipWriter.filenames.add(name);
5849
+ if (workers < getConfiguration().maxWorkers) {
5850
+ workers++;
5851
+ } else {
5852
+ await new Promise(resolve => pendingEntries.push(resolve));
5853
+ }
5854
+ try {
5855
+ return await addFile(zipWriter, name, reader, options);
5856
+ } catch (error) {
5857
+ zipWriter.filenames.delete(name);
5858
+ throw error;
5859
+ } finally {
5860
+ const pendingEntry = pendingEntries.shift();
5861
+ if (pendingEntry) {
5862
+ pendingEntry();
5863
+ } else {
5864
+ workers--;
5865
+ }
5866
+ }
5867
+ }
5868
+
5738
5869
  async function addFile(zipWriter, name, reader, options) {
5739
5870
  const attributesInfo = resolveAttributes(zipWriter, name, options);
5740
5871
  ({ name } = attributesInfo);
@@ -5923,11 +6054,12 @@
5923
6054
  if (getLength(rawComment) > MAX_16_BITS) {
5924
6055
  throw new Error(ERR_INVALID_ENTRY_COMMENT);
5925
6056
  }
5926
- const version = getOptionValue(zipWriter, options, PROPERTY_NAME_VERSION, VERSION_DEFLATE);
5927
- if (version > MAX_16_BITS) {
6057
+ const version = getOptionValue(zipWriter, options, PROPERTY_NAME_VERSION);
6058
+ if (version !== UNDEFINED_VALUE && version > MAX_16_BITS) {
5928
6059
  throw new Error(ERR_INVALID_VERSION);
5929
6060
  }
5930
6061
  const lastModDate = getDateOptionValue(zipWriter, options, PROPERTY_NAME_LAST_MODIFICATION_DATE, new Date());
6062
+ const rawLastModDate = getOptionValue(zipWriter, options, PROPERTY_NAME_RAW_LAST_MODIFICATION_DATE);
5931
6063
  const lastAccessDate = getDateOptionValue(zipWriter, options, PROPERTY_NAME_LAST_ACCESS_DATE);
5932
6064
  const creationDate = getDateOptionValue(zipWriter, options, PROPERTY_NAME_CREATION_DATE);
5933
6065
  const internalFileAttributes = getAliasedOptionValue(zipWriter, options, PROPERTY_NAME_INTERNAL_FILE_ATTRIBUTES, PROPERTY_NAME_DEPRECATED_INTERNAL_FILE_ATTRIBUTES, 0);
@@ -5971,7 +6103,7 @@
5971
6103
  if (bufferedWrite && dataDescriptor === UNDEFINED_VALUE) {
5972
6104
  dataDescriptor = false;
5973
6105
  }
5974
- if (dataDescriptor === UNDEFINED_VALUE || zipCrypto) {
6106
+ if (dataDescriptor === UNDEFINED_VALUE || (zipCrypto && !passThrough)) {
5975
6107
  dataDescriptor = true;
5976
6108
  }
5977
6109
  if (level !== UNDEFINED_VALUE && level != 6) {
@@ -5990,6 +6122,7 @@
5990
6122
  rawComment,
5991
6123
  version,
5992
6124
  lastModDate,
6125
+ rawLastModDate,
5993
6126
  lastAccessDate,
5994
6127
  creationDate,
5995
6128
  internalFileAttributes,
@@ -6265,10 +6398,8 @@
6265
6398
  }
6266
6399
  await initStream(fileWriter);
6267
6400
  const diskOffset = getDiskOffset(writer);
6268
- if (zipWriter.addSplitZipSignature) {
6269
- delete zipWriter.addSplitZipSignature;
6270
- await writeData(writer, getSplitZipSignatureArray());
6271
- zipWriter.offset += SPLIT_ZIP_FILE_SIGNATURE_LENGTH;
6401
+ if (zipWriter.addSplitZipSignature && !bufferedWrite) {
6402
+ await writeSplitZipSignature(zipWriter, writer);
6272
6403
  }
6273
6404
  if (usdz && !bufferedWrite) {
6274
6405
  appendExtraFieldUSDZ(entryInfo, zipWriter.offset - diskOffset);
@@ -6295,6 +6426,9 @@
6295
6426
  if (bufferedWrite) {
6296
6427
  await Promise.all([fileWriter.writable.getWriter().close(), lockPreviousFileEntry]);
6297
6428
  await requestLockWriter();
6429
+ if (zipWriter.addSplitZipSignature) {
6430
+ await writeSplitZipSignature(zipWriter, writer);
6431
+ }
6298
6432
  writingBufferedEntryData = true;
6299
6433
  writerSizeBeforeEntry = writer.size;
6300
6434
  await skipDiskIfNeeded();
@@ -6566,6 +6700,7 @@
6566
6700
  const {
6567
6701
  rawFilename,
6568
6702
  lastModDate,
6703
+ rawLastModDate: rawLastModDateOption,
6569
6704
  lastAccessDate,
6570
6705
  creationDate,
6571
6706
  level,
@@ -6699,6 +6834,9 @@
6699
6834
  if (compressionMethod === UNDEFINED_VALUE) {
6700
6835
  compressionMethod = compressed ? COMPRESSION_METHOD_DEFLATE : COMPRESSION_METHOD_STORE;
6701
6836
  }
6837
+ if (version === UNDEFINED_VALUE) {
6838
+ version = compressionMethod == COMPRESSION_METHOD_STORE && !directory && !encrypted ? VERSION_STORE : VERSION_DEFLATE;
6839
+ }
6702
6840
  const { codecVersionNeeded } = options;
6703
6841
  if (compressed && codecVersionNeeded !== UNDEFINED_VALUE) {
6704
6842
  version = version > codecVersionNeeded ? version : codecVersionNeeded;
@@ -6731,6 +6869,7 @@
6731
6869
  compressionMethod,
6732
6870
  uncompressedSize,
6733
6871
  lastModDate: dosLastModDate < MIN_DATE ? MIN_DATE : dosLastModDate > MAX_DATE ? MAX_DATE : dosLastModDate,
6872
+ rawLastModDate: rawLastModDateOption,
6734
6873
  rawFilename,
6735
6874
  zip64CompressedSize,
6736
6875
  zip64UncompressedSize,
@@ -6937,9 +7076,9 @@
6937
7076
 
6938
7077
  async function closeFile(zipWriter, comment, options) {
6939
7078
  const directoryDataLength = createDirectoryRecords(zipWriter.fileEntries);
6940
- const { directoryStart, directoryArray } = await writeDirectoryRecords(zipWriter, directoryDataLength, options);
7079
+ const { directoryStart, directoryEnd, directoryArray } = await writeDirectoryRecords(zipWriter, directoryDataLength, options);
6941
7080
  const signatureLength = await writeDigitalSignatureRecord(zipWriter, directoryArray, options);
6942
- await writeEndOfDirectoryRecord(zipWriter, comment, options, { directoryStart, directoryDataLength, signatureLength });
7081
+ await writeEndOfDirectoryRecord(zipWriter, comment, options, { directoryStart, directoryEnd, directoryDataLength, signatureLength });
6943
7082
  }
6944
7083
 
6945
7084
  function createDirectoryRecords(files) {
@@ -7023,6 +7162,7 @@
7023
7162
  let directoryDiskOffset = 0;
7024
7163
  let directoryStartDiskNumber = getDiskNumber(writer);
7025
7164
  let directoryStartDiskOffset = getDiskOffset(writer);
7165
+ let directoryEndDiskEntriesLength = 0;
7026
7166
  for (const [indexFileEntry, fileEntry] of Array.from(fileEntries.values()).entries()) {
7027
7167
  const {
7028
7168
  offset: fileEntryOffset,
@@ -7052,6 +7192,7 @@
7052
7192
  if (exceedsAvailableSize(writer, offset + directoryRecordLength - directoryDiskOffset)) {
7053
7193
  await writeData(writer, directoryArray.slice(directoryDiskOffset, offset));
7054
7194
  directoryDiskOffset = offset;
7195
+ directoryEndDiskEntriesLength = 0;
7055
7196
  await writer.closeDisk();
7056
7197
  }
7057
7198
  if (indexFileEntry == 0) {
@@ -7087,6 +7228,7 @@
7087
7228
  directoryRecord.writeBytes(rawComment);
7088
7229
  arraySet(directoryArray, directoryRecord.array, offset);
7089
7230
  offset += directoryRecordLength;
7231
+ directoryEndDiskEntriesLength++;
7090
7232
  if (options.onprogress) {
7091
7233
  try {
7092
7234
  await options.onprogress(indexFileEntry + 1, fileEntries.size, new Entry(fileEntry));
@@ -7098,6 +7240,7 @@
7098
7240
  await writeData(writer, directoryDiskOffset ? directoryArray.slice(directoryDiskOffset) : directoryArray);
7099
7241
  return {
7100
7242
  directoryStart: { diskNumber: directoryStartDiskNumber, diskOffset: directoryStartDiskOffset },
7243
+ directoryEnd: { diskNumber: getDiskNumber(writer), entriesLength: directoryEndDiskEntriesLength },
7101
7244
  directoryArray
7102
7245
  };
7103
7246
  }
@@ -7126,16 +7269,20 @@
7126
7269
 
7127
7270
  async function writeEndOfDirectoryRecord(zipWriter, comment, options, cdInfo) {
7128
7271
  const { writer } = zipWriter;
7129
- const { directoryStart, signatureLength } = cdInfo;
7272
+ const { directoryStart, directoryEnd, signatureLength } = cdInfo;
7130
7273
  let { directoryDataLength } = cdInfo;
7131
7274
  let fileEntriesLength = zipWriter.fileEntries.size;
7132
7275
  let diskNumber = directoryStart.diskNumber;
7133
7276
  let directoryOffset = getSegmentOffset(zipWriter, directoryStart);
7277
+ const commentLength = getLength(comment);
7278
+ if (commentLength > MAX_16_BITS) {
7279
+ throw new Error(ERR_INVALID_COMMENT);
7280
+ }
7281
+ let zip64 = getOptionValue(zipWriter, options, PROPERTY_NAME_ZIP64);
7134
7282
  let lastDiskNumber = getDiskNumber(writer);
7135
- if (exceedsAvailableSize(writer, END_OF_CENTRAL_DIR_LENGTH)) {
7283
+ if (exceedsAvailableSize(writer, (zip64 ? ZIP64_END_OF_CENTRAL_DIR_TOTAL_LENGTH : END_OF_CENTRAL_DIR_LENGTH) + commentLength)) {
7136
7284
  lastDiskNumber++;
7137
7285
  }
7138
- let zip64 = getOptionValue(zipWriter, options, PROPERTY_NAME_ZIP64);
7139
7286
  if (directoryOffset >= MAX_32_BITS || directoryDataLength >= MAX_32_BITS || fileEntriesLength >= MAX_16_BITS || lastDiskNumber >= MAX_16_BITS) {
7140
7287
  if (zip64 === false) {
7141
7288
  throw new Error(ERR_UNSUPPORTED_FORMAT);
@@ -7143,15 +7290,12 @@
7143
7290
  zip64 = true;
7144
7291
  }
7145
7292
  }
7146
- const commentLength = getLength(comment);
7147
- if (commentLength > MAX_16_BITS) {
7148
- throw new Error(ERR_INVALID_COMMENT);
7149
- }
7150
7293
  const endOfdirectoryRecord = createRecordWriter(zip64 ? ZIP64_END_OF_CENTRAL_DIR_TOTAL_LENGTH : END_OF_CENTRAL_DIR_LENGTH);
7151
7294
  if (exceedsAvailableSize(writer, getLength(endOfdirectoryRecord.array) + commentLength)) {
7152
7295
  await writer.closeDisk();
7153
7296
  }
7154
7297
  lastDiskNumber = getDiskNumber(writer);
7298
+ let diskFileEntriesLength = lastDiskNumber == directoryEnd.diskNumber ? directoryEnd.entriesLength : 0;
7155
7299
  if (zip64) {
7156
7300
  endOfdirectoryRecord.writeUint32(ZIP64_END_OF_CENTRAL_DIR_SIGNATURE);
7157
7301
  endOfdirectoryRecord.writeUint64(44);
@@ -7159,7 +7303,7 @@
7159
7303
  endOfdirectoryRecord.writeUint16(45);
7160
7304
  endOfdirectoryRecord.writeUint32(lastDiskNumber);
7161
7305
  endOfdirectoryRecord.writeUint32(diskNumber);
7162
- endOfdirectoryRecord.writeUint64(fileEntriesLength);
7306
+ endOfdirectoryRecord.writeUint64(diskFileEntriesLength);
7163
7307
  endOfdirectoryRecord.writeUint64(fileEntriesLength);
7164
7308
  endOfdirectoryRecord.writeUint64(directoryDataLength);
7165
7309
  endOfdirectoryRecord.writeUint64(directoryOffset);
@@ -7172,6 +7316,7 @@
7172
7316
  lastDiskNumber = MAX_16_BITS;
7173
7317
  diskNumber = MAX_16_BITS;
7174
7318
  }
7319
+ diskFileEntriesLength = MAX_16_BITS;
7175
7320
  fileEntriesLength = MAX_16_BITS;
7176
7321
  directoryOffset = MAX_32_BITS;
7177
7322
  directoryDataLength = MAX_32_BITS;
@@ -7179,7 +7324,7 @@
7179
7324
  endOfdirectoryRecord.writeUint32(END_OF_CENTRAL_DIR_SIGNATURE);
7180
7325
  endOfdirectoryRecord.writeUint16(lastDiskNumber);
7181
7326
  endOfdirectoryRecord.writeUint16(diskNumber);
7182
- endOfdirectoryRecord.writeUint16(fileEntriesLength);
7327
+ endOfdirectoryRecord.writeUint16(diskFileEntriesLength);
7183
7328
  endOfdirectoryRecord.writeUint16(fileEntriesLength);
7184
7329
  endOfdirectoryRecord.writeUint32(directoryDataLength);
7185
7330
  endOfdirectoryRecord.writeUint32(directoryOffset);
@@ -7278,9 +7423,21 @@
7278
7423
  async function copyData(zipWriter, reader, offset, size) {
7279
7424
  if (size > 0) {
7280
7425
  const { writer } = zipWriter;
7281
- await createReadable(reader, { offset, size }).pipeTo(writer.writable, { preventClose: true, preventAbort: true });
7282
- writer.size += size;
7283
- zipWriter.offset += size;
7426
+ let copiedLength = 0;
7427
+ try {
7428
+ await flushBufferedData(createReadable(reader, { offset, size }), writer, UNDEFINED_VALUE, chunkLength => copiedLength += chunkLength);
7429
+ } catch (error) {
7430
+ zipWriter.hasCorruptedEntries = true;
7431
+ try {
7432
+ error.corruptedEntry = true;
7433
+ } catch {
7434
+ // ignored
7435
+ }
7436
+ throw error;
7437
+ } finally {
7438
+ writer.size += copiedLength;
7439
+ zipWriter.offset += copiedLength;
7440
+ }
7284
7441
  }
7285
7442
  }
7286
7443
 
@@ -7305,6 +7462,12 @@
7305
7462
  return signatureArray;
7306
7463
  }
7307
7464
 
7465
+ async function writeSplitZipSignature(zipWriter, writer) {
7466
+ delete zipWriter.addSplitZipSignature;
7467
+ await writeData(writer, getSplitZipSignatureArray());
7468
+ zipWriter.offset += SPLIT_ZIP_FILE_SIGNATURE_LENGTH;
7469
+ }
7470
+
7308
7471
  async function writeData(writer, array) {
7309
7472
  const { writable } = writer;
7310
7473
  const streamWriter = writable.getWriter();
@@ -7536,6 +7699,7 @@
7536
7699
  const ERR_READABLE_CONSUMED = "Readable stream already consumed";
7537
7700
  const ERR_INVALID_PASS_THROUGH = "Invalid passThrough option (use readerOptions.passThrough or set uncompressedSize for each entry)";
7538
7701
  const ERR_INVALID_READER_OPTIONS = "Invalid readerOptions (must be an object)";
7702
+ const ERR_ZIP_CRYPTO_LAST_MOD_DATE = "The last modification date of an entry encrypted with ZipCrypto cannot be changed when passThrough is set";
7539
7703
  const ERR_ABORT_EXPORT = "zipjs-abort-export";
7540
7704
  const ERR_ABORTED = "The operation was aborted";
7541
7705
  const ABORT_ERROR_NAME = "AbortError";
@@ -8403,6 +8567,7 @@
8403
8567
  versionMadeBy,
8404
8568
  comment,
8405
8569
  lastModDate,
8570
+ rawLastModDate,
8406
8571
  creationDate,
8407
8572
  lastAccessDate,
8408
8573
  uncompressedSize,
@@ -8413,6 +8578,7 @@
8413
8578
  extraFieldAES,
8414
8579
  internalFileAttributes,
8415
8580
  extraField,
8581
+ bitFlag,
8416
8582
  uid,
8417
8583
  gid
8418
8584
  } = child.data;
@@ -8450,6 +8616,16 @@
8450
8616
  encryptionStrength,
8451
8617
  compressionMethod
8452
8618
  };
8619
+ if (bitFlag) {
8620
+ passThroughOptions.dataDescriptor = bitFlag.dataDescriptor;
8621
+ }
8622
+ const lastModDateOverride = childOptions.lastModDate === UNDEFINED_VALUE ? options.lastModDate : childOptions.lastModDate;
8623
+ if (lastModDateOverride === UNDEFINED_VALUE) {
8624
+ passThroughOptions.rawLastModDate = rawLastModDate;
8625
+ } else if (zipCrypto && (!bitFlag || bitFlag.dataDescriptor) && lastModDateOverride instanceof Date &&
8626
+ getDosTimeHighByte(lastModDateOverride) != ((rawLastModDate >>> 8) & MAX_8_BITS)) {
8627
+ throw new Error(ERR_ZIP_CRYPTO_LAST_MOD_DATE);
8628
+ }
8453
8629
  }
8454
8630
  }
8455
8631
  const entryOptions = Object.assign({ lastModDate: child.defaultLastModDate }, zipEntryMetadata, options, childOptions, passThroughOptions, { directory: child.directory });
@@ -8459,6 +8635,16 @@
8459
8635
  return { name, entryOptions };
8460
8636
  }
8461
8637
 
8638
+ function getDosTimeHighByte(lastModDate) {
8639
+ let dosLastModDate = new Date(Math.ceil(Math.floor(lastModDate.getTime() / 1000) / 2) * 2000);
8640
+ if (dosLastModDate < MIN_DATE) {
8641
+ dosLastModDate = MIN_DATE;
8642
+ } else if (dosLastModDate > MAX_DATE) {
8643
+ dosLastModDate = MAX_DATE;
8644
+ }
8645
+ return ((dosLastModDate.getHours() << 3) | (dosLastModDate.getMinutes() >> 3)) & MAX_8_BITS;
8646
+ }
8647
+
8462
8648
  function getDeterminedSize(child, passThrough) {
8463
8649
  const { reader } = child;
8464
8650
  if (reader && reader.size !== UNDEFINED_VALUE) {
@@ -8802,6 +8988,7 @@
8802
8988
  exports.ERR_INVALID_PASS_THROUGH = ERR_INVALID_PASS_THROUGH;
8803
8989
  exports.ERR_INVALID_READER_OPTIONS = ERR_INVALID_READER_OPTIONS;
8804
8990
  exports.ERR_READABLE_CONSUMED = ERR_READABLE_CONSUMED;
8991
+ exports.ERR_ZIP_CRYPTO_LAST_MOD_DATE = ERR_ZIP_CRYPTO_LAST_MOD_DATE;
8805
8992
  exports.ZipDirectoryEntry = ZipDirectoryEntry;
8806
8993
  exports.ZipEntry = ZipEntry;
8807
8994
  exports.ZipFS = ZipFS;