@zip.js/zip.js 2.8.56 → 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) {
@@ -4122,6 +4125,7 @@
4122
4125
  const ERR_INVALID_STRICTNESS = "Invalid strictness (must be 'strict', 'balanced' or 'tolerant')";
4123
4126
  const ERR_INVALID_FILENAME_VALIDATION = "Invalid filenameValidation (must be 'strict', 'balanced' or 'tolerant')";
4124
4127
  const ERR_INVALID_MAX_APPENDED_DATA_SIZE = "Invalid maxAppendedDataSize (must be a number greater than or equal to 0)";
4128
+ const ERR_UNSUPPORTED_UINT64 = "64-bit value exceeds Number.MAX_SAFE_INTEGER";
4125
4129
  const DRIVE_LETTER_REGEXP = /^[a-zA-Z]:/;
4126
4130
  const CHARSET_UTF8 = "utf-8";
4127
4131
  const PROPERTY_NAME_UTF8_SUFFIX = "UTF8";
@@ -4144,6 +4148,7 @@
4144
4148
  bytes: 8
4145
4149
  }
4146
4150
  };
4151
+ const MAX_SAFE_UINT64 = BigInt(Number.MAX_SAFE_INTEGER);
4147
4152
  const MAX_END_OF_CENTRAL_DIR_PROBES = 64;
4148
4153
  const MAX_DEFLATE_EXPANSION_RATIO = 1032;
4149
4154
  const CENTRAL_DIRECTORY_UNREACHABLE = 0;
@@ -4239,7 +4244,7 @@
4239
4244
  zip64EndOfDirectoryVersion2 = getBigUint64(endOfDirectoryView, 4) > ZIP64_END_OF_CENTRAL_DIR_LENGTH - 12;
4240
4245
  if (zip64EndOfDirectoryVersion2) {
4241
4246
  const extensibleDataLength = Math.min(
4242
- Number(getBigUint64(endOfDirectoryView, 4)) - (ZIP64_END_OF_CENTRAL_DIR_LENGTH - 12),
4247
+ getBigUint64(endOfDirectoryView, 4) - (ZIP64_END_OF_CENTRAL_DIR_LENGTH - 12),
4243
4248
  reader.size - directoryDataOffset - ZIP64_END_OF_CENTRAL_DIR_LENGTH);
4244
4249
  if (extensibleDataLength > 0) {
4245
4250
  zip64EndOfDirectoryLength += extensibleDataLength;
@@ -4339,6 +4344,10 @@
4339
4344
  const commentEncoding = getOptionValue$1(zipReader, options, OPTION_COMMENT_ENCODING);
4340
4345
  const filenames = checkAmbiguity ? new Set() : UNDEFINED_VALUE;
4341
4346
  let duplicateFilename;
4347
+ const recoverWrappedFilesLength = !checkAmbiguity && !zip64EndOfDirectory;
4348
+ if (!filesLength && recoverWrappedFilesLength) {
4349
+ filesLength = getWrappedFilesLength(directoryView, directoryArray, offset);
4350
+ }
4342
4351
  for (let indexFile = 0; indexFile < filesLength; indexFile++) {
4343
4352
  const fileEntry = new ZipEntry$1(reader, zipReader.options);
4344
4353
  if (offset + CENTRAL_FILE_HEADER_LENGTH > directoryArray.length || getUint32$1(directoryView, offset) != CENTRAL_FILE_HEADER_SIGNATURE) {
@@ -4448,7 +4457,7 @@
4448
4457
  internalFileAttribute: fileEntry.internalFileAttributes,
4449
4458
  externalFileAttribute: fileEntry.externalFileAttributes,
4450
4459
  executable,
4451
- 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),
4452
4461
  zipCrypto: fileEntry.encrypted && !fileEntry.extraFieldAES
4453
4462
  });
4454
4463
  const entry = new Entry(fileEntry);
@@ -4461,6 +4470,9 @@
4461
4470
  return arrayBufferPromise;
4462
4471
  };
4463
4472
  offset = endOffset;
4473
+ if (indexFile == filesLength - 1 && recoverWrappedFilesLength) {
4474
+ filesLength += getWrappedFilesLength(directoryView, directoryArray, offset);
4475
+ }
4464
4476
  const { onprogress } = options;
4465
4477
  if (onprogress) {
4466
4478
  try {
@@ -4526,6 +4538,46 @@
4526
4538
  }
4527
4539
  }
4528
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
+
4529
4581
  let ZipEntry$1 = class ZipEntry {
4530
4582
 
4531
4583
  constructor(reader, options) {
@@ -4579,6 +4631,7 @@
4579
4631
  extraFieldLength,
4580
4632
  filenameLength
4581
4633
  } = localDirectory;
4634
+ const dataOffset = localDirectory.dataOffset = localHeaderOffset + HEADER_SIZE + filenameLength + extraFieldLength;
4582
4635
  const checkLocalDirectoryOption = getOptionValue$1(zipEntry, options, OPTION_CHECK_LOCAL_DIRECTORY);
4583
4636
  const entryStrictness = getStrictness(options, zipEntry.options);
4584
4637
  const checkLocalDirectory = getCheckLocalDirectory(checkLocalDirectoryOption, entryStrictness);
@@ -4632,7 +4685,6 @@
4632
4685
  throw new Error(ERR_ENCRYPTED);
4633
4686
  }
4634
4687
  }
4635
- const dataOffset = localHeaderOffset + HEADER_SIZE + filenameLength + extraFieldLength;
4636
4688
  if (dataOffset + compressedSize > reader.size) {
4637
4689
  throw new Error(ERR_ENTRY_DATA_OUT_OF_BOUNDS);
4638
4690
  }
@@ -4752,6 +4804,16 @@
4752
4804
  return false;
4753
4805
  }
4754
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
+
4755
4817
  function readDigitalSignature(signatureRecordArray) {
4756
4818
  if (signatureRecordArray.length >= 6) {
4757
4819
  const signatureRecordView = getDataView(signatureRecordArray);
@@ -4780,8 +4842,8 @@
4780
4842
  const hashDataLength = getUint16$1(extensibleDataView, 26);
4781
4843
  Object.assign(directoryEncryptionInfo, {
4782
4844
  compressionMethod: getUint16$1(extensibleDataView, 0),
4783
- compressedSize: Number(getBigUint64(extensibleDataView, 2)),
4784
- uncompressedSize: Number(getBigUint64(extensibleDataView, 10)),
4845
+ compressedSize: getBigUint64(extensibleDataView, 2),
4846
+ uncompressedSize: getBigUint64(extensibleDataView, 10),
4785
4847
  encryptionAlgorithm: getUint16$1(extensibleDataView, 18),
4786
4848
  bitLength: getUint16$1(extensibleDataView, 20),
4787
4849
  flags: getUint16$1(extensibleDataView, 22),
@@ -4924,10 +4986,11 @@
4924
4986
  const computedCrc32View = getDataView(new Uint8Array(4));
4925
4987
  computedCrc32View.setUint32(0, computedCrc32.get(), true);
4926
4988
  const nameCrc32 = getUint32$1(extraFieldView, 1);
4989
+ const version = getUint8(extraFieldView, 0);
4927
4990
  Object.assign(extraFieldUnicode, {
4928
- version: getUint8(extraFieldView, 0),
4991
+ version,
4929
4992
  [propertyName]: decodeText(extraFieldUnicode.data.subarray(5)),
4930
- valid: !fileEntry.bitFlag.languageEncodingFlag && nameCrc32 == getUint32$1(computedCrc32View, 0)
4993
+ valid: version == 1 && !fileEntry.bitFlag.languageEncodingFlag && nameCrc32 == getUint32$1(computedCrc32View, 0)
4931
4994
  });
4932
4995
  if (extraFieldUnicode.valid) {
4933
4996
  directory[propertyName] = extraFieldUnicode[propertyName];
@@ -5396,7 +5459,8 @@
5396
5459
 
5397
5460
  function getDate(timeRaw) {
5398
5461
  const date = (timeRaw & 0xffff0000) >> 16, time = timeRaw & MAX_16_BITS;
5399
- 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;
5400
5464
  }
5401
5465
 
5402
5466
  function getDateNTFS(timeRaw) {
@@ -5416,7 +5480,11 @@
5416
5480
  }
5417
5481
 
5418
5482
  function getBigUint64(view, offset) {
5419
- return Number(view.getBigUint64(offset, true));
5483
+ const value = view.getBigUint64(offset, true);
5484
+ if (value > MAX_SAFE_UINT64) {
5485
+ throw new Error(ERR_UNSUPPORTED_UINT64);
5486
+ }
5487
+ return Number(value);
5420
5488
  }
5421
5489
 
5422
5490
  var zipReader = /*#__PURE__*/Object.freeze({
@@ -5445,7 +5513,10 @@
5445
5513
  ERR_UNSAFE_FILENAME: ERR_UNSAFE_FILENAME,
5446
5514
  ERR_UNSUPPORTED_COMPRESSION: ERR_UNSUPPORTED_COMPRESSION$1,
5447
5515
  ERR_UNSUPPORTED_ENCRYPTION: ERR_UNSUPPORTED_ENCRYPTION,
5448
- ZipReader: ZipReader
5516
+ ERR_UNSUPPORTED_UINT64: ERR_UNSUPPORTED_UINT64,
5517
+ ERR_WORKER_STARTUP_TIMEOUT: ERR_WORKER_STARTUP_TIMEOUT,
5518
+ ZipReader: ZipReader,
5519
+ ZipReaderStream: ZipReaderStream
5449
5520
  });
5450
5521
 
5451
5522
  /*
@@ -5542,153 +5613,150 @@
5542
5613
  offset: options[OPTION_OFFSET] === UNDEFINED_VALUE ? writer.size || writer.writable.size || 0 : options[OPTION_OFFSET],
5543
5614
  initialOffset: options[OPTION_OFFSET] === UNDEFINED_VALUE ? 0 : options[OPTION_OFFSET] - (writer.size || writer.writable.size || 0),
5544
5615
  pendingAddFileCalls: new Set(),
5616
+ pendingErrors: [],
5545
5617
  bufferedWrites: 0,
5546
5618
  lastFileEntry: UNDEFINED_VALUE
5547
5619
  });
5548
5620
  }
5549
5621
 
5550
- async prependZip(reader) {
5551
- if (this.filenames.size) {
5552
- throw new Error(ERR_ZIP_NOT_EMPTY);
5553
- }
5554
- reader = new GenericReader(reader);
5555
- await initStream(reader);
5556
- if (reader.size === UNDEFINED_VALUE || !reader.readUint8Array) {
5557
- reader = new BlobReader(await streamToBlob(reader.readable));
5558
- await initStream(reader);
5559
- }
5560
- const { ZipReader } = await Promise.resolve().then(function () { return zipReader; });
5561
- const zipReader$1 = new ZipReader(reader);
5562
- const entries = await zipReader$1.getEntries();
5563
- await zipReader$1.close();
5564
- await initStream(this.writer);
5565
- const { directoryOffset } = zipReader$1;
5566
- if (this.addSplitZipSignature) {
5567
- delete this.addSplitZipSignature;
5568
- if (!await startsWithSplitZipSignature(reader)) {
5569
- await writeData(this.writer, getSplitZipSignatureArray());
5570
- this.offset += SPLIT_ZIP_FILE_SIGNATURE_LENGTH;
5571
- }
5572
- }
5573
- const entryPositions = await copyZipData(this, reader, entries, directoryOffset);
5574
- this.filenames = new Set(entries.map(entry => entry.filename));
5575
- this.fileEntries = new Map(entries.map(entry => {
5576
- const {
5577
- version,
5578
- rawLastModDate,
5579
- lastAccessDate,
5580
- creationDate,
5581
- rawFilename,
5582
- bitFlag,
5583
- encrypted,
5584
- uncompressedSize,
5585
- compressedSize,
5586
- zip64
5587
- } = entry;
5588
- let {
5589
- compressionMethod,
5590
- rawExtraFieldZip64,
5591
- rawExtraFieldAES,
5592
- rawExtraFieldExtendedTimestamp,
5593
- rawExtraFieldNTFS,
5594
- rawExtraFieldUnix,
5595
- rawExtraField,
5596
- } = entry;
5597
- const { level, languageEncodingFlag, dataDescriptor } = bitFlag;
5598
- rawExtraFieldZip64 = rawExtraFieldZip64 || EMPTY_UINT8_ARRAY;
5599
- rawExtraFieldAES = rawExtraFieldAES || EMPTY_UINT8_ARRAY;
5600
- rawExtraFieldExtendedTimestamp = rawExtraFieldExtendedTimestamp || EMPTY_UINT8_ARRAY;
5601
- rawExtraFieldNTFS = rawExtraFieldNTFS || EMPTY_UINT8_ARRAY;
5602
- rawExtraFieldUnix = rawExtraFieldUnix || EMPTY_UINT8_ARRAY;
5603
- rawExtraField = rawExtraField || EMPTY_UINT8_ARRAY;
5604
- if (entry.extraFieldAES) {
5605
- compressionMethod = COMPRESSION_METHOD_AES;
5606
- }
5607
- const extraFieldLength = getLength(rawExtraFieldZip64, rawExtraFieldAES, rawExtraFieldExtendedTimestamp, rawExtraFieldNTFS, rawExtraFieldUnix, rawExtraField);
5608
- const zip64UncompressedSize = zip64 && uncompressedSize >= MAX_32_BITS;
5609
- const zip64CompressedSize = zip64 && compressedSize >= MAX_32_BITS;
5610
- const bitFlagValue = (getBitFlag(level, languageEncodingFlag, dataDescriptor, encrypted, compressionMethod) & ~BITFLAG_LEVEL) | (level << 1);
5611
- const {
5612
- headerArray,
5613
- headerView
5614
- } = getHeaderArrayData({
5615
- version,
5616
- bitFlag: bitFlagValue,
5617
- compressionMethod,
5618
- uncompressedSize,
5619
- compressedSize,
5620
- rawLastModDate,
5621
- rawFilename,
5622
- zip64CompressedSize,
5623
- zip64UncompressedSize,
5624
- extraFieldLength
5625
- });
5626
- const { crc32 } = entry;
5627
- if (crc32 !== UNDEFINED_VALUE) {
5628
- setUint32(headerView, HEADER_OFFSET_SIGNATURE, crc32);
5629
- }
5630
- const { offset, diskNumberStart } = entryPositions.get(entry);
5631
- Object.assign(entry, {
5632
- zip64UncompressedSize,
5633
- zip64CompressedSize,
5634
- offset,
5635
- diskNumberStart,
5636
- zip64DiskNumberStart: false,
5637
- rawExtraFieldZip64,
5638
- rawExtraFieldAES,
5639
- rawExtraFieldExtendedTimestamp,
5640
- rawExtraFieldNTFS,
5641
- rawExtraFieldUnix,
5642
- rawExtraField,
5643
- extendedTimestamp: rawExtraFieldExtendedTimestamp.length > 0 || rawExtraFieldNTFS.length > 0,
5644
- extraFieldExtendedTimestampFlag: 0x1 + (lastAccessDate ? 0x2 : 0) + (creationDate ? 0x4 : 0),
5645
- headerArray,
5646
- headerView
5647
- });
5648
- return [entry.filename, entry];
5649
- }));
5622
+ prependZip(reader) {
5623
+ return watchPromiseError(this, prependZipEntries(this, reader));
5624
+ }
5625
+
5626
+ appendZip(reader) {
5627
+ return watchPromiseError(this, this.appendZipEntries(reader));
5650
5628
  }
5651
5629
 
5652
- async add(name = "", reader, options = {}) {
5630
+ async appendZipEntries(reader) {
5653
5631
  const zipWriter = this;
5654
- options = Object.assign({}, options);
5655
- const { pendingAddFileCalls } = zipWriter;
5656
- if (workers < getConfiguration().maxWorkers) {
5657
- workers++;
5658
- } else {
5659
- await new Promise(resolve => pendingEntries.push(resolve));
5632
+ const { pendingAddFileCalls, filenames, fileEntries } = zipWriter;
5633
+ while (pendingAddFileCalls.size) {
5634
+ await Promise.allSettled(Array.from(pendingAddFileCalls));
5660
5635
  }
5661
- let promiseAddFile;
5662
- let nameAdded;
5636
+ let resolveAppendZip;
5637
+ const promiseAppendZip = new Promise(resolve => resolveAppendZip = resolve);
5638
+ pendingAddFileCalls.add(promiseAppendZip);
5639
+ const appendedFilenames = [];
5640
+ let releaseLockWriter;
5663
5641
  try {
5664
- name = name.trim();
5665
- if (getOptionValue(zipWriter, options, PROPERTY_NAME_DIRECTORY) && !name.endsWith(DIRECTORY_SIGNATURE)) {
5666
- name += DIRECTORY_SIGNATURE;
5667
- }
5668
- if (zipWriter.filenames.has(name)) {
5669
- throw new Error(ERR_DUPLICATED_NAME);
5670
- }
5671
- zipWriter.filenames.add(name);
5672
- nameAdded = true;
5673
- promiseAddFile = addFile(zipWriter, name, reader, options);
5674
- pendingAddFileCalls.add(promiseAddFile);
5675
- return await promiseAddFile;
5676
- } catch (error) {
5677
- if (nameAdded) {
5678
- 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
+ }
5679
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));
5680
5740
  throw error;
5681
5741
  } finally {
5682
- pendingAddFileCalls.delete(promiseAddFile);
5683
- const pendingEntry = pendingEntries.shift();
5684
- if (pendingEntry) {
5685
- pendingEntry();
5686
- } else {
5687
- workers--;
5742
+ resolveAppendZip();
5743
+ pendingAddFileCalls.delete(promiseAppendZip);
5744
+ if (releaseLockWriter) {
5745
+ releaseLockWriter();
5688
5746
  }
5689
5747
  }
5690
5748
  }
5691
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
+
5692
5760
  remove(entry) {
5693
5761
  const { filenames, fileEntries } = this;
5694
5762
  // deno-lint-ignore valid-typeof
@@ -5719,6 +5787,19 @@
5719
5787
  while (pendingAddFileCalls.size) {
5720
5788
  await Promise.allSettled(Array.from(pendingAddFileCalls));
5721
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
+ }
5722
5803
  await closeFile(zipWriter, comment, options);
5723
5804
  const preventClose = !ownsWritable(writer) && getOptionValue(zipWriter, options, OPTION_PREVENT_CLOSE);
5724
5805
  if (!preventClose) {
@@ -5728,6 +5809,63 @@
5728
5809
  }
5729
5810
  }
5730
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
+
5731
5869
  async function addFile(zipWriter, name, reader, options) {
5732
5870
  const attributesInfo = resolveAttributes(zipWriter, name, options);
5733
5871
  ({ name } = attributesInfo);
@@ -5916,11 +6054,12 @@
5916
6054
  if (getLength(rawComment) > MAX_16_BITS) {
5917
6055
  throw new Error(ERR_INVALID_ENTRY_COMMENT);
5918
6056
  }
5919
- const version = getOptionValue(zipWriter, options, PROPERTY_NAME_VERSION, VERSION_DEFLATE);
5920
- if (version > MAX_16_BITS) {
6057
+ const version = getOptionValue(zipWriter, options, PROPERTY_NAME_VERSION);
6058
+ if (version !== UNDEFINED_VALUE && version > MAX_16_BITS) {
5921
6059
  throw new Error(ERR_INVALID_VERSION);
5922
6060
  }
5923
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);
5924
6063
  const lastAccessDate = getDateOptionValue(zipWriter, options, PROPERTY_NAME_LAST_ACCESS_DATE);
5925
6064
  const creationDate = getDateOptionValue(zipWriter, options, PROPERTY_NAME_CREATION_DATE);
5926
6065
  const internalFileAttributes = getAliasedOptionValue(zipWriter, options, PROPERTY_NAME_INTERNAL_FILE_ATTRIBUTES, PROPERTY_NAME_DEPRECATED_INTERNAL_FILE_ATTRIBUTES, 0);
@@ -5964,7 +6103,7 @@
5964
6103
  if (bufferedWrite && dataDescriptor === UNDEFINED_VALUE) {
5965
6104
  dataDescriptor = false;
5966
6105
  }
5967
- if (dataDescriptor === UNDEFINED_VALUE || zipCrypto) {
6106
+ if (dataDescriptor === UNDEFINED_VALUE || (zipCrypto && !passThrough)) {
5968
6107
  dataDescriptor = true;
5969
6108
  }
5970
6109
  if (level !== UNDEFINED_VALUE && level != 6) {
@@ -5983,6 +6122,7 @@
5983
6122
  rawComment,
5984
6123
  version,
5985
6124
  lastModDate,
6125
+ rawLastModDate,
5986
6126
  lastAccessDate,
5987
6127
  creationDate,
5988
6128
  internalFileAttributes,
@@ -6100,6 +6240,10 @@
6100
6240
  maximumCompressedSize = contentSize === UNDEFINED_VALUE ? getMaximumCompressedSize(uncompressedSize) + encryptionOverhead : contentSize;
6101
6241
  }
6102
6242
  }
6243
+ const emptyEntry = !encryptedEntry && (!hasContent || (contentSize === 0 && !passThrough)) && !isCompressed(compressionMethod, level);
6244
+ if (emptyEntry && !zipCrypto && getOptionValue(zipWriter, options, OPTION_DATA_DESCRIPTOR) === UNDEFINED_VALUE) {
6245
+ dataDescriptor = false;
6246
+ }
6103
6247
  const zip64UncompressedSize = zip64Enabled || uncompressedSize >= MAX_32_BITS;
6104
6248
  const zip64CompressedSize = zip64Enabled || maximumCompressedSize >= MAX_32_BITS;
6105
6249
  if (zip64UncompressedSize || zip64CompressedSize) {
@@ -6114,6 +6258,7 @@
6114
6258
  maximumCompressedSize,
6115
6259
  resolvedOptions: {
6116
6260
  dataDescriptor,
6261
+ emptyEntry,
6117
6262
  zip64,
6118
6263
  zip64UncompressedSize,
6119
6264
  zip64CompressedSize,
@@ -6212,6 +6357,7 @@
6212
6357
  const {
6213
6358
  keepOrder,
6214
6359
  dataDescriptor,
6360
+ emptyEntry,
6215
6361
  signal
6216
6362
  } = options;
6217
6363
  const {
@@ -6236,7 +6382,7 @@
6236
6382
  lockPreviousFileEntry = previousFileEntry && previousFileEntry.lockFileEntry;
6237
6383
  requestLockCurrentFileEntry();
6238
6384
  }
6239
- if (options.bufferedWrite || !keepOrder || zipWriter.writerLocked || zipWriter.bufferedWrites || !dataDescriptor) {
6385
+ if (options.bufferedWrite || !keepOrder || zipWriter.writerLocked || zipWriter.bufferedWrites || (!dataDescriptor && !emptyEntry)) {
6240
6386
  bufferedWrite = true;
6241
6387
  zipWriter.bufferedWrites++;
6242
6388
  if (options.createTempStream) {
@@ -6252,10 +6398,8 @@
6252
6398
  }
6253
6399
  await initStream(fileWriter);
6254
6400
  const diskOffset = getDiskOffset(writer);
6255
- if (zipWriter.addSplitZipSignature) {
6256
- delete zipWriter.addSplitZipSignature;
6257
- await writeData(writer, getSplitZipSignatureArray());
6258
- zipWriter.offset += SPLIT_ZIP_FILE_SIGNATURE_LENGTH;
6401
+ if (zipWriter.addSplitZipSignature && !bufferedWrite) {
6402
+ await writeSplitZipSignature(zipWriter, writer);
6259
6403
  }
6260
6404
  if (usdz && !bufferedWrite) {
6261
6405
  appendExtraFieldUSDZ(entryInfo, zipWriter.offset - diskOffset);
@@ -6282,6 +6426,9 @@
6282
6426
  if (bufferedWrite) {
6283
6427
  await Promise.all([fileWriter.writable.getWriter().close(), lockPreviousFileEntry]);
6284
6428
  await requestLockWriter();
6429
+ if (zipWriter.addSplitZipSignature) {
6430
+ await writeSplitZipSignature(zipWriter, writer);
6431
+ }
6285
6432
  writingBufferedEntryData = true;
6286
6433
  writerSizeBeforeEntry = writer.size;
6287
6434
  await skipDiskIfNeeded();
@@ -6553,6 +6700,7 @@
6553
6700
  const {
6554
6701
  rawFilename,
6555
6702
  lastModDate,
6703
+ rawLastModDate: rawLastModDateOption,
6556
6704
  lastAccessDate,
6557
6705
  creationDate,
6558
6706
  level,
@@ -6658,8 +6806,8 @@
6658
6806
  try {
6659
6807
  const { uid, gid, unixExtraFieldType } = options;
6660
6808
  if (unixExtraFieldType == INFOZIP_EXTRA_FIELD_TYPE$1 && (uid !== UNDEFINED_VALUE || gid !== UNDEFINED_VALUE)) {
6661
- const uidBytes = packUnixId(uid);
6662
- const gidBytes = packUnixId(gid);
6809
+ const uidBytes = packUnixId(uid === UNDEFINED_VALUE ? 0 : uid);
6810
+ const gidBytes = packUnixId(gid === UNDEFINED_VALUE ? 0 : gid);
6663
6811
  const payloadLength = 3 + uidBytes.length + gidBytes.length;
6664
6812
  const extraFieldUnix = createRecordWriter(4 + payloadLength);
6665
6813
  extraFieldUnix.writeUint16(EXTRAFIELD_TYPE_INFOZIP);
@@ -6686,6 +6834,9 @@
6686
6834
  if (compressionMethod === UNDEFINED_VALUE) {
6687
6835
  compressionMethod = compressed ? COMPRESSION_METHOD_DEFLATE : COMPRESSION_METHOD_STORE;
6688
6836
  }
6837
+ if (version === UNDEFINED_VALUE) {
6838
+ version = compressionMethod == COMPRESSION_METHOD_STORE && !directory && !encrypted ? VERSION_STORE : VERSION_DEFLATE;
6839
+ }
6689
6840
  const { codecVersionNeeded } = options;
6690
6841
  if (compressed && codecVersionNeeded !== UNDEFINED_VALUE) {
6691
6842
  version = version > codecVersionNeeded ? version : codecVersionNeeded;
@@ -6718,6 +6869,7 @@
6718
6869
  compressionMethod,
6719
6870
  uncompressedSize,
6720
6871
  lastModDate: dosLastModDate < MIN_DATE ? MIN_DATE : dosLastModDate > MAX_DATE ? MAX_DATE : dosLastModDate,
6872
+ rawLastModDate: rawLastModDateOption,
6721
6873
  rawFilename,
6722
6874
  zip64CompressedSize,
6723
6875
  zip64UncompressedSize,
@@ -6790,18 +6942,14 @@
6790
6942
  }
6791
6943
 
6792
6944
  function packUnixId(id) {
6793
- if (id === UNDEFINED_VALUE) {
6794
- return EMPTY_UINT8_ARRAY;
6795
- } else {
6796
- const dataArray = new Uint8Array(4);
6797
- const dataView = getDataView(dataArray);
6798
- dataView.setUint32(0, id, true);
6799
- let length = 4;
6800
- while (length > 1 && dataArray[length - 1] === 0) {
6801
- length--;
6802
- }
6803
- return dataArray.subarray(0, length);
6945
+ const dataArray = new Uint8Array(4);
6946
+ const dataView = getDataView(dataArray);
6947
+ dataView.setUint32(0, id, true);
6948
+ let length = 4;
6949
+ while (length > 1 && dataArray[length - 1] === 0) {
6950
+ length--;
6804
6951
  }
6952
+ return dataArray.subarray(0, length);
6805
6953
  }
6806
6954
 
6807
6955
  function normalizeMsdosAttributes(msdosAttributesRaw, msdosAttributes) {
@@ -6928,9 +7076,9 @@
6928
7076
 
6929
7077
  async function closeFile(zipWriter, comment, options) {
6930
7078
  const directoryDataLength = createDirectoryRecords(zipWriter.fileEntries);
6931
- const { directoryStart, directoryArray } = await writeDirectoryRecords(zipWriter, directoryDataLength, options);
7079
+ const { directoryStart, directoryEnd, directoryArray } = await writeDirectoryRecords(zipWriter, directoryDataLength, options);
6932
7080
  const signatureLength = await writeDigitalSignatureRecord(zipWriter, directoryArray, options);
6933
- await writeEndOfDirectoryRecord(zipWriter, comment, options, { directoryStart, directoryDataLength, signatureLength });
7081
+ await writeEndOfDirectoryRecord(zipWriter, comment, options, { directoryStart, directoryEnd, directoryDataLength, signatureLength });
6934
7082
  }
6935
7083
 
6936
7084
  function createDirectoryRecords(files) {
@@ -7014,6 +7162,7 @@
7014
7162
  let directoryDiskOffset = 0;
7015
7163
  let directoryStartDiskNumber = getDiskNumber(writer);
7016
7164
  let directoryStartDiskOffset = getDiskOffset(writer);
7165
+ let directoryEndDiskEntriesLength = 0;
7017
7166
  for (const [indexFileEntry, fileEntry] of Array.from(fileEntries.values()).entries()) {
7018
7167
  const {
7019
7168
  offset: fileEntryOffset,
@@ -7043,6 +7192,7 @@
7043
7192
  if (exceedsAvailableSize(writer, offset + directoryRecordLength - directoryDiskOffset)) {
7044
7193
  await writeData(writer, directoryArray.slice(directoryDiskOffset, offset));
7045
7194
  directoryDiskOffset = offset;
7195
+ directoryEndDiskEntriesLength = 0;
7046
7196
  await writer.closeDisk();
7047
7197
  }
7048
7198
  if (indexFileEntry == 0) {
@@ -7078,6 +7228,7 @@
7078
7228
  directoryRecord.writeBytes(rawComment);
7079
7229
  arraySet(directoryArray, directoryRecord.array, offset);
7080
7230
  offset += directoryRecordLength;
7231
+ directoryEndDiskEntriesLength++;
7081
7232
  if (options.onprogress) {
7082
7233
  try {
7083
7234
  await options.onprogress(indexFileEntry + 1, fileEntries.size, new Entry(fileEntry));
@@ -7089,6 +7240,7 @@
7089
7240
  await writeData(writer, directoryDiskOffset ? directoryArray.slice(directoryDiskOffset) : directoryArray);
7090
7241
  return {
7091
7242
  directoryStart: { diskNumber: directoryStartDiskNumber, diskOffset: directoryStartDiskOffset },
7243
+ directoryEnd: { diskNumber: getDiskNumber(writer), entriesLength: directoryEndDiskEntriesLength },
7092
7244
  directoryArray
7093
7245
  };
7094
7246
  }
@@ -7117,16 +7269,20 @@
7117
7269
 
7118
7270
  async function writeEndOfDirectoryRecord(zipWriter, comment, options, cdInfo) {
7119
7271
  const { writer } = zipWriter;
7120
- const { directoryStart, signatureLength } = cdInfo;
7272
+ const { directoryStart, directoryEnd, signatureLength } = cdInfo;
7121
7273
  let { directoryDataLength } = cdInfo;
7122
7274
  let fileEntriesLength = zipWriter.fileEntries.size;
7123
7275
  let diskNumber = directoryStart.diskNumber;
7124
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);
7125
7282
  let lastDiskNumber = getDiskNumber(writer);
7126
- 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)) {
7127
7284
  lastDiskNumber++;
7128
7285
  }
7129
- let zip64 = getOptionValue(zipWriter, options, PROPERTY_NAME_ZIP64);
7130
7286
  if (directoryOffset >= MAX_32_BITS || directoryDataLength >= MAX_32_BITS || fileEntriesLength >= MAX_16_BITS || lastDiskNumber >= MAX_16_BITS) {
7131
7287
  if (zip64 === false) {
7132
7288
  throw new Error(ERR_UNSUPPORTED_FORMAT);
@@ -7134,15 +7290,12 @@
7134
7290
  zip64 = true;
7135
7291
  }
7136
7292
  }
7137
- const commentLength = getLength(comment);
7138
- if (commentLength > MAX_16_BITS) {
7139
- throw new Error(ERR_INVALID_COMMENT);
7140
- }
7141
7293
  const endOfdirectoryRecord = createRecordWriter(zip64 ? ZIP64_END_OF_CENTRAL_DIR_TOTAL_LENGTH : END_OF_CENTRAL_DIR_LENGTH);
7142
7294
  if (exceedsAvailableSize(writer, getLength(endOfdirectoryRecord.array) + commentLength)) {
7143
7295
  await writer.closeDisk();
7144
7296
  }
7145
7297
  lastDiskNumber = getDiskNumber(writer);
7298
+ let diskFileEntriesLength = lastDiskNumber == directoryEnd.diskNumber ? directoryEnd.entriesLength : 0;
7146
7299
  if (zip64) {
7147
7300
  endOfdirectoryRecord.writeUint32(ZIP64_END_OF_CENTRAL_DIR_SIGNATURE);
7148
7301
  endOfdirectoryRecord.writeUint64(44);
@@ -7150,7 +7303,7 @@
7150
7303
  endOfdirectoryRecord.writeUint16(45);
7151
7304
  endOfdirectoryRecord.writeUint32(lastDiskNumber);
7152
7305
  endOfdirectoryRecord.writeUint32(diskNumber);
7153
- endOfdirectoryRecord.writeUint64(fileEntriesLength);
7306
+ endOfdirectoryRecord.writeUint64(diskFileEntriesLength);
7154
7307
  endOfdirectoryRecord.writeUint64(fileEntriesLength);
7155
7308
  endOfdirectoryRecord.writeUint64(directoryDataLength);
7156
7309
  endOfdirectoryRecord.writeUint64(directoryOffset);
@@ -7163,6 +7316,7 @@
7163
7316
  lastDiskNumber = MAX_16_BITS;
7164
7317
  diskNumber = MAX_16_BITS;
7165
7318
  }
7319
+ diskFileEntriesLength = MAX_16_BITS;
7166
7320
  fileEntriesLength = MAX_16_BITS;
7167
7321
  directoryOffset = MAX_32_BITS;
7168
7322
  directoryDataLength = MAX_32_BITS;
@@ -7170,7 +7324,7 @@
7170
7324
  endOfdirectoryRecord.writeUint32(END_OF_CENTRAL_DIR_SIGNATURE);
7171
7325
  endOfdirectoryRecord.writeUint16(lastDiskNumber);
7172
7326
  endOfdirectoryRecord.writeUint16(diskNumber);
7173
- endOfdirectoryRecord.writeUint16(fileEntriesLength);
7327
+ endOfdirectoryRecord.writeUint16(diskFileEntriesLength);
7174
7328
  endOfdirectoryRecord.writeUint16(fileEntriesLength);
7175
7329
  endOfdirectoryRecord.writeUint32(directoryDataLength);
7176
7330
  endOfdirectoryRecord.writeUint32(directoryOffset);
@@ -7220,6 +7374,21 @@
7220
7374
  return getUint32(getDataView(signatureArray), 0) == SPLIT_ZIP_FILE_SIGNATURE;
7221
7375
  }
7222
7376
 
7377
+ function removeExtraFieldZip64(rawExtraField) {
7378
+ const rawExtraFieldView = getDataView(rawExtraField);
7379
+ let offsetExtraField = 0;
7380
+ while (offsetExtraField + 4 <= getLength(rawExtraField)) {
7381
+ const size = 4 + getUint16(rawExtraFieldView, offsetExtraField + 2);
7382
+ if (getUint16(rawExtraFieldView, offsetExtraField) == EXTRAFIELD_TYPE_ZIP64) {
7383
+ return removeExtraFieldZip64(concat(
7384
+ rawExtraField.subarray(0, offsetExtraField),
7385
+ rawExtraField.subarray(Math.min(offsetExtraField + size, getLength(rawExtraField)))));
7386
+ }
7387
+ offsetExtraField += size;
7388
+ }
7389
+ return rawExtraField;
7390
+ }
7391
+
7223
7392
  async function copyZipData(zipWriter, reader, entries, directoryOffset) {
7224
7393
  const { writer } = zipWriter;
7225
7394
  const entryPositions = new Map();
@@ -7254,9 +7423,21 @@
7254
7423
  async function copyData(zipWriter, reader, offset, size) {
7255
7424
  if (size > 0) {
7256
7425
  const { writer } = zipWriter;
7257
- await createReadable(reader, { offset, size }).pipeTo(writer.writable, { preventClose: true, preventAbort: true });
7258
- writer.size += size;
7259
- 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
+ }
7260
7441
  }
7261
7442
  }
7262
7443
 
@@ -7281,6 +7462,12 @@
7281
7462
  return signatureArray;
7282
7463
  }
7283
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
+
7284
7471
  async function writeData(writer, array) {
7285
7472
  const { writable } = writer;
7286
7473
  const streamWriter = writable.getWriter();
@@ -7512,6 +7699,7 @@
7512
7699
  const ERR_READABLE_CONSUMED = "Readable stream already consumed";
7513
7700
  const ERR_INVALID_PASS_THROUGH = "Invalid passThrough option (use readerOptions.passThrough or set uncompressedSize for each entry)";
7514
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";
7515
7703
  const ERR_ABORT_EXPORT = "zipjs-abort-export";
7516
7704
  const ERR_ABORTED = "The operation was aborted";
7517
7705
  const ABORT_ERROR_NAME = "AbortError";
@@ -8269,7 +8457,7 @@
8269
8457
  } else if (writer.constructor == BlobWriter) {
8270
8458
  return data.type == contentType;
8271
8459
  } else if (writer.constructor == Data64URIWriter) {
8272
- return data.startsWith(writer.data);
8460
+ return data.startsWith("data:" + (contentType || "") + ";base64,");
8273
8461
  } else {
8274
8462
  return true;
8275
8463
  }
@@ -8379,6 +8567,7 @@
8379
8567
  versionMadeBy,
8380
8568
  comment,
8381
8569
  lastModDate,
8570
+ rawLastModDate,
8382
8571
  creationDate,
8383
8572
  lastAccessDate,
8384
8573
  uncompressedSize,
@@ -8389,6 +8578,7 @@
8389
8578
  extraFieldAES,
8390
8579
  internalFileAttributes,
8391
8580
  extraField,
8581
+ bitFlag,
8392
8582
  uid,
8393
8583
  gid
8394
8584
  } = child.data;
@@ -8426,6 +8616,16 @@
8426
8616
  encryptionStrength,
8427
8617
  compressionMethod
8428
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
+ }
8429
8629
  }
8430
8630
  }
8431
8631
  const entryOptions = Object.assign({ lastModDate: child.defaultLastModDate }, zipEntryMetadata, options, childOptions, passThroughOptions, { directory: child.directory });
@@ -8435,6 +8635,16 @@
8435
8635
  return { name, entryOptions };
8436
8636
  }
8437
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
+
8438
8648
  function getDeterminedSize(child, passThrough) {
8439
8649
  const { reader } = child;
8440
8650
  if (reader && reader.size !== UNDEFINED_VALUE) {
@@ -8778,6 +8988,7 @@
8778
8988
  exports.ERR_INVALID_PASS_THROUGH = ERR_INVALID_PASS_THROUGH;
8779
8989
  exports.ERR_INVALID_READER_OPTIONS = ERR_INVALID_READER_OPTIONS;
8780
8990
  exports.ERR_READABLE_CONSUMED = ERR_READABLE_CONSUMED;
8991
+ exports.ERR_ZIP_CRYPTO_LAST_MOD_DATE = ERR_ZIP_CRYPTO_LAST_MOD_DATE;
8781
8992
  exports.ZipDirectoryEntry = ZipDirectoryEntry;
8782
8993
  exports.ZipEntry = ZipEntry;
8783
8994
  exports.ZipFS = ZipFS;