@zip.js/zip.js 2.20.0 → 2.21.0

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.
@@ -117,6 +117,10 @@ const MIN_DATE = new Date(1980, 0, 1);
117
117
 
118
118
  const UNDEFINED_VALUE = undefined;
119
119
  const INFINITY_VALUE = Infinity;
120
+ const ERR_LOCAL_FILE_HEADER_NOT_FOUND = "Local file header not found";
121
+ const ERR_OVERLAPPING_ENTRY = "Overlapping entry found";
122
+ const ERR_EXTRAFIELD_ZIP64_NOT_FOUND = "Zip64 extra field not found";
123
+
120
124
  const UNDEFINED_TYPE = "undefined";
121
125
  const FUNCTION_TYPE = "function";
122
126
  const OBJECT_TYPE = "object";
@@ -4810,12 +4814,9 @@ const ERR_BAD_FORMAT = "File format is not recognized";
4810
4814
  const ERR_EOCDR_NOT_FOUND = "End of central directory not found";
4811
4815
  const ERR_EOCDR_LOCATOR_ZIP64_NOT_FOUND = "End of Zip64 central directory locator not found";
4812
4816
  const ERR_CENTRAL_DIRECTORY_NOT_FOUND = "Central directory header not found";
4813
- const ERR_LOCAL_FILE_HEADER_NOT_FOUND = "Local file header not found";
4814
- const ERR_EXTRAFIELD_ZIP64_NOT_FOUND = "Zip64 extra field not found";
4815
4817
  const ERR_ENCRYPTED = "File contains encrypted entry";
4816
4818
  const ERR_UNSUPPORTED_ENCRYPTION = "Encryption method not supported";
4817
4819
  const ERR_SPLIT_ZIP_FILE = "Split zip file";
4818
- const ERR_OVERLAPPING_ENTRY = "Overlapping entry found";
4819
4820
  const ERR_ENTRY_DATA_OUT_OF_BOUNDS = "Entry data out of bounds";
4820
4821
  const ERR_AMBIGUOUS_ARCHIVE = "Ambiguous archive";
4821
4822
  const ERR_ENCRYPTED_CENTRAL_DIRECTORY = "Encrypted central directory is not supported";
@@ -4880,7 +4881,8 @@ class ZipReader {
4880
4881
  Object.assign(this, {
4881
4882
  reader: new GenericReader(reader),
4882
4883
  options,
4883
- readRanges: { indexes: new Set(), sortedRanges: [], pendingRanges: [] }
4884
+ readRanges: { indexes: new Set(), sortedRanges: [], pendingRanges: [] },
4885
+ entriesMissingZip64ExtraField: new WeakSet()
4884
4886
  });
4885
4887
  }
4886
4888
 
@@ -4951,16 +4953,22 @@ class ZipReader {
4951
4953
  directoryDataOffset = getDiskOffset$1(reader, getUint32$1(endOfDirectoryLocatorView, 4)) + getBigUint64(endOfDirectoryLocatorView, 8);
4952
4954
  let endOfDirectoryArray = await readUint8Array(reader, directoryDataOffset, ZIP64_END_OF_CENTRAL_DIR_LENGTH);
4953
4955
  let endOfDirectoryView = getDataView(endOfDirectoryArray);
4954
- const expectedDirectoryDataOffset = endOfDirectoryInfo.offset - ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH - ZIP64_END_OF_CENTRAL_DIR_LENGTH;
4955
- if ((endOfDirectoryArray.length < ZIP64_END_OF_CENTRAL_DIR_LENGTH || getUint32$1(endOfDirectoryView, 0) != ZIP64_END_OF_CENTRAL_DIR_SIGNATURE) &&
4956
- directoryDataOffset != expectedDirectoryDataOffset && expectedDirectoryDataOffset >= 0) {
4957
- const originalDirectoryDataOffset = directoryDataOffset;
4958
- directoryDataOffset = expectedDirectoryDataOffset;
4959
- if (directoryDataOffset > originalDirectoryDataOffset) {
4960
- prependedDataLength = directoryDataOffset - originalDirectoryDataOffset;
4956
+ if (endOfDirectoryArray.length < ZIP64_END_OF_CENTRAL_DIR_LENGTH || getUint32$1(endOfDirectoryView, 0) != ZIP64_END_OF_CENTRAL_DIR_SIGNATURE) {
4957
+ const locatorOffset = endOfDirectoryInfo.offset - ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH;
4958
+ let expectedDirectoryDataOffset = locatorOffset - ZIP64_END_OF_CENTRAL_DIR_LENGTH;
4959
+ if (!await startsWithSignature(reader, expectedDirectoryDataOffset, ZIP64_END_OF_CENTRAL_DIR_SIGNATURE)) {
4960
+ expectedDirectoryDataOffset = await findZip64EndOfDirectoryOffset(reader, locatorOffset);
4961
+ }
4962
+ if (expectedDirectoryDataOffset !== UNDEFINED_VALUE && expectedDirectoryDataOffset >= 0 &&
4963
+ directoryDataOffset != expectedDirectoryDataOffset) {
4964
+ const originalDirectoryDataOffset = directoryDataOffset;
4965
+ directoryDataOffset = expectedDirectoryDataOffset;
4966
+ if (directoryDataOffset > originalDirectoryDataOffset) {
4967
+ prependedDataLength = directoryDataOffset - originalDirectoryDataOffset;
4968
+ }
4969
+ endOfDirectoryArray = await readUint8Array(reader, directoryDataOffset, ZIP64_END_OF_CENTRAL_DIR_LENGTH);
4970
+ endOfDirectoryView = getDataView(endOfDirectoryArray);
4961
4971
  }
4962
- endOfDirectoryArray = await readUint8Array(reader, directoryDataOffset, ZIP64_END_OF_CENTRAL_DIR_LENGTH);
4963
- endOfDirectoryView = getDataView(endOfDirectoryArray);
4964
4972
  }
4965
4973
  if (endOfDirectoryArray.length < ZIP64_END_OF_CENTRAL_DIR_LENGTH || getUint32$1(endOfDirectoryView, 0) != ZIP64_END_OF_CENTRAL_DIR_SIGNATURE) {
4966
4974
  throw new Error(ERR_EOCDR_LOCATOR_ZIP64_NOT_FOUND);
@@ -5005,10 +5013,6 @@ class ZipReader {
5005
5013
  let declaredDirectoryDataLength = directoryDataLength;
5006
5014
  const centralDirectoryEndOffset = endOfDirectoryInfo.offset -
5007
5015
  (zip64EndOfDirectory ? zip64EndOfDirectoryLength + ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH : 0);
5008
- if (directoryDataOffset >= reader.size) {
5009
- prependedDataLength = reader.size - directoryDataOffset - directoryDataLength - END_OF_CENTRAL_DIR_LENGTH;
5010
- directoryDataOffset = reader.size - directoryDataLength - END_OF_CENTRAL_DIR_LENGTH;
5011
- }
5012
5016
  if (expectedLastDiskNumber != lastDiskNumber) {
5013
5017
  throw new Error(ERR_SPLIT_ZIP_FILE);
5014
5018
  }
@@ -5016,52 +5020,64 @@ class ZipReader {
5016
5020
  throw new Error(ERR_BAD_FORMAT);
5017
5021
  }
5018
5022
  let offset = 0;
5019
- let directoryArray = await readUint8Array(reader, directoryDataOffset, directoryDataLength);
5023
+ let directoryArray = directoryDataOffset < reader.size ?
5024
+ await readUint8Array(reader, directoryDataOffset, directoryDataLength) :
5025
+ EMPTY_UINT8_ARRAY;
5020
5026
  let directoryView = getDataView(directoryArray);
5021
5027
  if (directoryDataLength) {
5022
- if (directoryArray.length < 4) {
5023
- throw new Error(ERR_BAD_FORMAT);
5024
- }
5025
5028
  let expectedDirectoryDataOffset = centralDirectoryEndOffset - directoryDataLength;
5026
5029
  if (directoryDataOffset != expectedDirectoryDataOffset && diskNumber == lastDiskNumber) {
5027
- const storedPointsAtDirectory = getUint32$1(directoryView, offset) == CENTRAL_FILE_HEADER_SIGNATURE ||
5030
+ const storedPointsAtDirectory = directoryArray.length >= 4 && (
5031
+ getUint32$1(directoryView, offset) == CENTRAL_FILE_HEADER_SIGNATURE ||
5028
5032
  Boolean(directoryEncryptionInfo && directoryEncryptionInfo.compressedSize) ||
5029
- detectEncryptedCentralDirectory(directoryView);
5033
+ detectEncryptedCentralDirectory(directoryView));
5034
+ if (!storedPointsAtDirectory && expectedDirectoryDataOffset < 0) {
5035
+ throw new Error(ERR_BAD_FORMAT);
5036
+ }
5030
5037
  let reconcile = !storedPointsAtDirectory;
5031
5038
  if (expectedDirectoryDataOffset >= 0 && expectedDirectoryDataOffset + 4 <= reader.size) {
5032
- const expectedPointsAtDirectory = await pointsAtDirectory(reader, expectedDirectoryDataOffset);
5033
- if (storedPointsAtDirectory) {
5034
- reconcile = expectedPointsAtDirectory;
5035
- } else if (!expectedPointsAtDirectory) {
5039
+ let expectedPointsAtDirectory = await pointsAtDirectory(reader, expectedDirectoryDataOffset);
5040
+ if (!expectedPointsAtDirectory) {
5036
5041
  const signatureRecordOffset = await findDigitalSignatureRecordOffset(reader, centralDirectoryEndOffset);
5037
5042
  const signedDirectoryDataOffset = signatureRecordOffset - directoryDataLength;
5038
5043
  if (signatureRecordOffset !== UNDEFINED_VALUE && signedDirectoryDataOffset >= 0 &&
5039
5044
  await pointsAtDirectory(reader, signedDirectoryDataOffset)) {
5040
5045
  expectedDirectoryDataOffset = signedDirectoryDataOffset;
5046
+ expectedPointsAtDirectory = true;
5041
5047
  }
5042
5048
  }
5049
+ if (storedPointsAtDirectory) {
5050
+ reconcile = expectedPointsAtDirectory;
5051
+ }
5043
5052
  }
5044
- if (reconcile) {
5053
+ if (reconcile && expectedDirectoryDataOffset != directoryDataOffset) {
5045
5054
  const originalDirectoryDataOffset = directoryDataOffset;
5046
5055
  directoryDataOffset = expectedDirectoryDataOffset;
5047
5056
  directoryArray = await readUint8Array(reader, directoryDataOffset, directoryDataLength);
5048
5057
  directoryView = getDataView(directoryArray);
5049
- if (directoryDataOffset > originalDirectoryDataOffset) {
5050
- prependedDataLength += directoryDataOffset - originalDirectoryDataOffset;
5058
+ const offsetDelta = directoryDataOffset - originalDirectoryDataOffset;
5059
+ const localHeaderOffset = getFirstLocalHeaderOffset(directoryArray, directoryView);
5060
+ const localHeaderFound = localHeaderOffset !== UNDEFINED_VALUE &&
5061
+ await startsWithSignature(reader, localHeaderOffset, LOCAL_FILE_HEADER_SIGNATURE);
5062
+ const shiftedLocalHeaderFound = localHeaderOffset !== UNDEFINED_VALUE &&
5063
+ await startsWithSignature(reader, localHeaderOffset + offsetDelta, LOCAL_FILE_HEADER_SIGNATURE);
5064
+ if (offsetDelta > 0 && !(localHeaderFound && !shiftedLocalHeaderFound)) {
5065
+ prependedDataLength += offsetDelta;
5051
5066
  prependedCentralDirectory = storedPointsAtDirectory;
5052
5067
  } else {
5053
5068
  reportAmbiguity(checkAmbiguity, warnings, WARNING_MISMATCHED_CENTRAL_DIRECTORY_OFFSET);
5054
- const offsetDelta = directoryDataOffset - originalDirectoryDataOffset;
5055
- if (directoryArray.length >= CENTRAL_FILE_HEADER_LENGTH) {
5056
- const localHeaderOffset = getUint32$1(directoryView, 42);
5057
- if (!await startsWithSignature(reader, localHeaderOffset, LOCAL_FILE_HEADER_SIGNATURE) &&
5058
- await startsWithSignature(reader, localHeaderOffset + offsetDelta, LOCAL_FILE_HEADER_SIGNATURE)) {
5059
- prependedDataLength += offsetDelta;
5060
- }
5069
+ if (offsetDelta < 0 && !localHeaderFound && shiftedLocalHeaderFound) {
5070
+ prependedDataLength += offsetDelta;
5061
5071
  }
5062
5072
  }
5063
5073
  }
5064
5074
  }
5075
+ if (directoryArray.length < 4) {
5076
+ throw new Error(ERR_BAD_FORMAT);
5077
+ }
5078
+ } else if (!filesLength && directoryDataOffset < centralDirectoryEndOffset && diskNumber == lastDiskNumber) {
5079
+ prependedDataLength += centralDirectoryEndOffset - directoryDataOffset;
5080
+ directoryDataOffset = centralDirectoryEndOffset;
5065
5081
  }
5066
5082
  const expectedDirectoryDataLength = centralDirectoryEndOffset - directoryDataOffset;
5067
5083
  if (directoryDataLength != expectedDirectoryDataLength && expectedDirectoryDataLength >= 0 && diskNumber == lastDiskNumber) {
@@ -5103,8 +5119,10 @@ class ZipReader {
5103
5119
  addWarning(warnings, WARNING_WRAPPED_ENTRIES_COUNT);
5104
5120
  }
5105
5121
  }
5122
+ const entryOptions = Object.assign({}, zipReader.options, options, { [OPTION_STRICTNESS]: strictness });
5123
+ delete entryOptions[OPTION_CHECK_AMBIGUITY];
5106
5124
  for (let indexFile = 0; indexFile < filesLength; indexFile++) {
5107
- const fileEntry = new ZipEntry$1(reader, zipReader.options);
5125
+ const fileEntry = new ZipEntry$1(reader, entryOptions);
5108
5126
  if (offset + CENTRAL_FILE_HEADER_LENGTH > directoryArray.length || getUint32$1(directoryView, offset) != CENTRAL_FILE_HEADER_SIGNATURE) {
5109
5127
  if (indexFile == 0 && !decryptedDirectory && (zip64EndOfDirectoryVersion2 || detectEncryptedCentralDirectory(directoryView))) {
5110
5128
  throw new Error(ERR_ENCRYPTED_CENTRAL_DIRECTORY);
@@ -5195,13 +5213,17 @@ class ZipReader {
5195
5213
  if (malformedExtraField) {
5196
5214
  addWarning(warnings, WARNING_MALFORMED_EXTRA_FIELD, filename);
5197
5215
  }
5198
- fileEntry.offset += prependedDataLength;
5199
- const entryPosition = getDiskOffset$1(reader, fileEntry.diskNumberStart) + fileEntry.offset;
5200
- startOffset = Math.min(entryPosition, startOffset);
5201
- if (entryPosition < previousEntryPosition) {
5202
- addWarning(warnings, WARNING_UNSORTED_CENTRAL_DIRECTORY, filename);
5216
+ if (fileEntry.zip64ExtraFieldMissing && fileEntry.offset == MAX_32_BITS) {
5217
+ startOffset = 0;
5218
+ } else {
5219
+ fileEntry.offset += prependedDataLength;
5220
+ const entryPosition = getDiskOffset$1(reader, fileEntry.diskNumberStart) + fileEntry.offset;
5221
+ startOffset = Math.min(entryPosition, startOffset);
5222
+ if (entryPosition < previousEntryPosition) {
5223
+ addWarning(warnings, WARNING_UNSORTED_CENTRAL_DIRECTORY, filename);
5224
+ }
5225
+ previousEntryPosition = entryPosition;
5203
5226
  }
5204
- previousEntryPosition = entryPosition;
5205
5227
  if ((fileEntry.version & MAX_8_BITS) > MAX_KNOWN_VERSION) {
5206
5228
  addWarning(warnings, WARNING_UNKNOWN_VERSION, filename);
5207
5229
  }
@@ -5238,12 +5260,15 @@ class ZipReader {
5238
5260
  zipCrypto: fileEntry.encrypted && !fileEntry.extraFieldAES
5239
5261
  });
5240
5262
  const entry = new Entry(fileEntry);
5241
- entry.getData = (writer, options) => fileEntry.getData(writer, entry, zipReader.readRanges, options);
5263
+ if (fileEntry.zip64ExtraFieldMissing) {
5264
+ zipReader.entriesMissingZip64ExtraField.add(entry);
5265
+ }
5266
+ entry.getData = (writer, options) => fileEntry.getData(writer, entry, zipReader, options);
5242
5267
  entry.arrayBuffer = async options => {
5243
5268
  const writer = new TransformStream();
5244
5269
  const arrayBufferPromise = streamToBlob(writer.readable).then(blob => blob.arrayBuffer());
5245
5270
  arrayBufferPromise.catch(() => { });
5246
- await fileEntry.getData(writer, entry, zipReader.readRanges,
5271
+ await fileEntry.getData(writer, entry, zipReader,
5247
5272
  Object.assign({}, options, { preventClose: false }));
5248
5273
  return arrayBufferPromise;
5249
5274
  };
@@ -5451,8 +5476,9 @@ let ZipEntry$1 = class ZipEntry {
5451
5476
  });
5452
5477
  }
5453
5478
 
5454
- async getData(writer, fileEntry, readRanges, options = {}) {
5479
+ async getData(writer, fileEntry, zipReader, options = {}) {
5455
5480
  const zipEntry = this;
5481
+ const { readRanges, directoryOffset } = zipReader;
5456
5482
  if (zipEntry.zip64ExtraFieldMissing) {
5457
5483
  throw new Error(ERR_EXTRAFIELD_ZIP64_NOT_FOUND);
5458
5484
  }
@@ -5526,10 +5552,10 @@ let ZipEntry$1 = class ZipEntry {
5526
5552
  }
5527
5553
  validateLocalDirectory(zipEntry, localDirectory, rawLocalFilename, checkLocalFilename, checkLocalDirectory ? UNDEFINED_VALUE : warnings);
5528
5554
  const { lastAccessDate, creationDate, uid, gid } = localDirectory;
5529
- if (lastAccessDate) {
5555
+ if (lastAccessDate && fileEntry.lastAccessDate === UNDEFINED_VALUE) {
5530
5556
  fileEntry.lastAccessDate = lastAccessDate;
5531
5557
  }
5532
- if (creationDate) {
5558
+ if (creationDate && fileEntry.creationDate === UNDEFINED_VALUE) {
5533
5559
  fileEntry.creationDate = creationDate;
5534
5560
  }
5535
5561
  if (uid !== UNDEFINED_VALUE && fileEntry.uid === UNDEFINED_VALUE) {
@@ -5558,7 +5584,7 @@ let ZipEntry$1 = class ZipEntry {
5558
5584
  throw new Error(ERR_ENCRYPTED);
5559
5585
  }
5560
5586
  }
5561
- if (dataOffset + compressedSize > reader.size) {
5587
+ if (dataOffset + compressedSize > Math.min(reader.size, directoryOffset)) {
5562
5588
  throw new Error(ERR_ENTRY_DATA_OUT_OF_BOUNDS);
5563
5589
  }
5564
5590
  const size = compressedSize;
@@ -5624,6 +5650,7 @@ let ZipEntry$1 = class ZipEntry {
5624
5650
  extraFieldZip64: extraFieldZip64 || localDirectory.extraFieldZip64,
5625
5651
  readRanges
5626
5652
  });
5653
+ validateDataDescriptor(zipEntry, localDirectory, checkLocalDirectory ? UNDEFINED_VALUE : warnings);
5627
5654
  }
5628
5655
  let writable, abortError, aborted;
5629
5656
  try {
@@ -5643,10 +5670,7 @@ let ZipEntry$1 = class ZipEntry {
5643
5670
  writer.size += writtenSize;
5644
5671
  }
5645
5672
  } catch (error) {
5646
- const { outputSize: failedOutputSize } = workerOptions;
5647
- if (failedOutputSize !== UNDEFINED_VALUE) {
5648
- writer.size += failedOutputSize;
5649
- } else if (isErrorObject(error) && error.outputSize !== UNDEFINED_VALUE) {
5673
+ if (isErrorObject(error) && error.outputSize !== UNDEFINED_VALUE) {
5650
5674
  writer.size += error.outputSize;
5651
5675
  }
5652
5676
  if (!checkPasswordOnly || !isErrorObject(error) || error.message != ERR_ABORT_CHECK_PASSWORD) {
@@ -5674,13 +5698,7 @@ let ZipEntry$1 = class ZipEntry {
5674
5698
  };
5675
5699
 
5676
5700
  function detectEncryptedCentralDirectory(directoryView) {
5677
- const maxOffset = Math.min(directoryView.byteLength, 1024) - 3;
5678
- for (let offset = 0; offset < maxOffset; offset++) {
5679
- if (getUint32$1(directoryView, offset) == ARCHIVE_EXTRA_DATA_SIGNATURE) {
5680
- return true;
5681
- }
5682
- }
5683
- return false;
5701
+ return directoryView.byteLength >= 4 && getUint32$1(directoryView, 0) == ARCHIVE_EXTRA_DATA_SIGNATURE;
5684
5702
  }
5685
5703
 
5686
5704
  function getWrappedFilesLength(directoryView, directoryArray, offset) {
@@ -5717,6 +5735,46 @@ async function findDigitalSignatureRecordOffset(reader, endOffset) {
5717
5735
  }
5718
5736
  }
5719
5737
 
5738
+ async function findZip64EndOfDirectoryOffset(reader, endOffset) {
5739
+ const startOffset = Math.max(0, endOffset - (ZIP64_END_OF_CENTRAL_DIR_LENGTH + MAX_16_BITS));
5740
+ const tailArray = await readUint8Array(reader, startOffset, endOffset - startOffset);
5741
+ const tailView = getDataView(tailArray);
5742
+ for (let indexByte = tailArray.length - ZIP64_END_OF_CENTRAL_DIR_LENGTH; indexByte >= 0; indexByte--) {
5743
+ if (getUint32$1(tailView, indexByte) == ZIP64_END_OF_CENTRAL_DIR_SIGNATURE &&
5744
+ indexByte + 12 + Number(tailView.getBigUint64(indexByte + 4, true)) == tailArray.length) {
5745
+ return startOffset + indexByte;
5746
+ }
5747
+ }
5748
+ }
5749
+
5750
+ function getFirstLocalHeaderOffset(directoryArray, directoryView) {
5751
+ if (directoryArray.length < CENTRAL_FILE_HEADER_LENGTH) {
5752
+ return UNDEFINED_VALUE;
5753
+ }
5754
+ const localHeaderOffset = getUint32$1(directoryView, 42);
5755
+ if (localHeaderOffset != MAX_32_BITS) {
5756
+ return localHeaderOffset;
5757
+ }
5758
+ let offsetExtraField = CENTRAL_FILE_HEADER_LENGTH + getUint16$1(directoryView, 28);
5759
+ const endExtraField = Math.min(offsetExtraField + getUint16$1(directoryView, 30), directoryArray.length);
5760
+ while (offsetExtraField + 4 <= endExtraField) {
5761
+ const type = getUint16$1(directoryView, offsetExtraField);
5762
+ const size = getUint16$1(directoryView, offsetExtraField + 2);
5763
+ if (type == EXTRAFIELD_TYPE_ZIP64) {
5764
+ let offsetValue = offsetExtraField + 4;
5765
+ if (getUint32$1(directoryView, 24) == MAX_32_BITS) {
5766
+ offsetValue += 8;
5767
+ }
5768
+ if (getUint32$1(directoryView, 20) == MAX_32_BITS) {
5769
+ offsetValue += 8;
5770
+ }
5771
+ return offsetValue + 8 <= endExtraField ? getBigUint64(directoryView, offsetValue) : UNDEFINED_VALUE;
5772
+ }
5773
+ offsetExtraField += 4 + size;
5774
+ }
5775
+ return UNDEFINED_VALUE;
5776
+ }
5777
+
5720
5778
  function readDigitalSignature(signatureRecordArray) {
5721
5779
  if (signatureRecordArray.length >= 6) {
5722
5780
  const signatureRecordView = getDataView(signatureRecordArray);
@@ -5806,6 +5864,7 @@ function readCommonFooter(fileEntry, directory, dataView, offset, localDirectory
5806
5864
  uncompressedSize: getUint32$1(dataView, offset + HEADER_OFFSET_UNCOMPRESSED_SIZE)
5807
5865
  });
5808
5866
  const extraFieldZip64 = extraField.get(EXTRAFIELD_TYPE_ZIP64);
5867
+ let extraFieldZip64Missing;
5809
5868
  if (extraFieldZip64) {
5810
5869
  if (!readExtraFieldZip64(extraFieldZip64, directory, localDirectory)) {
5811
5870
  malformedExtraField = true;
@@ -5815,7 +5874,7 @@ function readCommonFooter(fileEntry, directory, dataView, offset, localDirectory
5815
5874
  if (localDirectory) {
5816
5875
  malformedExtraField = true;
5817
5876
  } else {
5818
- throw new Error(ERR_EXTRAFIELD_ZIP64_NOT_FOUND);
5877
+ extraFieldZip64Missing = true;
5819
5878
  }
5820
5879
  }
5821
5880
  const extraFieldUnicodePath = extraField.get(EXTRAFIELD_TYPE_UNICODE_PATH);
@@ -5873,6 +5932,9 @@ function readCommonFooter(fileEntry, directory, dataView, offset, localDirectory
5873
5932
  if (extraFieldUSDZ) {
5874
5933
  directory.extraFieldUSDZ = extraFieldUSDZ;
5875
5934
  }
5935
+ if (extraFieldZip64Missing) {
5936
+ throw new Error(ERR_EXTRAFIELD_ZIP64_NOT_FOUND);
5937
+ }
5876
5938
  return malformedExtraField;
5877
5939
  }
5878
5940
 
@@ -6087,13 +6149,7 @@ async function detectOverlappingEntry({
6087
6149
  let dataDescriptorLength = 0;
6088
6150
  if (dataDescriptor) {
6089
6151
  const zip64 = Boolean(extraFieldZip64);
6090
- const dataDescriptorArray = await readUint8Array(reader, dataOffset + compressedSize, DATA_DESCRIPTOR_RECORD_ZIP_64_LENGTH + DATA_DESCRIPTOR_RECORD_SIGNATURE_LENGTH);
6091
- const dataDescriptorView = getDataView(dataDescriptorArray);
6092
- const candidates = [[zip64, true], [zip64, false], [!zip64, true], [!zip64, false]]
6093
- .map(([zip64Layout, signature]) => readDataDescriptor(dataDescriptorView, zip64Layout, signature))
6094
- .filter(candidate => candidate && candidate.compressedSize == compressedSize && candidate.uncompressedSize == uncompressedSize);
6095
- const localDataDescriptor = candidates.find(candidate => candidate.crc32 == crc32) || candidates[0] ||
6096
- readDataDescriptor(dataDescriptorView, zip64, true) || readDataDescriptor(dataDescriptorView, zip64, false);
6152
+ const localDataDescriptor = await readLocalDataDescriptor(reader, dataOffset + compressedSize, { crc32, compressedSize, uncompressedSize, zip64 });
6097
6153
  if (localDataDescriptor) {
6098
6154
  fileEntry.localDirectory.dataDescriptor = localDataDescriptor;
6099
6155
  dataDescriptorLength = getDataDescriptorLength(localDataDescriptor.zip64, localDataDescriptor.signature);
@@ -6163,6 +6219,25 @@ function mergeRanges(sortedRanges, pendingRanges) {
6163
6219
  return mergedRanges;
6164
6220
  }
6165
6221
 
6222
+ async function readLocalDataDescriptor(reader, offset, { crc32, compressedSize, uncompressedSize, zip64 }) {
6223
+ const maxLength = DATA_DESCRIPTOR_RECORD_ZIP_64_LENGTH + DATA_DESCRIPTOR_RECORD_SIGNATURE_LENGTH;
6224
+ const length = Math.min(maxLength, Math.max(0, reader.size - offset));
6225
+ const dataDescriptorArray = length ? await readUint8Array(reader, offset, length) : EMPTY_UINT8_ARRAY;
6226
+ const dataDescriptorView = getDataView(dataDescriptorArray);
6227
+ const candidates = [[zip64, true], [zip64, false], [!zip64, true], [!zip64, false]]
6228
+ .map(([zip64Layout, signature]) => readDataDescriptor(dataDescriptorView, zip64Layout, signature))
6229
+ .filter(candidate => candidate && candidate.compressedSize == compressedSize && candidate.uncompressedSize == uncompressedSize);
6230
+ return candidates.find(candidate => candidate.crc32 == crc32) || candidates[0] ||
6231
+ readDataDescriptor(dataDescriptorView, zip64, true) || readDataDescriptor(dataDescriptorView, zip64, false);
6232
+ }
6233
+
6234
+ async function getEntryDataDescriptorLength(reader, offset, { crc32, compressedSize, uncompressedSize, extraFieldZip64 }) {
6235
+ const dataDescriptor = await readLocalDataDescriptor(reader, offset, { crc32, compressedSize, uncompressedSize, zip64: Boolean(extraFieldZip64) });
6236
+ if (dataDescriptor && dataDescriptor.compressedSize == compressedSize && dataDescriptor.uncompressedSize == uncompressedSize) {
6237
+ return getDataDescriptorLength(dataDescriptor.zip64, dataDescriptor.signature);
6238
+ }
6239
+ }
6240
+
6166
6241
  function readDataDescriptor(dataDescriptorView, zip64, signature) {
6167
6242
  const offset = signature ? DATA_DESCRIPTOR_RECORD_SIGNATURE_LENGTH : 0;
6168
6243
  if (dataDescriptorView.byteLength < getDataDescriptorLength(zip64, signature) ||
@@ -6422,6 +6497,18 @@ function validateLocalDirectory(zipEntry, localDirectory, rawLocalFilename, chec
6422
6497
  }
6423
6498
  }
6424
6499
 
6500
+ function validateDataDescriptor(zipEntry, localDirectory, warnings) {
6501
+ const { dataDescriptor } = localDirectory;
6502
+ const maskedLocalDirectory = zipEntry.decryptedDirectory &&
6503
+ (localDirectory.rawBitFlag & BITFLAG_MASKED_LOCAL_HEADERS) == BITFLAG_MASKED_LOCAL_HEADERS;
6504
+ if (dataDescriptor && !maskedLocalDirectory &&
6505
+ ((zipEntry.crc32 !== UNDEFINED_VALUE && dataDescriptor.crc32 != zipEntry.crc32) ||
6506
+ dataDescriptor.compressedSize != zipEntry.compressedSize ||
6507
+ dataDescriptor.uncompressedSize != zipEntry.uncompressedSize)) {
6508
+ reportAmbiguity(!warnings, warnings, WARNING_MISMATCHED_LOCAL_FILE_HEADER_CRC32_OR_SIZES);
6509
+ }
6510
+ }
6511
+
6425
6512
  function reportAmbiguity(reject, warnings, reason) {
6426
6513
  if (reject) {
6427
6514
  throwAmbiguousArchive(reason);
@@ -6524,6 +6611,7 @@ var zipReader = /*#__PURE__*/Object.freeze({
6524
6611
  WARNING_WRAPPED_ENTRIES_COUNT: WARNING_WRAPPED_ENTRIES_COUNT,
6525
6612
  ZipReader: ZipReader,
6526
6613
  ZipReaderStream: ZipReaderStream,
6614
+ getEntryDataDescriptorLength: getEntryDataDescriptorLength,
6527
6615
  isZipFile: isZipFile
6528
6616
  });
6529
6617
 
@@ -6647,136 +6735,7 @@ class ZipWriter {
6647
6735
  }
6648
6736
 
6649
6737
  appendZip(reader, options = {}) {
6650
- return watchPromiseError(this, this.appendZipEntries(reader, options));
6651
- }
6652
-
6653
- async appendZipEntries(reader, options = {}) {
6654
- const zipWriter = this;
6655
- const { pendingAddFileCalls, filenames, fileEntries } = zipWriter;
6656
- const filter = checkFunctionOption(options.filter);
6657
- while (pendingAddFileCalls.size) {
6658
- await Promise.allSettled(Array.from(pendingAddFileCalls));
6659
- }
6660
- let resolveAppendZip;
6661
- const promiseAppendZip = new Promise(resolve => resolveAppendZip = resolve);
6662
- pendingAddFileCalls.add(promiseAppendZip);
6663
- const appendedFilenames = [];
6664
- let releaseLockWriter;
6665
- try {
6666
- reader = new GenericReader(reader);
6667
- await initStream(reader);
6668
- if (reader.size === UNDEFINED_VALUE || !reader.readUint8Array) {
6669
- reader = new BlobReader(await streamToBlob(reader.readable));
6670
- await initStream(reader);
6671
- }
6672
- const { ZipReader } = await Promise.resolve().then(function () { return zipReader; });
6673
- const zipReader$1 = new ZipReader(reader);
6674
- const entries = await zipReader$1.getEntries();
6675
- const keptEntries = [];
6676
- for (const entry of entries) {
6677
- if (!filter || await filter(entry)) {
6678
- keptEntries.push(entry);
6679
- }
6680
- }
6681
- await zipReader$1.close();
6682
- await initStream(zipWriter.writer);
6683
- const { directoryOffset } = zipReader$1;
6684
- keptEntries.forEach(({ filename }) => {
6685
- if (filenames.has(filename)) {
6686
- throw new Error(ERR_DUPLICATED_NAME);
6687
- }
6688
- filenames.add(filename);
6689
- appendedFilenames.push(filename);
6690
- });
6691
- zipWriter.writerLocked = true;
6692
- const { lockWriter } = zipWriter;
6693
- zipWriter.lockWriter = new Promise(resolve => releaseLockWriter = () => {
6694
- zipWriter.writerLocked = false;
6695
- resolve();
6696
- });
6697
- await lockWriter;
6698
- if (zipWriter.addSplitZipSignature) {
6699
- delete zipWriter.addSplitZipSignature;
6700
- if (!await startsWithSplitZipSignature(reader)) {
6701
- await writeData(zipWriter.writer, getSplitZipSignatureArray());
6702
- zipWriter.offset += SPLIT_ZIP_FILE_SIGNATURE_LENGTH;
6703
- }
6704
- }
6705
- const entryPositions = await copyZipData(zipWriter, reader, entries, keptEntries, directoryOffset, Boolean(filter));
6706
- keptEntries.forEach(entry => {
6707
- const {
6708
- version,
6709
- rawLastModDate,
6710
- rawFilename,
6711
- bitFlag,
6712
- encrypted,
6713
- uncompressedSize,
6714
- compressedSize,
6715
- extraFieldZip64
6716
- } = entry;
6717
- let {
6718
- compressionMethod,
6719
- rawExtraField,
6720
- } = entry;
6721
- const { level, languageEncodingFlag, dataDescriptor } = bitFlag;
6722
- rawExtraField = removeExtraFieldZip64(rawExtraField || EMPTY_UINT8_ARRAY);
6723
- if (entry.extraFieldAES) {
6724
- compressionMethod = COMPRESSION_METHOD_AES;
6725
- }
6726
- const extraFieldLength = getLength(rawExtraField);
6727
- const zip64UncompressedSize = Boolean(extraFieldZip64) && extraFieldZip64.uncompressedSize !== UNDEFINED_VALUE;
6728
- const zip64CompressedSize = Boolean(extraFieldZip64) && extraFieldZip64.compressedSize !== UNDEFINED_VALUE;
6729
- const bitFlagValue = (getBitFlag(level, languageEncodingFlag, dataDescriptor, encrypted, compressionMethod) & ~BITFLAG_LEVEL) | (level << 1);
6730
- const {
6731
- headerArray,
6732
- headerView
6733
- } = getHeaderArrayData({
6734
- version,
6735
- bitFlag: bitFlagValue,
6736
- compressionMethod,
6737
- uncompressedSize,
6738
- compressedSize,
6739
- rawLastModDate,
6740
- rawFilename,
6741
- zip64CompressedSize,
6742
- zip64UncompressedSize,
6743
- extraFieldLength
6744
- });
6745
- const { crc32 } = entry;
6746
- if (crc32 !== UNDEFINED_VALUE) {
6747
- setUint32(headerView, HEADER_OFFSET_SIGNATURE, crc32);
6748
- }
6749
- const { offset, diskNumberStart } = entryPositions.get(entry);
6750
- Object.assign(entry, {
6751
- zip64Enabled: true,
6752
- zip64UncompressedSize,
6753
- zip64CompressedSize,
6754
- offset,
6755
- diskNumberStart,
6756
- zip64DiskNumberStart: false,
6757
- rawExtraFieldZip64: EMPTY_UINT8_ARRAY,
6758
- rawExtraFieldAES: EMPTY_UINT8_ARRAY,
6759
- rawExtraFieldExtendedTimestamp: EMPTY_UINT8_ARRAY,
6760
- rawExtraFieldNTFS: EMPTY_UINT8_ARRAY,
6761
- rawExtraFieldUnix: EMPTY_UINT8_ARRAY,
6762
- rawCentralExtraFieldUnix: EMPTY_UINT8_ARRAY,
6763
- rawExtraField,
6764
- rawCentralExtraField: EMPTY_UINT8_ARRAY,
6765
- headerArray,
6766
- headerView
6767
- });
6768
- fileEntries.set(entry.filename, entry);
6769
- });
6770
- } catch (error) {
6771
- appendedFilenames.forEach(filename => filenames.delete(filename));
6772
- throw error;
6773
- } finally {
6774
- resolveAppendZip();
6775
- pendingAddFileCalls.delete(promiseAppendZip);
6776
- if (releaseLockWriter) {
6777
- releaseLockWriter();
6778
- }
6779
- }
6738
+ return watchPromiseError(this, appendZipEntries(this, reader, options));
6780
6739
  }
6781
6740
 
6782
6741
  add(name = "", reader, options = {}) {
@@ -6938,11 +6897,140 @@ function watchPromiseError(zipWriter, promise) {
6938
6897
  return watchedPromise;
6939
6898
  }
6940
6899
 
6900
+ async function appendZipEntries(zipWriter, reader, options = {}) {
6901
+ const { pendingAddFileCalls, filenames, fileEntries } = zipWriter;
6902
+ const filter = checkFunctionOption(options.filter);
6903
+ while (pendingAddFileCalls.size) {
6904
+ await Promise.allSettled(Array.from(pendingAddFileCalls));
6905
+ }
6906
+ let resolveAppendZip;
6907
+ const promiseAppendZip = new Promise(resolve => resolveAppendZip = resolve);
6908
+ pendingAddFileCalls.add(promiseAppendZip);
6909
+ const appendedFilenames = [];
6910
+ let releaseLockWriter;
6911
+ try {
6912
+ reader = new GenericReader(reader);
6913
+ await initStream(reader);
6914
+ if (reader.size === UNDEFINED_VALUE || !reader.readUint8Array) {
6915
+ reader = new BlobReader(await streamToBlob(reader.readable));
6916
+ await initStream(reader);
6917
+ }
6918
+ const { ZipReader, getEntryDataDescriptorLength } = await Promise.resolve().then(function () { return zipReader; });
6919
+ const zipReader$1 = new ZipReader(reader);
6920
+ const entries = await zipReader$1.getEntries();
6921
+ const keptEntries = [];
6922
+ for (const entry of entries) {
6923
+ if (!filter || await filter(entry)) {
6924
+ keptEntries.push(entry);
6925
+ }
6926
+ }
6927
+ await zipReader$1.close();
6928
+ await initStream(zipWriter.writer);
6929
+ const { directoryOffset, entriesMissingZip64ExtraField } = zipReader$1;
6930
+ keptEntries.forEach(entry => {
6931
+ const { filename } = entry;
6932
+ if (entriesMissingZip64ExtraField.has(entry)) {
6933
+ throw new Error(ERR_EXTRAFIELD_ZIP64_NOT_FOUND);
6934
+ }
6935
+ if (filenames.has(filename)) {
6936
+ throw new Error(ERR_DUPLICATED_NAME);
6937
+ }
6938
+ filenames.add(filename);
6939
+ appendedFilenames.push(filename);
6940
+ });
6941
+ zipWriter.writerLocked = true;
6942
+ const { lockWriter } = zipWriter;
6943
+ zipWriter.lockWriter = new Promise(resolve => releaseLockWriter = () => {
6944
+ zipWriter.writerLocked = false;
6945
+ resolve();
6946
+ });
6947
+ await lockWriter;
6948
+ if (zipWriter.addSplitZipSignature) {
6949
+ delete zipWriter.addSplitZipSignature;
6950
+ if (filter || !await startsWithSplitZipSignature(reader)) {
6951
+ await writeData(zipWriter.writer, getSplitZipSignatureArray());
6952
+ zipWriter.offset += SPLIT_ZIP_FILE_SIGNATURE_LENGTH;
6953
+ }
6954
+ }
6955
+ const entryPositions = await copyZipData(zipWriter, reader, entries, keptEntries, directoryOffset, Boolean(filter), getEntryDataDescriptorLength);
6956
+ keptEntries.forEach(entry => {
6957
+ const {
6958
+ version,
6959
+ rawLastModDate,
6960
+ rawFilename,
6961
+ rawBitFlag,
6962
+ uncompressedSize,
6963
+ compressedSize,
6964
+ extraFieldZip64
6965
+ } = entry;
6966
+ let {
6967
+ compressionMethod,
6968
+ rawExtraField,
6969
+ } = entry;
6970
+ rawExtraField = removeExtraFieldZip64(rawExtraField || EMPTY_UINT8_ARRAY);
6971
+ if (entry.extraFieldAES) {
6972
+ compressionMethod = COMPRESSION_METHOD_AES;
6973
+ }
6974
+ const extraFieldLength = getLength(rawExtraField);
6975
+ const zip64UncompressedSize = Boolean(extraFieldZip64) && extraFieldZip64.uncompressedSize !== UNDEFINED_VALUE;
6976
+ const zip64CompressedSize = Boolean(extraFieldZip64) && extraFieldZip64.compressedSize !== UNDEFINED_VALUE;
6977
+ const {
6978
+ headerArray,
6979
+ headerView
6980
+ } = getHeaderArrayData({
6981
+ version,
6982
+ bitFlag: rawBitFlag,
6983
+ compressionMethod,
6984
+ uncompressedSize,
6985
+ compressedSize,
6986
+ rawLastModDate,
6987
+ rawFilename,
6988
+ zip64CompressedSize,
6989
+ zip64UncompressedSize,
6990
+ extraFieldLength
6991
+ });
6992
+ const { crc32 } = entry;
6993
+ if (crc32 !== UNDEFINED_VALUE) {
6994
+ setUint32(headerView, HEADER_OFFSET_SIGNATURE, crc32);
6995
+ }
6996
+ const { offset, diskNumberStart } = entryPositions.get(entry);
6997
+ Object.assign(entry, {
6998
+ zip64Enabled: true,
6999
+ zip64UncompressedSize,
7000
+ zip64CompressedSize,
7001
+ offset,
7002
+ diskNumberStart,
7003
+ zip64DiskNumberStart: false,
7004
+ rawExtraFieldZip64: EMPTY_UINT8_ARRAY,
7005
+ rawExtraFieldAES: EMPTY_UINT8_ARRAY,
7006
+ rawExtraFieldExtendedTimestamp: EMPTY_UINT8_ARRAY,
7007
+ rawExtraFieldNTFS: EMPTY_UINT8_ARRAY,
7008
+ rawExtraFieldUnix: EMPTY_UINT8_ARRAY,
7009
+ rawCentralExtraFieldUnix: EMPTY_UINT8_ARRAY,
7010
+ rawExtraField,
7011
+ rawCentralExtraField: EMPTY_UINT8_ARRAY,
7012
+ headerArray,
7013
+ headerView
7014
+ });
7015
+ fileEntries.set(entry.filename, entry);
7016
+ });
7017
+ } catch (error) {
7018
+ appendedFilenames.forEach(filename => filenames.delete(filename));
7019
+ throw error;
7020
+ } finally {
7021
+ resolveAppendZip();
7022
+ pendingAddFileCalls.delete(promiseAppendZip);
7023
+ if (releaseLockWriter) {
7024
+ releaseLockWriter();
7025
+ }
7026
+ }
7027
+ }
7028
+
6941
7029
  async function prependZipEntries(zipWriter, reader) {
6942
7030
  if (zipWriter.filenames.size) {
6943
7031
  throw new Error(ERR_ZIP_NOT_EMPTY);
6944
7032
  }
6945
- await zipWriter.appendZipEntries(reader);
7033
+ await appendZipEntries(zipWriter, reader);
6946
7034
  }
6947
7035
 
6948
7036
  async function addFileEntry(zipWriter, name, reader, options) {
@@ -8714,7 +8802,7 @@ function removeExtraFieldZip64(rawExtraField) {
8714
8802
  return rawExtraField;
8715
8803
  }
8716
8804
 
8717
- async function copyZipData(zipWriter, reader, entries, keptEntries, directoryOffset, compact) {
8805
+ async function copyZipData(zipWriter, reader, entries, keptEntries, directoryOffset, compact, getEntryDataDescriptorLength) {
8718
8806
  const { writer } = zipWriter;
8719
8807
  const entryPositions = new Map();
8720
8808
  if (writer.closeDisk || compact) {
@@ -8722,6 +8810,27 @@ async function copyZipData(zipWriter, reader, entries, keptEntries, directoryOff
8722
8810
  getSourceOffset(reader, firstEntry) - getSourceOffset(reader, secondEntry));
8723
8811
  const regionEnds = getRegionEnds(reader, sortedEntries, directoryOffset);
8724
8812
  const keptEntrySet = new Set(keptEntries);
8813
+ const localHeaderLengths = new Map();
8814
+ for (let indexEntry = 0; indexEntry < sortedEntries.length; indexEntry++) {
8815
+ const entry = sortedEntries[indexEntry];
8816
+ if (keptEntrySet.has(entry)) {
8817
+ const sourceOffset = getSourceOffset(reader, entry);
8818
+ const localHeaderLength = await getLocalHeaderLength(reader, sourceOffset);
8819
+ if (localHeaderLength === UNDEFINED_VALUE) {
8820
+ throw new Error(ERR_LOCAL_FILE_HEADER_NOT_FOUND);
8821
+ }
8822
+ let entryEnd = sourceOffset + localHeaderLength + entry.compressedSize;
8823
+ if (entry.bitFlag.dataDescriptor) {
8824
+ const dataDescriptorLength = await getEntryDataDescriptorLength(reader, entryEnd, entry);
8825
+ entryEnd = dataDescriptorLength === UNDEFINED_VALUE ? Math.max(entryEnd, regionEnds[indexEntry]) : entryEnd + dataDescriptorLength;
8826
+ }
8827
+ if (entryEnd > regionEnds[indexEntry]) {
8828
+ throw new Error(ERR_OVERLAPPING_ENTRY);
8829
+ }
8830
+ regionEnds[indexEntry] = entryEnd;
8831
+ localHeaderLengths.set(entry, localHeaderLength);
8832
+ }
8833
+ }
8725
8834
  let copiedOffset = 0;
8726
8835
  let lastPosition;
8727
8836
  for (let indexEntry = 0; indexEntry < sortedEntries.length; indexEntry++) {
@@ -8734,7 +8843,7 @@ async function copyZipData(zipWriter, reader, entries, keptEntries, directoryOff
8734
8843
  if (!compact) {
8735
8844
  await copyData(zipWriter, reader, copiedOffset, sourceOffset - copiedOffset);
8736
8845
  }
8737
- if (writer.closeDisk && exceedsAvailableSize(writer, await getLocalHeaderLength(reader, sourceOffset))) {
8846
+ if (writer.closeDisk && exceedsAvailableSize(writer, localHeaderLengths.get(entry))) {
8738
8847
  await writer.closeDisk();
8739
8848
  }
8740
8849
  lastPosition = {
@@ -8768,7 +8877,7 @@ function getRegionEnds(reader, sortedEntries, directoryOffset) {
8768
8877
  const sourceOffset = getSourceOffset(reader, sortedEntries[indexEntry]);
8769
8878
  const nextEntry = sortedEntries[indexEntry + 1];
8770
8879
  if (nextEntry && getSourceOffset(reader, nextEntry) > sourceOffset) {
8771
- regionEnd = getSourceOffset(reader, nextEntry);
8880
+ regionEnd = Math.min(getSourceOffset(reader, nextEntry), directoryOffset);
8772
8881
  }
8773
8882
  regionEnds[indexEntry] = regionEnd;
8774
8883
  }
@@ -8782,11 +8891,13 @@ async function copyData(zipWriter, reader, offset, size) {
8782
8891
  try {
8783
8892
  await flushBufferedData(createReadable(reader, { offset, size }), writer, UNDEFINED_VALUE, chunkLength => copiedLength += chunkLength);
8784
8893
  } catch (error) {
8785
- zipWriter.hasCorruptedEntries = true;
8786
- try {
8787
- error.corruptedEntry = true;
8788
- } catch {
8789
- // ignored
8894
+ if (copiedLength) {
8895
+ zipWriter.hasCorruptedEntries = true;
8896
+ try {
8897
+ error.corruptedEntry = true;
8898
+ } catch {
8899
+ // ignored
8900
+ }
8790
8901
  }
8791
8902
  throw error;
8792
8903
  } finally {
@@ -8797,11 +8908,16 @@ async function copyData(zipWriter, reader, offset, size) {
8797
8908
  }
8798
8909
 
8799
8910
  async function getLocalHeaderLength(reader, offset) {
8800
- const headerArray = await readUint8Array(reader, offset, HEADER_SIZE);
8911
+ const headerArray = offset >= 0 && offset + HEADER_SIZE <= reader.size ?
8912
+ await readUint8Array(reader, offset, HEADER_SIZE) :
8913
+ EMPTY_UINT8_ARRAY;
8801
8914
  if (getLength(headerArray) < HEADER_SIZE) {
8802
- return HEADER_SIZE;
8915
+ return UNDEFINED_VALUE;
8803
8916
  }
8804
8917
  const headerView = getDataView(headerArray);
8918
+ if (getUint32(headerView, 0) != LOCAL_FILE_HEADER_SIGNATURE) {
8919
+ return UNDEFINED_VALUE;
8920
+ }
8805
8921
  return HEADER_SIZE +
8806
8922
  getUint16(headerView, HEADER_OFFSET_FILENAME_LENGTH + LOCAL_HEADER_COMMON_OFFSET) +
8807
8923
  getUint16(headerView, HEADER_OFFSET_EXTRAFIELD_LENGTH + LOCAL_HEADER_COMMON_OFFSET);
@@ -9152,7 +9268,7 @@ function formatSupported(StreamClass, format) {
9152
9268
  EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
9153
9269
  */
9154
9270
 
9155
- const VERSION = "2.20.0";
9271
+ const VERSION = "2.21.0";
9156
9272
 
9157
9273
  /*
9158
9274
  Copyright (c) 2025 Gildas Lormeau. All rights reserved.