@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";
@@ -4790,12 +4794,9 @@ const ERR_BAD_FORMAT = "File format is not recognized";
4790
4794
  const ERR_EOCDR_NOT_FOUND = "End of central directory not found";
4791
4795
  const ERR_EOCDR_LOCATOR_ZIP64_NOT_FOUND = "End of Zip64 central directory locator not found";
4792
4796
  const ERR_CENTRAL_DIRECTORY_NOT_FOUND = "Central directory header not found";
4793
- const ERR_LOCAL_FILE_HEADER_NOT_FOUND = "Local file header not found";
4794
- const ERR_EXTRAFIELD_ZIP64_NOT_FOUND = "Zip64 extra field not found";
4795
4797
  const ERR_ENCRYPTED = "File contains encrypted entry";
4796
4798
  const ERR_UNSUPPORTED_ENCRYPTION = "Encryption method not supported";
4797
4799
  const ERR_SPLIT_ZIP_FILE = "Split zip file";
4798
- const ERR_OVERLAPPING_ENTRY = "Overlapping entry found";
4799
4800
  const ERR_ENTRY_DATA_OUT_OF_BOUNDS = "Entry data out of bounds";
4800
4801
  const ERR_AMBIGUOUS_ARCHIVE = "Ambiguous archive";
4801
4802
  const ERR_ENCRYPTED_CENTRAL_DIRECTORY = "Encrypted central directory is not supported";
@@ -4860,7 +4861,8 @@ class ZipReader {
4860
4861
  Object.assign(this, {
4861
4862
  reader: new GenericReader(reader),
4862
4863
  options,
4863
- readRanges: { indexes: new Set(), sortedRanges: [], pendingRanges: [] }
4864
+ readRanges: { indexes: new Set(), sortedRanges: [], pendingRanges: [] },
4865
+ entriesMissingZip64ExtraField: new WeakSet()
4864
4866
  });
4865
4867
  }
4866
4868
 
@@ -4931,16 +4933,22 @@ class ZipReader {
4931
4933
  directoryDataOffset = getDiskOffset$1(reader, getUint32$1(endOfDirectoryLocatorView, 4)) + getBigUint64(endOfDirectoryLocatorView, 8);
4932
4934
  let endOfDirectoryArray = await readUint8Array(reader, directoryDataOffset, ZIP64_END_OF_CENTRAL_DIR_LENGTH);
4933
4935
  let endOfDirectoryView = getDataView(endOfDirectoryArray);
4934
- const expectedDirectoryDataOffset = endOfDirectoryInfo.offset - ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH - ZIP64_END_OF_CENTRAL_DIR_LENGTH;
4935
- if ((endOfDirectoryArray.length < ZIP64_END_OF_CENTRAL_DIR_LENGTH || getUint32$1(endOfDirectoryView, 0) != ZIP64_END_OF_CENTRAL_DIR_SIGNATURE) &&
4936
- directoryDataOffset != expectedDirectoryDataOffset && expectedDirectoryDataOffset >= 0) {
4937
- const originalDirectoryDataOffset = directoryDataOffset;
4938
- directoryDataOffset = expectedDirectoryDataOffset;
4939
- if (directoryDataOffset > originalDirectoryDataOffset) {
4940
- prependedDataLength = directoryDataOffset - originalDirectoryDataOffset;
4936
+ if (endOfDirectoryArray.length < ZIP64_END_OF_CENTRAL_DIR_LENGTH || getUint32$1(endOfDirectoryView, 0) != ZIP64_END_OF_CENTRAL_DIR_SIGNATURE) {
4937
+ const locatorOffset = endOfDirectoryInfo.offset - ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH;
4938
+ let expectedDirectoryDataOffset = locatorOffset - ZIP64_END_OF_CENTRAL_DIR_LENGTH;
4939
+ if (!await startsWithSignature(reader, expectedDirectoryDataOffset, ZIP64_END_OF_CENTRAL_DIR_SIGNATURE)) {
4940
+ expectedDirectoryDataOffset = await findZip64EndOfDirectoryOffset(reader, locatorOffset);
4941
+ }
4942
+ if (expectedDirectoryDataOffset !== UNDEFINED_VALUE && expectedDirectoryDataOffset >= 0 &&
4943
+ directoryDataOffset != expectedDirectoryDataOffset) {
4944
+ const originalDirectoryDataOffset = directoryDataOffset;
4945
+ directoryDataOffset = expectedDirectoryDataOffset;
4946
+ if (directoryDataOffset > originalDirectoryDataOffset) {
4947
+ prependedDataLength = directoryDataOffset - originalDirectoryDataOffset;
4948
+ }
4949
+ endOfDirectoryArray = await readUint8Array(reader, directoryDataOffset, ZIP64_END_OF_CENTRAL_DIR_LENGTH);
4950
+ endOfDirectoryView = getDataView(endOfDirectoryArray);
4941
4951
  }
4942
- endOfDirectoryArray = await readUint8Array(reader, directoryDataOffset, ZIP64_END_OF_CENTRAL_DIR_LENGTH);
4943
- endOfDirectoryView = getDataView(endOfDirectoryArray);
4944
4952
  }
4945
4953
  if (endOfDirectoryArray.length < ZIP64_END_OF_CENTRAL_DIR_LENGTH || getUint32$1(endOfDirectoryView, 0) != ZIP64_END_OF_CENTRAL_DIR_SIGNATURE) {
4946
4954
  throw new Error(ERR_EOCDR_LOCATOR_ZIP64_NOT_FOUND);
@@ -4985,10 +4993,6 @@ class ZipReader {
4985
4993
  let declaredDirectoryDataLength = directoryDataLength;
4986
4994
  const centralDirectoryEndOffset = endOfDirectoryInfo.offset -
4987
4995
  (zip64EndOfDirectory ? zip64EndOfDirectoryLength + ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH : 0);
4988
- if (directoryDataOffset >= reader.size) {
4989
- prependedDataLength = reader.size - directoryDataOffset - directoryDataLength - END_OF_CENTRAL_DIR_LENGTH;
4990
- directoryDataOffset = reader.size - directoryDataLength - END_OF_CENTRAL_DIR_LENGTH;
4991
- }
4992
4996
  if (expectedLastDiskNumber != lastDiskNumber) {
4993
4997
  throw new Error(ERR_SPLIT_ZIP_FILE);
4994
4998
  }
@@ -4996,52 +5000,64 @@ class ZipReader {
4996
5000
  throw new Error(ERR_BAD_FORMAT);
4997
5001
  }
4998
5002
  let offset = 0;
4999
- let directoryArray = await readUint8Array(reader, directoryDataOffset, directoryDataLength);
5003
+ let directoryArray = directoryDataOffset < reader.size ?
5004
+ await readUint8Array(reader, directoryDataOffset, directoryDataLength) :
5005
+ EMPTY_UINT8_ARRAY;
5000
5006
  let directoryView = getDataView(directoryArray);
5001
5007
  if (directoryDataLength) {
5002
- if (directoryArray.length < 4) {
5003
- throw new Error(ERR_BAD_FORMAT);
5004
- }
5005
5008
  let expectedDirectoryDataOffset = centralDirectoryEndOffset - directoryDataLength;
5006
5009
  if (directoryDataOffset != expectedDirectoryDataOffset && diskNumber == lastDiskNumber) {
5007
- const storedPointsAtDirectory = getUint32$1(directoryView, offset) == CENTRAL_FILE_HEADER_SIGNATURE ||
5010
+ const storedPointsAtDirectory = directoryArray.length >= 4 && (
5011
+ getUint32$1(directoryView, offset) == CENTRAL_FILE_HEADER_SIGNATURE ||
5008
5012
  Boolean(directoryEncryptionInfo && directoryEncryptionInfo.compressedSize) ||
5009
- detectEncryptedCentralDirectory(directoryView);
5013
+ detectEncryptedCentralDirectory(directoryView));
5014
+ if (!storedPointsAtDirectory && expectedDirectoryDataOffset < 0) {
5015
+ throw new Error(ERR_BAD_FORMAT);
5016
+ }
5010
5017
  let reconcile = !storedPointsAtDirectory;
5011
5018
  if (expectedDirectoryDataOffset >= 0 && expectedDirectoryDataOffset + 4 <= reader.size) {
5012
- const expectedPointsAtDirectory = await pointsAtDirectory(reader, expectedDirectoryDataOffset);
5013
- if (storedPointsAtDirectory) {
5014
- reconcile = expectedPointsAtDirectory;
5015
- } else if (!expectedPointsAtDirectory) {
5019
+ let expectedPointsAtDirectory = await pointsAtDirectory(reader, expectedDirectoryDataOffset);
5020
+ if (!expectedPointsAtDirectory) {
5016
5021
  const signatureRecordOffset = await findDigitalSignatureRecordOffset(reader, centralDirectoryEndOffset);
5017
5022
  const signedDirectoryDataOffset = signatureRecordOffset - directoryDataLength;
5018
5023
  if (signatureRecordOffset !== UNDEFINED_VALUE && signedDirectoryDataOffset >= 0 &&
5019
5024
  await pointsAtDirectory(reader, signedDirectoryDataOffset)) {
5020
5025
  expectedDirectoryDataOffset = signedDirectoryDataOffset;
5026
+ expectedPointsAtDirectory = true;
5021
5027
  }
5022
5028
  }
5029
+ if (storedPointsAtDirectory) {
5030
+ reconcile = expectedPointsAtDirectory;
5031
+ }
5023
5032
  }
5024
- if (reconcile) {
5033
+ if (reconcile && expectedDirectoryDataOffset != directoryDataOffset) {
5025
5034
  const originalDirectoryDataOffset = directoryDataOffset;
5026
5035
  directoryDataOffset = expectedDirectoryDataOffset;
5027
5036
  directoryArray = await readUint8Array(reader, directoryDataOffset, directoryDataLength);
5028
5037
  directoryView = getDataView(directoryArray);
5029
- if (directoryDataOffset > originalDirectoryDataOffset) {
5030
- prependedDataLength += directoryDataOffset - originalDirectoryDataOffset;
5038
+ const offsetDelta = directoryDataOffset - originalDirectoryDataOffset;
5039
+ const localHeaderOffset = getFirstLocalHeaderOffset(directoryArray, directoryView);
5040
+ const localHeaderFound = localHeaderOffset !== UNDEFINED_VALUE &&
5041
+ await startsWithSignature(reader, localHeaderOffset, LOCAL_FILE_HEADER_SIGNATURE);
5042
+ const shiftedLocalHeaderFound = localHeaderOffset !== UNDEFINED_VALUE &&
5043
+ await startsWithSignature(reader, localHeaderOffset + offsetDelta, LOCAL_FILE_HEADER_SIGNATURE);
5044
+ if (offsetDelta > 0 && !(localHeaderFound && !shiftedLocalHeaderFound)) {
5045
+ prependedDataLength += offsetDelta;
5031
5046
  prependedCentralDirectory = storedPointsAtDirectory;
5032
5047
  } else {
5033
5048
  reportAmbiguity(checkAmbiguity, warnings, WARNING_MISMATCHED_CENTRAL_DIRECTORY_OFFSET);
5034
- const offsetDelta = directoryDataOffset - originalDirectoryDataOffset;
5035
- if (directoryArray.length >= CENTRAL_FILE_HEADER_LENGTH) {
5036
- const localHeaderOffset = getUint32$1(directoryView, 42);
5037
- if (!await startsWithSignature(reader, localHeaderOffset, LOCAL_FILE_HEADER_SIGNATURE) &&
5038
- await startsWithSignature(reader, localHeaderOffset + offsetDelta, LOCAL_FILE_HEADER_SIGNATURE)) {
5039
- prependedDataLength += offsetDelta;
5040
- }
5049
+ if (offsetDelta < 0 && !localHeaderFound && shiftedLocalHeaderFound) {
5050
+ prependedDataLength += offsetDelta;
5041
5051
  }
5042
5052
  }
5043
5053
  }
5044
5054
  }
5055
+ if (directoryArray.length < 4) {
5056
+ throw new Error(ERR_BAD_FORMAT);
5057
+ }
5058
+ } else if (!filesLength && directoryDataOffset < centralDirectoryEndOffset && diskNumber == lastDiskNumber) {
5059
+ prependedDataLength += centralDirectoryEndOffset - directoryDataOffset;
5060
+ directoryDataOffset = centralDirectoryEndOffset;
5045
5061
  }
5046
5062
  const expectedDirectoryDataLength = centralDirectoryEndOffset - directoryDataOffset;
5047
5063
  if (directoryDataLength != expectedDirectoryDataLength && expectedDirectoryDataLength >= 0 && diskNumber == lastDiskNumber) {
@@ -5083,8 +5099,10 @@ class ZipReader {
5083
5099
  addWarning(warnings, WARNING_WRAPPED_ENTRIES_COUNT);
5084
5100
  }
5085
5101
  }
5102
+ const entryOptions = Object.assign({}, zipReader.options, options, { [OPTION_STRICTNESS]: strictness });
5103
+ delete entryOptions[OPTION_CHECK_AMBIGUITY];
5086
5104
  for (let indexFile = 0; indexFile < filesLength; indexFile++) {
5087
- const fileEntry = new ZipEntry(reader, zipReader.options);
5105
+ const fileEntry = new ZipEntry(reader, entryOptions);
5088
5106
  if (offset + CENTRAL_FILE_HEADER_LENGTH > directoryArray.length || getUint32$1(directoryView, offset) != CENTRAL_FILE_HEADER_SIGNATURE) {
5089
5107
  if (indexFile == 0 && !decryptedDirectory && (zip64EndOfDirectoryVersion2 || detectEncryptedCentralDirectory(directoryView))) {
5090
5108
  throw new Error(ERR_ENCRYPTED_CENTRAL_DIRECTORY);
@@ -5175,13 +5193,17 @@ class ZipReader {
5175
5193
  if (malformedExtraField) {
5176
5194
  addWarning(warnings, WARNING_MALFORMED_EXTRA_FIELD, filename);
5177
5195
  }
5178
- fileEntry.offset += prependedDataLength;
5179
- const entryPosition = getDiskOffset$1(reader, fileEntry.diskNumberStart) + fileEntry.offset;
5180
- startOffset = Math.min(entryPosition, startOffset);
5181
- if (entryPosition < previousEntryPosition) {
5182
- addWarning(warnings, WARNING_UNSORTED_CENTRAL_DIRECTORY, filename);
5196
+ if (fileEntry.zip64ExtraFieldMissing && fileEntry.offset == MAX_32_BITS) {
5197
+ startOffset = 0;
5198
+ } else {
5199
+ fileEntry.offset += prependedDataLength;
5200
+ const entryPosition = getDiskOffset$1(reader, fileEntry.diskNumberStart) + fileEntry.offset;
5201
+ startOffset = Math.min(entryPosition, startOffset);
5202
+ if (entryPosition < previousEntryPosition) {
5203
+ addWarning(warnings, WARNING_UNSORTED_CENTRAL_DIRECTORY, filename);
5204
+ }
5205
+ previousEntryPosition = entryPosition;
5183
5206
  }
5184
- previousEntryPosition = entryPosition;
5185
5207
  if ((fileEntry.version & MAX_8_BITS) > MAX_KNOWN_VERSION) {
5186
5208
  addWarning(warnings, WARNING_UNKNOWN_VERSION, filename);
5187
5209
  }
@@ -5218,12 +5240,15 @@ class ZipReader {
5218
5240
  zipCrypto: fileEntry.encrypted && !fileEntry.extraFieldAES
5219
5241
  });
5220
5242
  const entry = new Entry(fileEntry);
5221
- entry.getData = (writer, options) => fileEntry.getData(writer, entry, zipReader.readRanges, options);
5243
+ if (fileEntry.zip64ExtraFieldMissing) {
5244
+ zipReader.entriesMissingZip64ExtraField.add(entry);
5245
+ }
5246
+ entry.getData = (writer, options) => fileEntry.getData(writer, entry, zipReader, options);
5222
5247
  entry.arrayBuffer = async options => {
5223
5248
  const writer = new TransformStream();
5224
5249
  const arrayBufferPromise = streamToBlob(writer.readable).then(blob => blob.arrayBuffer());
5225
5250
  arrayBufferPromise.catch(() => { });
5226
- await fileEntry.getData(writer, entry, zipReader.readRanges,
5251
+ await fileEntry.getData(writer, entry, zipReader,
5227
5252
  Object.assign({}, options, { preventClose: false }));
5228
5253
  return arrayBufferPromise;
5229
5254
  };
@@ -5431,8 +5456,9 @@ class ZipEntry {
5431
5456
  });
5432
5457
  }
5433
5458
 
5434
- async getData(writer, fileEntry, readRanges, options = {}) {
5459
+ async getData(writer, fileEntry, zipReader, options = {}) {
5435
5460
  const zipEntry = this;
5461
+ const { readRanges, directoryOffset } = zipReader;
5436
5462
  if (zipEntry.zip64ExtraFieldMissing) {
5437
5463
  throw new Error(ERR_EXTRAFIELD_ZIP64_NOT_FOUND);
5438
5464
  }
@@ -5506,10 +5532,10 @@ class ZipEntry {
5506
5532
  }
5507
5533
  validateLocalDirectory(zipEntry, localDirectory, rawLocalFilename, checkLocalFilename, checkLocalDirectory ? UNDEFINED_VALUE : warnings);
5508
5534
  const { lastAccessDate, creationDate, uid, gid } = localDirectory;
5509
- if (lastAccessDate) {
5535
+ if (lastAccessDate && fileEntry.lastAccessDate === UNDEFINED_VALUE) {
5510
5536
  fileEntry.lastAccessDate = lastAccessDate;
5511
5537
  }
5512
- if (creationDate) {
5538
+ if (creationDate && fileEntry.creationDate === UNDEFINED_VALUE) {
5513
5539
  fileEntry.creationDate = creationDate;
5514
5540
  }
5515
5541
  if (uid !== UNDEFINED_VALUE && fileEntry.uid === UNDEFINED_VALUE) {
@@ -5538,7 +5564,7 @@ class ZipEntry {
5538
5564
  throw new Error(ERR_ENCRYPTED);
5539
5565
  }
5540
5566
  }
5541
- if (dataOffset + compressedSize > reader.size) {
5567
+ if (dataOffset + compressedSize > Math.min(reader.size, directoryOffset)) {
5542
5568
  throw new Error(ERR_ENTRY_DATA_OUT_OF_BOUNDS);
5543
5569
  }
5544
5570
  const size = compressedSize;
@@ -5604,6 +5630,7 @@ class ZipEntry {
5604
5630
  extraFieldZip64: extraFieldZip64 || localDirectory.extraFieldZip64,
5605
5631
  readRanges
5606
5632
  });
5633
+ validateDataDescriptor(zipEntry, localDirectory, checkLocalDirectory ? UNDEFINED_VALUE : warnings);
5607
5634
  }
5608
5635
  let writable, abortError, aborted;
5609
5636
  try {
@@ -5623,10 +5650,7 @@ class ZipEntry {
5623
5650
  writer.size += writtenSize;
5624
5651
  }
5625
5652
  } catch (error) {
5626
- const { outputSize: failedOutputSize } = workerOptions;
5627
- if (failedOutputSize !== UNDEFINED_VALUE) {
5628
- writer.size += failedOutputSize;
5629
- } else if (isErrorObject(error) && error.outputSize !== UNDEFINED_VALUE) {
5653
+ if (isErrorObject(error) && error.outputSize !== UNDEFINED_VALUE) {
5630
5654
  writer.size += error.outputSize;
5631
5655
  }
5632
5656
  if (!checkPasswordOnly || !isErrorObject(error) || error.message != ERR_ABORT_CHECK_PASSWORD) {
@@ -5654,13 +5678,7 @@ class ZipEntry {
5654
5678
  }
5655
5679
 
5656
5680
  function detectEncryptedCentralDirectory(directoryView) {
5657
- const maxOffset = Math.min(directoryView.byteLength, 1024) - 3;
5658
- for (let offset = 0; offset < maxOffset; offset++) {
5659
- if (getUint32$1(directoryView, offset) == ARCHIVE_EXTRA_DATA_SIGNATURE) {
5660
- return true;
5661
- }
5662
- }
5663
- return false;
5681
+ return directoryView.byteLength >= 4 && getUint32$1(directoryView, 0) == ARCHIVE_EXTRA_DATA_SIGNATURE;
5664
5682
  }
5665
5683
 
5666
5684
  function getWrappedFilesLength(directoryView, directoryArray, offset) {
@@ -5697,6 +5715,46 @@ async function findDigitalSignatureRecordOffset(reader, endOffset) {
5697
5715
  }
5698
5716
  }
5699
5717
 
5718
+ async function findZip64EndOfDirectoryOffset(reader, endOffset) {
5719
+ const startOffset = Math.max(0, endOffset - (ZIP64_END_OF_CENTRAL_DIR_LENGTH + MAX_16_BITS));
5720
+ const tailArray = await readUint8Array(reader, startOffset, endOffset - startOffset);
5721
+ const tailView = getDataView(tailArray);
5722
+ for (let indexByte = tailArray.length - ZIP64_END_OF_CENTRAL_DIR_LENGTH; indexByte >= 0; indexByte--) {
5723
+ if (getUint32$1(tailView, indexByte) == ZIP64_END_OF_CENTRAL_DIR_SIGNATURE &&
5724
+ indexByte + 12 + Number(tailView.getBigUint64(indexByte + 4, true)) == tailArray.length) {
5725
+ return startOffset + indexByte;
5726
+ }
5727
+ }
5728
+ }
5729
+
5730
+ function getFirstLocalHeaderOffset(directoryArray, directoryView) {
5731
+ if (directoryArray.length < CENTRAL_FILE_HEADER_LENGTH) {
5732
+ return UNDEFINED_VALUE;
5733
+ }
5734
+ const localHeaderOffset = getUint32$1(directoryView, 42);
5735
+ if (localHeaderOffset != MAX_32_BITS) {
5736
+ return localHeaderOffset;
5737
+ }
5738
+ let offsetExtraField = CENTRAL_FILE_HEADER_LENGTH + getUint16$1(directoryView, 28);
5739
+ const endExtraField = Math.min(offsetExtraField + getUint16$1(directoryView, 30), directoryArray.length);
5740
+ while (offsetExtraField + 4 <= endExtraField) {
5741
+ const type = getUint16$1(directoryView, offsetExtraField);
5742
+ const size = getUint16$1(directoryView, offsetExtraField + 2);
5743
+ if (type == EXTRAFIELD_TYPE_ZIP64) {
5744
+ let offsetValue = offsetExtraField + 4;
5745
+ if (getUint32$1(directoryView, 24) == MAX_32_BITS) {
5746
+ offsetValue += 8;
5747
+ }
5748
+ if (getUint32$1(directoryView, 20) == MAX_32_BITS) {
5749
+ offsetValue += 8;
5750
+ }
5751
+ return offsetValue + 8 <= endExtraField ? getBigUint64(directoryView, offsetValue) : UNDEFINED_VALUE;
5752
+ }
5753
+ offsetExtraField += 4 + size;
5754
+ }
5755
+ return UNDEFINED_VALUE;
5756
+ }
5757
+
5700
5758
  function readDigitalSignature(signatureRecordArray) {
5701
5759
  if (signatureRecordArray.length >= 6) {
5702
5760
  const signatureRecordView = getDataView(signatureRecordArray);
@@ -5786,6 +5844,7 @@ function readCommonFooter(fileEntry, directory, dataView, offset, localDirectory
5786
5844
  uncompressedSize: getUint32$1(dataView, offset + HEADER_OFFSET_UNCOMPRESSED_SIZE)
5787
5845
  });
5788
5846
  const extraFieldZip64 = extraField.get(EXTRAFIELD_TYPE_ZIP64);
5847
+ let extraFieldZip64Missing;
5789
5848
  if (extraFieldZip64) {
5790
5849
  if (!readExtraFieldZip64(extraFieldZip64, directory, localDirectory)) {
5791
5850
  malformedExtraField = true;
@@ -5795,7 +5854,7 @@ function readCommonFooter(fileEntry, directory, dataView, offset, localDirectory
5795
5854
  if (localDirectory) {
5796
5855
  malformedExtraField = true;
5797
5856
  } else {
5798
- throw new Error(ERR_EXTRAFIELD_ZIP64_NOT_FOUND);
5857
+ extraFieldZip64Missing = true;
5799
5858
  }
5800
5859
  }
5801
5860
  const extraFieldUnicodePath = extraField.get(EXTRAFIELD_TYPE_UNICODE_PATH);
@@ -5853,6 +5912,9 @@ function readCommonFooter(fileEntry, directory, dataView, offset, localDirectory
5853
5912
  if (extraFieldUSDZ) {
5854
5913
  directory.extraFieldUSDZ = extraFieldUSDZ;
5855
5914
  }
5915
+ if (extraFieldZip64Missing) {
5916
+ throw new Error(ERR_EXTRAFIELD_ZIP64_NOT_FOUND);
5917
+ }
5856
5918
  return malformedExtraField;
5857
5919
  }
5858
5920
 
@@ -6067,13 +6129,7 @@ async function detectOverlappingEntry({
6067
6129
  let dataDescriptorLength = 0;
6068
6130
  if (dataDescriptor) {
6069
6131
  const zip64 = Boolean(extraFieldZip64);
6070
- const dataDescriptorArray = await readUint8Array(reader, dataOffset + compressedSize, DATA_DESCRIPTOR_RECORD_ZIP_64_LENGTH + DATA_DESCRIPTOR_RECORD_SIGNATURE_LENGTH);
6071
- const dataDescriptorView = getDataView(dataDescriptorArray);
6072
- const candidates = [[zip64, true], [zip64, false], [!zip64, true], [!zip64, false]]
6073
- .map(([zip64Layout, signature]) => readDataDescriptor(dataDescriptorView, zip64Layout, signature))
6074
- .filter(candidate => candidate && candidate.compressedSize == compressedSize && candidate.uncompressedSize == uncompressedSize);
6075
- const localDataDescriptor = candidates.find(candidate => candidate.crc32 == crc32) || candidates[0] ||
6076
- readDataDescriptor(dataDescriptorView, zip64, true) || readDataDescriptor(dataDescriptorView, zip64, false);
6132
+ const localDataDescriptor = await readLocalDataDescriptor(reader, dataOffset + compressedSize, { crc32, compressedSize, uncompressedSize, zip64 });
6077
6133
  if (localDataDescriptor) {
6078
6134
  fileEntry.localDirectory.dataDescriptor = localDataDescriptor;
6079
6135
  dataDescriptorLength = getDataDescriptorLength(localDataDescriptor.zip64, localDataDescriptor.signature);
@@ -6143,6 +6199,25 @@ function mergeRanges(sortedRanges, pendingRanges) {
6143
6199
  return mergedRanges;
6144
6200
  }
6145
6201
 
6202
+ async function readLocalDataDescriptor(reader, offset, { crc32, compressedSize, uncompressedSize, zip64 }) {
6203
+ const maxLength = DATA_DESCRIPTOR_RECORD_ZIP_64_LENGTH + DATA_DESCRIPTOR_RECORD_SIGNATURE_LENGTH;
6204
+ const length = Math.min(maxLength, Math.max(0, reader.size - offset));
6205
+ const dataDescriptorArray = length ? await readUint8Array(reader, offset, length) : EMPTY_UINT8_ARRAY;
6206
+ const dataDescriptorView = getDataView(dataDescriptorArray);
6207
+ const candidates = [[zip64, true], [zip64, false], [!zip64, true], [!zip64, false]]
6208
+ .map(([zip64Layout, signature]) => readDataDescriptor(dataDescriptorView, zip64Layout, signature))
6209
+ .filter(candidate => candidate && candidate.compressedSize == compressedSize && candidate.uncompressedSize == uncompressedSize);
6210
+ return candidates.find(candidate => candidate.crc32 == crc32) || candidates[0] ||
6211
+ readDataDescriptor(dataDescriptorView, zip64, true) || readDataDescriptor(dataDescriptorView, zip64, false);
6212
+ }
6213
+
6214
+ async function getEntryDataDescriptorLength(reader, offset, { crc32, compressedSize, uncompressedSize, extraFieldZip64 }) {
6215
+ const dataDescriptor = await readLocalDataDescriptor(reader, offset, { crc32, compressedSize, uncompressedSize, zip64: Boolean(extraFieldZip64) });
6216
+ if (dataDescriptor && dataDescriptor.compressedSize == compressedSize && dataDescriptor.uncompressedSize == uncompressedSize) {
6217
+ return getDataDescriptorLength(dataDescriptor.zip64, dataDescriptor.signature);
6218
+ }
6219
+ }
6220
+
6146
6221
  function readDataDescriptor(dataDescriptorView, zip64, signature) {
6147
6222
  const offset = signature ? DATA_DESCRIPTOR_RECORD_SIGNATURE_LENGTH : 0;
6148
6223
  if (dataDescriptorView.byteLength < getDataDescriptorLength(zip64, signature) ||
@@ -6402,6 +6477,18 @@ function validateLocalDirectory(zipEntry, localDirectory, rawLocalFilename, chec
6402
6477
  }
6403
6478
  }
6404
6479
 
6480
+ function validateDataDescriptor(zipEntry, localDirectory, warnings) {
6481
+ const { dataDescriptor } = localDirectory;
6482
+ const maskedLocalDirectory = zipEntry.decryptedDirectory &&
6483
+ (localDirectory.rawBitFlag & BITFLAG_MASKED_LOCAL_HEADERS) == BITFLAG_MASKED_LOCAL_HEADERS;
6484
+ if (dataDescriptor && !maskedLocalDirectory &&
6485
+ ((zipEntry.crc32 !== UNDEFINED_VALUE && dataDescriptor.crc32 != zipEntry.crc32) ||
6486
+ dataDescriptor.compressedSize != zipEntry.compressedSize ||
6487
+ dataDescriptor.uncompressedSize != zipEntry.uncompressedSize)) {
6488
+ reportAmbiguity(!warnings, warnings, WARNING_MISMATCHED_LOCAL_FILE_HEADER_CRC32_OR_SIZES);
6489
+ }
6490
+ }
6491
+
6405
6492
  function reportAmbiguity(reject, warnings, reason) {
6406
6493
  if (reject) {
6407
6494
  throwAmbiguousArchive(reason);
@@ -6504,6 +6591,7 @@ var zipReader = /*#__PURE__*/Object.freeze({
6504
6591
  WARNING_WRAPPED_ENTRIES_COUNT: WARNING_WRAPPED_ENTRIES_COUNT,
6505
6592
  ZipReader: ZipReader,
6506
6593
  ZipReaderStream: ZipReaderStream,
6594
+ getEntryDataDescriptorLength: getEntryDataDescriptorLength,
6507
6595
  isZipFile: isZipFile
6508
6596
  });
6509
6597
 
@@ -6627,136 +6715,7 @@ class ZipWriter {
6627
6715
  }
6628
6716
 
6629
6717
  appendZip(reader, options = {}) {
6630
- return watchPromiseError(this, this.appendZipEntries(reader, options));
6631
- }
6632
-
6633
- async appendZipEntries(reader, options = {}) {
6634
- const zipWriter = this;
6635
- const { pendingAddFileCalls, filenames, fileEntries } = zipWriter;
6636
- const filter = checkFunctionOption(options.filter);
6637
- while (pendingAddFileCalls.size) {
6638
- await Promise.allSettled(Array.from(pendingAddFileCalls));
6639
- }
6640
- let resolveAppendZip;
6641
- const promiseAppendZip = new Promise(resolve => resolveAppendZip = resolve);
6642
- pendingAddFileCalls.add(promiseAppendZip);
6643
- const appendedFilenames = [];
6644
- let releaseLockWriter;
6645
- try {
6646
- reader = new GenericReader(reader);
6647
- await initStream(reader);
6648
- if (reader.size === UNDEFINED_VALUE || !reader.readUint8Array) {
6649
- reader = new BlobReader(await streamToBlob(reader.readable));
6650
- await initStream(reader);
6651
- }
6652
- const { ZipReader } = await Promise.resolve().then(function () { return zipReader; });
6653
- const zipReader$1 = new ZipReader(reader);
6654
- const entries = await zipReader$1.getEntries();
6655
- const keptEntries = [];
6656
- for (const entry of entries) {
6657
- if (!filter || await filter(entry)) {
6658
- keptEntries.push(entry);
6659
- }
6660
- }
6661
- await zipReader$1.close();
6662
- await initStream(zipWriter.writer);
6663
- const { directoryOffset } = zipReader$1;
6664
- keptEntries.forEach(({ filename }) => {
6665
- if (filenames.has(filename)) {
6666
- throw new Error(ERR_DUPLICATED_NAME);
6667
- }
6668
- filenames.add(filename);
6669
- appendedFilenames.push(filename);
6670
- });
6671
- zipWriter.writerLocked = true;
6672
- const { lockWriter } = zipWriter;
6673
- zipWriter.lockWriter = new Promise(resolve => releaseLockWriter = () => {
6674
- zipWriter.writerLocked = false;
6675
- resolve();
6676
- });
6677
- await lockWriter;
6678
- if (zipWriter.addSplitZipSignature) {
6679
- delete zipWriter.addSplitZipSignature;
6680
- if (!await startsWithSplitZipSignature(reader)) {
6681
- await writeData(zipWriter.writer, getSplitZipSignatureArray());
6682
- zipWriter.offset += SPLIT_ZIP_FILE_SIGNATURE_LENGTH;
6683
- }
6684
- }
6685
- const entryPositions = await copyZipData(zipWriter, reader, entries, keptEntries, directoryOffset, Boolean(filter));
6686
- keptEntries.forEach(entry => {
6687
- const {
6688
- version,
6689
- rawLastModDate,
6690
- rawFilename,
6691
- bitFlag,
6692
- encrypted,
6693
- uncompressedSize,
6694
- compressedSize,
6695
- extraFieldZip64
6696
- } = entry;
6697
- let {
6698
- compressionMethod,
6699
- rawExtraField,
6700
- } = entry;
6701
- const { level, languageEncodingFlag, dataDescriptor } = bitFlag;
6702
- rawExtraField = removeExtraFieldZip64(rawExtraField || EMPTY_UINT8_ARRAY);
6703
- if (entry.extraFieldAES) {
6704
- compressionMethod = COMPRESSION_METHOD_AES;
6705
- }
6706
- const extraFieldLength = getLength(rawExtraField);
6707
- const zip64UncompressedSize = Boolean(extraFieldZip64) && extraFieldZip64.uncompressedSize !== UNDEFINED_VALUE;
6708
- const zip64CompressedSize = Boolean(extraFieldZip64) && extraFieldZip64.compressedSize !== UNDEFINED_VALUE;
6709
- const bitFlagValue = (getBitFlag(level, languageEncodingFlag, dataDescriptor, encrypted, compressionMethod) & ~BITFLAG_LEVEL) | (level << 1);
6710
- const {
6711
- headerArray,
6712
- headerView
6713
- } = getHeaderArrayData({
6714
- version,
6715
- bitFlag: bitFlagValue,
6716
- compressionMethod,
6717
- uncompressedSize,
6718
- compressedSize,
6719
- rawLastModDate,
6720
- rawFilename,
6721
- zip64CompressedSize,
6722
- zip64UncompressedSize,
6723
- extraFieldLength
6724
- });
6725
- const { crc32 } = entry;
6726
- if (crc32 !== UNDEFINED_VALUE) {
6727
- setUint32(headerView, HEADER_OFFSET_SIGNATURE, crc32);
6728
- }
6729
- const { offset, diskNumberStart } = entryPositions.get(entry);
6730
- Object.assign(entry, {
6731
- zip64Enabled: true,
6732
- zip64UncompressedSize,
6733
- zip64CompressedSize,
6734
- offset,
6735
- diskNumberStart,
6736
- zip64DiskNumberStart: false,
6737
- rawExtraFieldZip64: EMPTY_UINT8_ARRAY,
6738
- rawExtraFieldAES: EMPTY_UINT8_ARRAY,
6739
- rawExtraFieldExtendedTimestamp: EMPTY_UINT8_ARRAY,
6740
- rawExtraFieldNTFS: EMPTY_UINT8_ARRAY,
6741
- rawExtraFieldUnix: EMPTY_UINT8_ARRAY,
6742
- rawCentralExtraFieldUnix: EMPTY_UINT8_ARRAY,
6743
- rawExtraField,
6744
- rawCentralExtraField: EMPTY_UINT8_ARRAY,
6745
- headerArray,
6746
- headerView
6747
- });
6748
- fileEntries.set(entry.filename, entry);
6749
- });
6750
- } catch (error) {
6751
- appendedFilenames.forEach(filename => filenames.delete(filename));
6752
- throw error;
6753
- } finally {
6754
- resolveAppendZip();
6755
- pendingAddFileCalls.delete(promiseAppendZip);
6756
- if (releaseLockWriter) {
6757
- releaseLockWriter();
6758
- }
6759
- }
6718
+ return watchPromiseError(this, appendZipEntries(this, reader, options));
6760
6719
  }
6761
6720
 
6762
6721
  add(name = "", reader, options = {}) {
@@ -6918,11 +6877,140 @@ function watchPromiseError(zipWriter, promise) {
6918
6877
  return watchedPromise;
6919
6878
  }
6920
6879
 
6880
+ async function appendZipEntries(zipWriter, reader, options = {}) {
6881
+ const { pendingAddFileCalls, filenames, fileEntries } = zipWriter;
6882
+ const filter = checkFunctionOption(options.filter);
6883
+ while (pendingAddFileCalls.size) {
6884
+ await Promise.allSettled(Array.from(pendingAddFileCalls));
6885
+ }
6886
+ let resolveAppendZip;
6887
+ const promiseAppendZip = new Promise(resolve => resolveAppendZip = resolve);
6888
+ pendingAddFileCalls.add(promiseAppendZip);
6889
+ const appendedFilenames = [];
6890
+ let releaseLockWriter;
6891
+ try {
6892
+ reader = new GenericReader(reader);
6893
+ await initStream(reader);
6894
+ if (reader.size === UNDEFINED_VALUE || !reader.readUint8Array) {
6895
+ reader = new BlobReader(await streamToBlob(reader.readable));
6896
+ await initStream(reader);
6897
+ }
6898
+ const { ZipReader, getEntryDataDescriptorLength } = await Promise.resolve().then(function () { return zipReader; });
6899
+ const zipReader$1 = new ZipReader(reader);
6900
+ const entries = await zipReader$1.getEntries();
6901
+ const keptEntries = [];
6902
+ for (const entry of entries) {
6903
+ if (!filter || await filter(entry)) {
6904
+ keptEntries.push(entry);
6905
+ }
6906
+ }
6907
+ await zipReader$1.close();
6908
+ await initStream(zipWriter.writer);
6909
+ const { directoryOffset, entriesMissingZip64ExtraField } = zipReader$1;
6910
+ keptEntries.forEach(entry => {
6911
+ const { filename } = entry;
6912
+ if (entriesMissingZip64ExtraField.has(entry)) {
6913
+ throw new Error(ERR_EXTRAFIELD_ZIP64_NOT_FOUND);
6914
+ }
6915
+ if (filenames.has(filename)) {
6916
+ throw new Error(ERR_DUPLICATED_NAME);
6917
+ }
6918
+ filenames.add(filename);
6919
+ appendedFilenames.push(filename);
6920
+ });
6921
+ zipWriter.writerLocked = true;
6922
+ const { lockWriter } = zipWriter;
6923
+ zipWriter.lockWriter = new Promise(resolve => releaseLockWriter = () => {
6924
+ zipWriter.writerLocked = false;
6925
+ resolve();
6926
+ });
6927
+ await lockWriter;
6928
+ if (zipWriter.addSplitZipSignature) {
6929
+ delete zipWriter.addSplitZipSignature;
6930
+ if (filter || !await startsWithSplitZipSignature(reader)) {
6931
+ await writeData(zipWriter.writer, getSplitZipSignatureArray());
6932
+ zipWriter.offset += SPLIT_ZIP_FILE_SIGNATURE_LENGTH;
6933
+ }
6934
+ }
6935
+ const entryPositions = await copyZipData(zipWriter, reader, entries, keptEntries, directoryOffset, Boolean(filter), getEntryDataDescriptorLength);
6936
+ keptEntries.forEach(entry => {
6937
+ const {
6938
+ version,
6939
+ rawLastModDate,
6940
+ rawFilename,
6941
+ rawBitFlag,
6942
+ uncompressedSize,
6943
+ compressedSize,
6944
+ extraFieldZip64
6945
+ } = entry;
6946
+ let {
6947
+ compressionMethod,
6948
+ rawExtraField,
6949
+ } = entry;
6950
+ rawExtraField = removeExtraFieldZip64(rawExtraField || EMPTY_UINT8_ARRAY);
6951
+ if (entry.extraFieldAES) {
6952
+ compressionMethod = COMPRESSION_METHOD_AES;
6953
+ }
6954
+ const extraFieldLength = getLength(rawExtraField);
6955
+ const zip64UncompressedSize = Boolean(extraFieldZip64) && extraFieldZip64.uncompressedSize !== UNDEFINED_VALUE;
6956
+ const zip64CompressedSize = Boolean(extraFieldZip64) && extraFieldZip64.compressedSize !== UNDEFINED_VALUE;
6957
+ const {
6958
+ headerArray,
6959
+ headerView
6960
+ } = getHeaderArrayData({
6961
+ version,
6962
+ bitFlag: rawBitFlag,
6963
+ compressionMethod,
6964
+ uncompressedSize,
6965
+ compressedSize,
6966
+ rawLastModDate,
6967
+ rawFilename,
6968
+ zip64CompressedSize,
6969
+ zip64UncompressedSize,
6970
+ extraFieldLength
6971
+ });
6972
+ const { crc32 } = entry;
6973
+ if (crc32 !== UNDEFINED_VALUE) {
6974
+ setUint32(headerView, HEADER_OFFSET_SIGNATURE, crc32);
6975
+ }
6976
+ const { offset, diskNumberStart } = entryPositions.get(entry);
6977
+ Object.assign(entry, {
6978
+ zip64Enabled: true,
6979
+ zip64UncompressedSize,
6980
+ zip64CompressedSize,
6981
+ offset,
6982
+ diskNumberStart,
6983
+ zip64DiskNumberStart: false,
6984
+ rawExtraFieldZip64: EMPTY_UINT8_ARRAY,
6985
+ rawExtraFieldAES: EMPTY_UINT8_ARRAY,
6986
+ rawExtraFieldExtendedTimestamp: EMPTY_UINT8_ARRAY,
6987
+ rawExtraFieldNTFS: EMPTY_UINT8_ARRAY,
6988
+ rawExtraFieldUnix: EMPTY_UINT8_ARRAY,
6989
+ rawCentralExtraFieldUnix: EMPTY_UINT8_ARRAY,
6990
+ rawExtraField,
6991
+ rawCentralExtraField: EMPTY_UINT8_ARRAY,
6992
+ headerArray,
6993
+ headerView
6994
+ });
6995
+ fileEntries.set(entry.filename, entry);
6996
+ });
6997
+ } catch (error) {
6998
+ appendedFilenames.forEach(filename => filenames.delete(filename));
6999
+ throw error;
7000
+ } finally {
7001
+ resolveAppendZip();
7002
+ pendingAddFileCalls.delete(promiseAppendZip);
7003
+ if (releaseLockWriter) {
7004
+ releaseLockWriter();
7005
+ }
7006
+ }
7007
+ }
7008
+
6921
7009
  async function prependZipEntries(zipWriter, reader) {
6922
7010
  if (zipWriter.filenames.size) {
6923
7011
  throw new Error(ERR_ZIP_NOT_EMPTY);
6924
7012
  }
6925
- await zipWriter.appendZipEntries(reader);
7013
+ await appendZipEntries(zipWriter, reader);
6926
7014
  }
6927
7015
 
6928
7016
  async function addFileEntry(zipWriter, name, reader, options) {
@@ -8596,7 +8684,7 @@ function removeExtraFieldZip64(rawExtraField) {
8596
8684
  return rawExtraField;
8597
8685
  }
8598
8686
 
8599
- async function copyZipData(zipWriter, reader, entries, keptEntries, directoryOffset, compact) {
8687
+ async function copyZipData(zipWriter, reader, entries, keptEntries, directoryOffset, compact, getEntryDataDescriptorLength) {
8600
8688
  const { writer } = zipWriter;
8601
8689
  const entryPositions = new Map();
8602
8690
  if (writer.closeDisk || compact) {
@@ -8604,6 +8692,27 @@ async function copyZipData(zipWriter, reader, entries, keptEntries, directoryOff
8604
8692
  getSourceOffset(reader, firstEntry) - getSourceOffset(reader, secondEntry));
8605
8693
  const regionEnds = getRegionEnds(reader, sortedEntries, directoryOffset);
8606
8694
  const keptEntrySet = new Set(keptEntries);
8695
+ const localHeaderLengths = new Map();
8696
+ for (let indexEntry = 0; indexEntry < sortedEntries.length; indexEntry++) {
8697
+ const entry = sortedEntries[indexEntry];
8698
+ if (keptEntrySet.has(entry)) {
8699
+ const sourceOffset = getSourceOffset(reader, entry);
8700
+ const localHeaderLength = await getLocalHeaderLength(reader, sourceOffset);
8701
+ if (localHeaderLength === UNDEFINED_VALUE) {
8702
+ throw new Error(ERR_LOCAL_FILE_HEADER_NOT_FOUND);
8703
+ }
8704
+ let entryEnd = sourceOffset + localHeaderLength + entry.compressedSize;
8705
+ if (entry.bitFlag.dataDescriptor) {
8706
+ const dataDescriptorLength = await getEntryDataDescriptorLength(reader, entryEnd, entry);
8707
+ entryEnd = dataDescriptorLength === UNDEFINED_VALUE ? Math.max(entryEnd, regionEnds[indexEntry]) : entryEnd + dataDescriptorLength;
8708
+ }
8709
+ if (entryEnd > regionEnds[indexEntry]) {
8710
+ throw new Error(ERR_OVERLAPPING_ENTRY);
8711
+ }
8712
+ regionEnds[indexEntry] = entryEnd;
8713
+ localHeaderLengths.set(entry, localHeaderLength);
8714
+ }
8715
+ }
8607
8716
  let copiedOffset = 0;
8608
8717
  let lastPosition;
8609
8718
  for (let indexEntry = 0; indexEntry < sortedEntries.length; indexEntry++) {
@@ -8616,7 +8725,7 @@ async function copyZipData(zipWriter, reader, entries, keptEntries, directoryOff
8616
8725
  if (!compact) {
8617
8726
  await copyData(zipWriter, reader, copiedOffset, sourceOffset - copiedOffset);
8618
8727
  }
8619
- if (writer.closeDisk && exceedsAvailableSize(writer, await getLocalHeaderLength(reader, sourceOffset))) {
8728
+ if (writer.closeDisk && exceedsAvailableSize(writer, localHeaderLengths.get(entry))) {
8620
8729
  await writer.closeDisk();
8621
8730
  }
8622
8731
  lastPosition = {
@@ -8650,7 +8759,7 @@ function getRegionEnds(reader, sortedEntries, directoryOffset) {
8650
8759
  const sourceOffset = getSourceOffset(reader, sortedEntries[indexEntry]);
8651
8760
  const nextEntry = sortedEntries[indexEntry + 1];
8652
8761
  if (nextEntry && getSourceOffset(reader, nextEntry) > sourceOffset) {
8653
- regionEnd = getSourceOffset(reader, nextEntry);
8762
+ regionEnd = Math.min(getSourceOffset(reader, nextEntry), directoryOffset);
8654
8763
  }
8655
8764
  regionEnds[indexEntry] = regionEnd;
8656
8765
  }
@@ -8664,11 +8773,13 @@ async function copyData(zipWriter, reader, offset, size) {
8664
8773
  try {
8665
8774
  await flushBufferedData(createReadable(reader, { offset, size }), writer, UNDEFINED_VALUE, chunkLength => copiedLength += chunkLength);
8666
8775
  } catch (error) {
8667
- zipWriter.hasCorruptedEntries = true;
8668
- try {
8669
- error.corruptedEntry = true;
8670
- } catch {
8671
- // ignored
8776
+ if (copiedLength) {
8777
+ zipWriter.hasCorruptedEntries = true;
8778
+ try {
8779
+ error.corruptedEntry = true;
8780
+ } catch {
8781
+ // ignored
8782
+ }
8672
8783
  }
8673
8784
  throw error;
8674
8785
  } finally {
@@ -8679,11 +8790,16 @@ async function copyData(zipWriter, reader, offset, size) {
8679
8790
  }
8680
8791
 
8681
8792
  async function getLocalHeaderLength(reader, offset) {
8682
- const headerArray = await readUint8Array(reader, offset, HEADER_SIZE);
8793
+ const headerArray = offset >= 0 && offset + HEADER_SIZE <= reader.size ?
8794
+ await readUint8Array(reader, offset, HEADER_SIZE) :
8795
+ EMPTY_UINT8_ARRAY;
8683
8796
  if (getLength(headerArray) < HEADER_SIZE) {
8684
- return HEADER_SIZE;
8797
+ return UNDEFINED_VALUE;
8685
8798
  }
8686
8799
  const headerView = getDataView(headerArray);
8800
+ if (getUint32(headerView, 0) != LOCAL_FILE_HEADER_SIGNATURE) {
8801
+ return UNDEFINED_VALUE;
8802
+ }
8687
8803
  return HEADER_SIZE +
8688
8804
  getUint16(headerView, HEADER_OFFSET_FILENAME_LENGTH + LOCAL_HEADER_COMMON_OFFSET) +
8689
8805
  getUint16(headerView, HEADER_OFFSET_EXTRAFIELD_LENGTH + LOCAL_HEADER_COMMON_OFFSET);
@@ -9034,7 +9150,7 @@ function formatSupported(StreamClass, format) {
9034
9150
  EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
9035
9151
  */
9036
9152
 
9037
- const VERSION = "2.20.0";
9153
+ const VERSION = "2.21.0";
9038
9154
 
9039
9155
  /*
9040
9156
  Copyright (c) 2025 Gildas Lormeau. All rights reserved.