@zip.js/zip.js 2.20.0 → 2.22.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.
package/dist/zip-core.js CHANGED
@@ -126,6 +126,10 @@
126
126
 
127
127
  const UNDEFINED_VALUE = undefined;
128
128
  const INFINITY_VALUE = Infinity;
129
+ const ERR_LOCAL_FILE_HEADER_NOT_FOUND = "Local file header not found";
130
+ const ERR_OVERLAPPING_ENTRY = "Overlapping entry found";
131
+ const ERR_EXTRAFIELD_ZIP64_NOT_FOUND = "Zip64 extra field not found";
132
+
129
133
  const UNDEFINED_TYPE = "undefined";
130
134
  const FUNCTION_TYPE = "function";
131
135
  const OBJECT_TYPE = "object";
@@ -221,6 +225,7 @@
221
225
  const ERR_INVALID_SIGNAL = "Invalid signal (must be an AbortSignal instance)";
222
226
  const ERR_INVALID_PASSWORD_TYPE = "Invalid password (password must be a string, rawPassword must be a Uint8Array)";
223
227
  const ERR_INVALID_PASS_THROUGH_VALUE = "Invalid passThrough option (must be a boolean or 'compressed')";
228
+ const ERR_INVALID_READER_OPTIONS = "Invalid readerOptions (must be an object)";
224
229
  const ERR_ABORTED = "The operation was aborted";
225
230
  const ABORT_ERROR_NAME = "AbortError";
226
231
 
@@ -231,6 +236,13 @@
231
236
  return value;
232
237
  }
233
238
 
239
+ function checkReaderOptionsObject(readerOptions) {
240
+ if (readerOptions && (typeof readerOptions != OBJECT_TYPE || Array.isArray(readerOptions))) {
241
+ throw new Error(ERR_INVALID_READER_OPTIONS);
242
+ }
243
+ return readerOptions;
244
+ }
245
+
234
246
  function checkSignalOption(signal) {
235
247
  if (signal && (typeof signal.addEventListener != FUNCTION_TYPE || typeof signal.aborted != BOOLEAN_TYPE)) {
236
248
  throw new Error(ERR_INVALID_SIGNAL);
@@ -326,7 +338,6 @@
326
338
  workerStartupTimeout: 5000,
327
339
  useWebWorkers: true,
328
340
  useCompressionStream: true,
329
- transferStreams: true,
330
341
  CompressionStream: typeof CompressionStream != UNDEFINED_TYPE && CompressionStream,
331
342
  DecompressionStream: typeof DecompressionStream != UNDEFINED_TYPE && DecompressionStream
332
343
  };
@@ -340,8 +351,7 @@
340
351
  ];
341
352
  const BOOLEAN_PROPERTY_NAMES = [
342
353
  "useCompressionStream",
343
- "useWebWorkers",
344
- "transferStreams"
354
+ "useWebWorkers"
345
355
  ];
346
356
  const NUMBER_PROPERTY_NAMES = [
347
357
  "chunkSize",
@@ -4755,12 +4765,9 @@
4755
4765
  const ERR_EOCDR_NOT_FOUND = "End of central directory not found";
4756
4766
  const ERR_EOCDR_LOCATOR_ZIP64_NOT_FOUND = "End of Zip64 central directory locator not found";
4757
4767
  const ERR_CENTRAL_DIRECTORY_NOT_FOUND = "Central directory header not found";
4758
- const ERR_LOCAL_FILE_HEADER_NOT_FOUND = "Local file header not found";
4759
- const ERR_EXTRAFIELD_ZIP64_NOT_FOUND = "Zip64 extra field not found";
4760
4768
  const ERR_ENCRYPTED = "File contains encrypted entry";
4761
4769
  const ERR_UNSUPPORTED_ENCRYPTION = "Encryption method not supported";
4762
4770
  const ERR_SPLIT_ZIP_FILE = "Split zip file";
4763
- const ERR_OVERLAPPING_ENTRY = "Overlapping entry found";
4764
4771
  const ERR_ENTRY_DATA_OUT_OF_BOUNDS = "Entry data out of bounds";
4765
4772
  const ERR_AMBIGUOUS_ARCHIVE = "Ambiguous archive";
4766
4773
  const ERR_ENCRYPTED_CENTRAL_DIRECTORY = "Encrypted central directory is not supported";
@@ -4824,8 +4831,9 @@
4824
4831
  constructor(reader, options = {}) {
4825
4832
  Object.assign(this, {
4826
4833
  reader: new GenericReader(reader),
4827
- options,
4828
- readRanges: { indexes: new Set(), sortedRanges: [], pendingRanges: [] }
4834
+ options: options || {},
4835
+ readRanges: { indexes: new Set(), sortedRanges: [], pendingRanges: [] },
4836
+ entriesMissingZip64ExtraField: new WeakSet()
4829
4837
  });
4830
4838
  }
4831
4839
 
@@ -4896,16 +4904,22 @@
4896
4904
  directoryDataOffset = getDiskOffset$1(reader, getUint32$1(endOfDirectoryLocatorView, 4)) + getBigUint64(endOfDirectoryLocatorView, 8);
4897
4905
  let endOfDirectoryArray = await readUint8Array(reader, directoryDataOffset, ZIP64_END_OF_CENTRAL_DIR_LENGTH);
4898
4906
  let endOfDirectoryView = getDataView(endOfDirectoryArray);
4899
- const expectedDirectoryDataOffset = endOfDirectoryInfo.offset - ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH - ZIP64_END_OF_CENTRAL_DIR_LENGTH;
4900
- if ((endOfDirectoryArray.length < ZIP64_END_OF_CENTRAL_DIR_LENGTH || getUint32$1(endOfDirectoryView, 0) != ZIP64_END_OF_CENTRAL_DIR_SIGNATURE) &&
4901
- directoryDataOffset != expectedDirectoryDataOffset && expectedDirectoryDataOffset >= 0) {
4902
- const originalDirectoryDataOffset = directoryDataOffset;
4903
- directoryDataOffset = expectedDirectoryDataOffset;
4904
- if (directoryDataOffset > originalDirectoryDataOffset) {
4905
- prependedDataLength = directoryDataOffset - originalDirectoryDataOffset;
4907
+ if (endOfDirectoryArray.length < ZIP64_END_OF_CENTRAL_DIR_LENGTH || getUint32$1(endOfDirectoryView, 0) != ZIP64_END_OF_CENTRAL_DIR_SIGNATURE) {
4908
+ const locatorOffset = endOfDirectoryInfo.offset - ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH;
4909
+ let expectedDirectoryDataOffset = locatorOffset - ZIP64_END_OF_CENTRAL_DIR_LENGTH;
4910
+ if (!await startsWithSignature(reader, expectedDirectoryDataOffset, ZIP64_END_OF_CENTRAL_DIR_SIGNATURE)) {
4911
+ expectedDirectoryDataOffset = await findZip64EndOfDirectoryOffset(reader, locatorOffset);
4912
+ }
4913
+ if (expectedDirectoryDataOffset !== UNDEFINED_VALUE && expectedDirectoryDataOffset >= 0 &&
4914
+ directoryDataOffset != expectedDirectoryDataOffset) {
4915
+ const originalDirectoryDataOffset = directoryDataOffset;
4916
+ directoryDataOffset = expectedDirectoryDataOffset;
4917
+ if (directoryDataOffset > originalDirectoryDataOffset) {
4918
+ prependedDataLength = directoryDataOffset - originalDirectoryDataOffset;
4919
+ }
4920
+ endOfDirectoryArray = await readUint8Array(reader, directoryDataOffset, ZIP64_END_OF_CENTRAL_DIR_LENGTH);
4921
+ endOfDirectoryView = getDataView(endOfDirectoryArray);
4906
4922
  }
4907
- endOfDirectoryArray = await readUint8Array(reader, directoryDataOffset, ZIP64_END_OF_CENTRAL_DIR_LENGTH);
4908
- endOfDirectoryView = getDataView(endOfDirectoryArray);
4909
4923
  }
4910
4924
  if (endOfDirectoryArray.length < ZIP64_END_OF_CENTRAL_DIR_LENGTH || getUint32$1(endOfDirectoryView, 0) != ZIP64_END_OF_CENTRAL_DIR_SIGNATURE) {
4911
4925
  throw new Error(ERR_EOCDR_LOCATOR_ZIP64_NOT_FOUND);
@@ -4950,10 +4964,6 @@
4950
4964
  let declaredDirectoryDataLength = directoryDataLength;
4951
4965
  const centralDirectoryEndOffset = endOfDirectoryInfo.offset -
4952
4966
  (zip64EndOfDirectory ? zip64EndOfDirectoryLength + ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH : 0);
4953
- if (directoryDataOffset >= reader.size) {
4954
- prependedDataLength = reader.size - directoryDataOffset - directoryDataLength - END_OF_CENTRAL_DIR_LENGTH;
4955
- directoryDataOffset = reader.size - directoryDataLength - END_OF_CENTRAL_DIR_LENGTH;
4956
- }
4957
4967
  if (expectedLastDiskNumber != lastDiskNumber) {
4958
4968
  throw new Error(ERR_SPLIT_ZIP_FILE);
4959
4969
  }
@@ -4961,52 +4971,64 @@
4961
4971
  throw new Error(ERR_BAD_FORMAT);
4962
4972
  }
4963
4973
  let offset = 0;
4964
- let directoryArray = await readUint8Array(reader, directoryDataOffset, directoryDataLength);
4974
+ let directoryArray = directoryDataOffset < reader.size ?
4975
+ await readUint8Array(reader, directoryDataOffset, directoryDataLength) :
4976
+ EMPTY_UINT8_ARRAY;
4965
4977
  let directoryView = getDataView(directoryArray);
4966
4978
  if (directoryDataLength) {
4967
- if (directoryArray.length < 4) {
4968
- throw new Error(ERR_BAD_FORMAT);
4969
- }
4970
4979
  let expectedDirectoryDataOffset = centralDirectoryEndOffset - directoryDataLength;
4971
4980
  if (directoryDataOffset != expectedDirectoryDataOffset && diskNumber == lastDiskNumber) {
4972
- const storedPointsAtDirectory = getUint32$1(directoryView, offset) == CENTRAL_FILE_HEADER_SIGNATURE ||
4981
+ const storedPointsAtDirectory = directoryArray.length >= 4 && (
4982
+ getUint32$1(directoryView, offset) == CENTRAL_FILE_HEADER_SIGNATURE ||
4973
4983
  Boolean(directoryEncryptionInfo && directoryEncryptionInfo.compressedSize) ||
4974
- detectEncryptedCentralDirectory(directoryView);
4984
+ detectEncryptedCentralDirectory(directoryView));
4985
+ if (!storedPointsAtDirectory && expectedDirectoryDataOffset < 0) {
4986
+ throw new Error(ERR_BAD_FORMAT);
4987
+ }
4975
4988
  let reconcile = !storedPointsAtDirectory;
4976
4989
  if (expectedDirectoryDataOffset >= 0 && expectedDirectoryDataOffset + 4 <= reader.size) {
4977
- const expectedPointsAtDirectory = await pointsAtDirectory(reader, expectedDirectoryDataOffset);
4978
- if (storedPointsAtDirectory) {
4979
- reconcile = expectedPointsAtDirectory;
4980
- } else if (!expectedPointsAtDirectory) {
4990
+ let expectedPointsAtDirectory = await pointsAtDirectory(reader, expectedDirectoryDataOffset);
4991
+ if (!expectedPointsAtDirectory) {
4981
4992
  const signatureRecordOffset = await findDigitalSignatureRecordOffset(reader, centralDirectoryEndOffset);
4982
4993
  const signedDirectoryDataOffset = signatureRecordOffset - directoryDataLength;
4983
4994
  if (signatureRecordOffset !== UNDEFINED_VALUE && signedDirectoryDataOffset >= 0 &&
4984
4995
  await pointsAtDirectory(reader, signedDirectoryDataOffset)) {
4985
4996
  expectedDirectoryDataOffset = signedDirectoryDataOffset;
4997
+ expectedPointsAtDirectory = true;
4986
4998
  }
4987
4999
  }
5000
+ if (storedPointsAtDirectory) {
5001
+ reconcile = expectedPointsAtDirectory;
5002
+ }
4988
5003
  }
4989
- if (reconcile) {
5004
+ if (reconcile && expectedDirectoryDataOffset != directoryDataOffset) {
4990
5005
  const originalDirectoryDataOffset = directoryDataOffset;
4991
5006
  directoryDataOffset = expectedDirectoryDataOffset;
4992
5007
  directoryArray = await readUint8Array(reader, directoryDataOffset, directoryDataLength);
4993
5008
  directoryView = getDataView(directoryArray);
4994
- if (directoryDataOffset > originalDirectoryDataOffset) {
4995
- prependedDataLength += directoryDataOffset - originalDirectoryDataOffset;
5009
+ const offsetDelta = directoryDataOffset - originalDirectoryDataOffset;
5010
+ const localHeaderOffset = getFirstLocalHeaderOffset(directoryArray, directoryView);
5011
+ const localHeaderFound = localHeaderOffset !== UNDEFINED_VALUE &&
5012
+ await startsWithSignature(reader, localHeaderOffset, LOCAL_FILE_HEADER_SIGNATURE);
5013
+ const shiftedLocalHeaderFound = localHeaderOffset !== UNDEFINED_VALUE &&
5014
+ await startsWithSignature(reader, localHeaderOffset + offsetDelta, LOCAL_FILE_HEADER_SIGNATURE);
5015
+ if (offsetDelta > 0 && !(localHeaderFound && !shiftedLocalHeaderFound)) {
5016
+ prependedDataLength += offsetDelta;
4996
5017
  prependedCentralDirectory = storedPointsAtDirectory;
4997
5018
  } else {
4998
5019
  reportAmbiguity(checkAmbiguity, warnings, WARNING_MISMATCHED_CENTRAL_DIRECTORY_OFFSET);
4999
- const offsetDelta = directoryDataOffset - originalDirectoryDataOffset;
5000
- if (directoryArray.length >= CENTRAL_FILE_HEADER_LENGTH) {
5001
- const localHeaderOffset = getUint32$1(directoryView, 42);
5002
- if (!await startsWithSignature(reader, localHeaderOffset, LOCAL_FILE_HEADER_SIGNATURE) &&
5003
- await startsWithSignature(reader, localHeaderOffset + offsetDelta, LOCAL_FILE_HEADER_SIGNATURE)) {
5004
- prependedDataLength += offsetDelta;
5005
- }
5020
+ if (offsetDelta < 0 && !localHeaderFound && shiftedLocalHeaderFound) {
5021
+ prependedDataLength += offsetDelta;
5006
5022
  }
5007
5023
  }
5008
5024
  }
5009
5025
  }
5026
+ if (directoryArray.length < 4) {
5027
+ throw new Error(ERR_BAD_FORMAT);
5028
+ }
5029
+ } else if (!filesLength && directoryDataOffset < centralDirectoryEndOffset && diskNumber == lastDiskNumber) {
5030
+ prependedDataLength += centralDirectoryEndOffset - directoryDataOffset;
5031
+ directoryDataOffset = centralDirectoryEndOffset;
5010
5032
  }
5011
5033
  const expectedDirectoryDataLength = centralDirectoryEndOffset - directoryDataOffset;
5012
5034
  if (directoryDataLength != expectedDirectoryDataLength && expectedDirectoryDataLength >= 0 && diskNumber == lastDiskNumber) {
@@ -5048,8 +5070,10 @@
5048
5070
  addWarning(warnings, WARNING_WRAPPED_ENTRIES_COUNT);
5049
5071
  }
5050
5072
  }
5073
+ const entryOptions = Object.assign({}, zipReader.options, options, { [OPTION_STRICTNESS]: strictness });
5074
+ delete entryOptions[OPTION_CHECK_AMBIGUITY];
5051
5075
  for (let indexFile = 0; indexFile < filesLength; indexFile++) {
5052
- const fileEntry = new ZipEntry(reader, zipReader.options);
5076
+ const fileEntry = new ZipEntry(reader, entryOptions);
5053
5077
  if (offset + CENTRAL_FILE_HEADER_LENGTH > directoryArray.length || getUint32$1(directoryView, offset) != CENTRAL_FILE_HEADER_SIGNATURE) {
5054
5078
  if (indexFile == 0 && !decryptedDirectory && (zip64EndOfDirectoryVersion2 || detectEncryptedCentralDirectory(directoryView))) {
5055
5079
  throw new Error(ERR_ENCRYPTED_CENTRAL_DIRECTORY);
@@ -5140,13 +5164,17 @@
5140
5164
  if (malformedExtraField) {
5141
5165
  addWarning(warnings, WARNING_MALFORMED_EXTRA_FIELD, filename);
5142
5166
  }
5143
- fileEntry.offset += prependedDataLength;
5144
- const entryPosition = getDiskOffset$1(reader, fileEntry.diskNumberStart) + fileEntry.offset;
5145
- startOffset = Math.min(entryPosition, startOffset);
5146
- if (entryPosition < previousEntryPosition) {
5147
- addWarning(warnings, WARNING_UNSORTED_CENTRAL_DIRECTORY, filename);
5167
+ if (fileEntry.zip64ExtraFieldMissing && fileEntry.offset == MAX_32_BITS) {
5168
+ startOffset = 0;
5169
+ } else {
5170
+ fileEntry.offset += prependedDataLength;
5171
+ const entryPosition = getDiskOffset$1(reader, fileEntry.diskNumberStart) + fileEntry.offset;
5172
+ startOffset = Math.min(entryPosition, startOffset);
5173
+ if (entryPosition < previousEntryPosition) {
5174
+ addWarning(warnings, WARNING_UNSORTED_CENTRAL_DIRECTORY, filename);
5175
+ }
5176
+ previousEntryPosition = entryPosition;
5148
5177
  }
5149
- previousEntryPosition = entryPosition;
5150
5178
  if ((fileEntry.version & MAX_8_BITS) > MAX_KNOWN_VERSION) {
5151
5179
  addWarning(warnings, WARNING_UNKNOWN_VERSION, filename);
5152
5180
  }
@@ -5183,12 +5211,15 @@
5183
5211
  zipCrypto: fileEntry.encrypted && !fileEntry.extraFieldAES
5184
5212
  });
5185
5213
  const entry = new Entry(fileEntry);
5186
- entry.getData = (writer, options) => fileEntry.getData(writer, entry, zipReader.readRanges, options);
5214
+ if (fileEntry.zip64ExtraFieldMissing) {
5215
+ zipReader.entriesMissingZip64ExtraField.add(entry);
5216
+ }
5217
+ entry.getData = (writer, options) => fileEntry.getData(writer, entry, zipReader, options);
5187
5218
  entry.arrayBuffer = async options => {
5188
5219
  const writer = new TransformStream();
5189
5220
  const arrayBufferPromise = streamToBlob(writer.readable).then(blob => blob.arrayBuffer());
5190
5221
  arrayBufferPromise.catch(() => { });
5191
- await fileEntry.getData(writer, entry, zipReader.readRanges,
5222
+ await fileEntry.getData(writer, entry, zipReader,
5192
5223
  Object.assign({}, options, { preventClose: false }));
5193
5224
  return arrayBufferPromise;
5194
5225
  };
@@ -5396,8 +5427,9 @@
5396
5427
  });
5397
5428
  }
5398
5429
 
5399
- async getData(writer, fileEntry, readRanges, options = {}) {
5430
+ async getData(writer, fileEntry, zipReader, options = {}) {
5400
5431
  const zipEntry = this;
5432
+ const { readRanges, directoryOffset } = zipReader;
5401
5433
  if (zipEntry.zip64ExtraFieldMissing) {
5402
5434
  throw new Error(ERR_EXTRAFIELD_ZIP64_NOT_FOUND);
5403
5435
  }
@@ -5471,10 +5503,10 @@
5471
5503
  }
5472
5504
  validateLocalDirectory(zipEntry, localDirectory, rawLocalFilename, checkLocalFilename, checkLocalDirectory ? UNDEFINED_VALUE : warnings);
5473
5505
  const { lastAccessDate, creationDate, uid, gid } = localDirectory;
5474
- if (lastAccessDate) {
5506
+ if (lastAccessDate && fileEntry.lastAccessDate === UNDEFINED_VALUE) {
5475
5507
  fileEntry.lastAccessDate = lastAccessDate;
5476
5508
  }
5477
- if (creationDate) {
5509
+ if (creationDate && fileEntry.creationDate === UNDEFINED_VALUE) {
5478
5510
  fileEntry.creationDate = creationDate;
5479
5511
  }
5480
5512
  if (uid !== UNDEFINED_VALUE && fileEntry.uid === UNDEFINED_VALUE) {
@@ -5503,7 +5535,7 @@
5503
5535
  throw new Error(ERR_ENCRYPTED);
5504
5536
  }
5505
5537
  }
5506
- if (dataOffset + compressedSize > reader.size) {
5538
+ if (dataOffset + compressedSize > Math.min(reader.size, directoryOffset)) {
5507
5539
  throw new Error(ERR_ENTRY_DATA_OUT_OF_BOUNDS);
5508
5540
  }
5509
5541
  const size = compressedSize;
@@ -5569,6 +5601,7 @@
5569
5601
  extraFieldZip64: extraFieldZip64 || localDirectory.extraFieldZip64,
5570
5602
  readRanges
5571
5603
  });
5604
+ validateDataDescriptor(zipEntry, localDirectory, checkLocalDirectory ? UNDEFINED_VALUE : warnings);
5572
5605
  }
5573
5606
  let writable, abortError, aborted;
5574
5607
  try {
@@ -5588,10 +5621,7 @@
5588
5621
  writer.size += writtenSize;
5589
5622
  }
5590
5623
  } catch (error) {
5591
- const { outputSize: failedOutputSize } = workerOptions;
5592
- if (failedOutputSize !== UNDEFINED_VALUE) {
5593
- writer.size += failedOutputSize;
5594
- } else if (isErrorObject(error) && error.outputSize !== UNDEFINED_VALUE) {
5624
+ if (isErrorObject(error) && error.outputSize !== UNDEFINED_VALUE) {
5595
5625
  writer.size += error.outputSize;
5596
5626
  }
5597
5627
  if (!checkPasswordOnly || !isErrorObject(error) || error.message != ERR_ABORT_CHECK_PASSWORD) {
@@ -5619,13 +5649,7 @@
5619
5649
  }
5620
5650
 
5621
5651
  function detectEncryptedCentralDirectory(directoryView) {
5622
- const maxOffset = Math.min(directoryView.byteLength, 1024) - 3;
5623
- for (let offset = 0; offset < maxOffset; offset++) {
5624
- if (getUint32$1(directoryView, offset) == ARCHIVE_EXTRA_DATA_SIGNATURE) {
5625
- return true;
5626
- }
5627
- }
5628
- return false;
5652
+ return directoryView.byteLength >= 4 && getUint32$1(directoryView, 0) == ARCHIVE_EXTRA_DATA_SIGNATURE;
5629
5653
  }
5630
5654
 
5631
5655
  function getWrappedFilesLength(directoryView, directoryArray, offset) {
@@ -5662,6 +5686,46 @@
5662
5686
  }
5663
5687
  }
5664
5688
 
5689
+ async function findZip64EndOfDirectoryOffset(reader, endOffset) {
5690
+ const startOffset = Math.max(0, endOffset - (ZIP64_END_OF_CENTRAL_DIR_LENGTH + MAX_16_BITS));
5691
+ const tailArray = await readUint8Array(reader, startOffset, endOffset - startOffset);
5692
+ const tailView = getDataView(tailArray);
5693
+ for (let indexByte = tailArray.length - ZIP64_END_OF_CENTRAL_DIR_LENGTH; indexByte >= 0; indexByte--) {
5694
+ if (getUint32$1(tailView, indexByte) == ZIP64_END_OF_CENTRAL_DIR_SIGNATURE &&
5695
+ indexByte + 12 + Number(tailView.getBigUint64(indexByte + 4, true)) == tailArray.length) {
5696
+ return startOffset + indexByte;
5697
+ }
5698
+ }
5699
+ }
5700
+
5701
+ function getFirstLocalHeaderOffset(directoryArray, directoryView) {
5702
+ if (directoryArray.length < CENTRAL_FILE_HEADER_LENGTH) {
5703
+ return UNDEFINED_VALUE;
5704
+ }
5705
+ const localHeaderOffset = getUint32$1(directoryView, 42);
5706
+ if (localHeaderOffset != MAX_32_BITS) {
5707
+ return localHeaderOffset;
5708
+ }
5709
+ let offsetExtraField = CENTRAL_FILE_HEADER_LENGTH + getUint16$1(directoryView, 28);
5710
+ const endExtraField = Math.min(offsetExtraField + getUint16$1(directoryView, 30), directoryArray.length);
5711
+ while (offsetExtraField + 4 <= endExtraField) {
5712
+ const type = getUint16$1(directoryView, offsetExtraField);
5713
+ const size = getUint16$1(directoryView, offsetExtraField + 2);
5714
+ if (type == EXTRAFIELD_TYPE_ZIP64) {
5715
+ let offsetValue = offsetExtraField + 4;
5716
+ if (getUint32$1(directoryView, 24) == MAX_32_BITS) {
5717
+ offsetValue += 8;
5718
+ }
5719
+ if (getUint32$1(directoryView, 20) == MAX_32_BITS) {
5720
+ offsetValue += 8;
5721
+ }
5722
+ return offsetValue + 8 <= endExtraField ? getBigUint64(directoryView, offsetValue) : UNDEFINED_VALUE;
5723
+ }
5724
+ offsetExtraField += 4 + size;
5725
+ }
5726
+ return UNDEFINED_VALUE;
5727
+ }
5728
+
5665
5729
  function readDigitalSignature(signatureRecordArray) {
5666
5730
  if (signatureRecordArray.length >= 6) {
5667
5731
  const signatureRecordView = getDataView(signatureRecordArray);
@@ -5751,6 +5815,7 @@
5751
5815
  uncompressedSize: getUint32$1(dataView, offset + HEADER_OFFSET_UNCOMPRESSED_SIZE)
5752
5816
  });
5753
5817
  const extraFieldZip64 = extraField.get(EXTRAFIELD_TYPE_ZIP64);
5818
+ let extraFieldZip64Missing;
5754
5819
  if (extraFieldZip64) {
5755
5820
  if (!readExtraFieldZip64(extraFieldZip64, directory, localDirectory)) {
5756
5821
  malformedExtraField = true;
@@ -5760,7 +5825,7 @@
5760
5825
  if (localDirectory) {
5761
5826
  malformedExtraField = true;
5762
5827
  } else {
5763
- throw new Error(ERR_EXTRAFIELD_ZIP64_NOT_FOUND);
5828
+ extraFieldZip64Missing = true;
5764
5829
  }
5765
5830
  }
5766
5831
  const extraFieldUnicodePath = extraField.get(EXTRAFIELD_TYPE_UNICODE_PATH);
@@ -5818,6 +5883,9 @@
5818
5883
  if (extraFieldUSDZ) {
5819
5884
  directory.extraFieldUSDZ = extraFieldUSDZ;
5820
5885
  }
5886
+ if (extraFieldZip64Missing) {
5887
+ throw new Error(ERR_EXTRAFIELD_ZIP64_NOT_FOUND);
5888
+ }
5821
5889
  return malformedExtraField;
5822
5890
  }
5823
5891
 
@@ -6032,13 +6100,7 @@
6032
6100
  let dataDescriptorLength = 0;
6033
6101
  if (dataDescriptor) {
6034
6102
  const zip64 = Boolean(extraFieldZip64);
6035
- const dataDescriptorArray = await readUint8Array(reader, dataOffset + compressedSize, DATA_DESCRIPTOR_RECORD_ZIP_64_LENGTH + DATA_DESCRIPTOR_RECORD_SIGNATURE_LENGTH);
6036
- const dataDescriptorView = getDataView(dataDescriptorArray);
6037
- const candidates = [[zip64, true], [zip64, false], [!zip64, true], [!zip64, false]]
6038
- .map(([zip64Layout, signature]) => readDataDescriptor(dataDescriptorView, zip64Layout, signature))
6039
- .filter(candidate => candidate && candidate.compressedSize == compressedSize && candidate.uncompressedSize == uncompressedSize);
6040
- const localDataDescriptor = candidates.find(candidate => candidate.crc32 == crc32) || candidates[0] ||
6041
- readDataDescriptor(dataDescriptorView, zip64, true) || readDataDescriptor(dataDescriptorView, zip64, false);
6103
+ const localDataDescriptor = await readLocalDataDescriptor(reader, dataOffset + compressedSize, { crc32, compressedSize, uncompressedSize, zip64 });
6042
6104
  if (localDataDescriptor) {
6043
6105
  fileEntry.localDirectory.dataDescriptor = localDataDescriptor;
6044
6106
  dataDescriptorLength = getDataDescriptorLength(localDataDescriptor.zip64, localDataDescriptor.signature);
@@ -6108,6 +6170,25 @@
6108
6170
  return mergedRanges;
6109
6171
  }
6110
6172
 
6173
+ async function readLocalDataDescriptor(reader, offset, { crc32, compressedSize, uncompressedSize, zip64 }) {
6174
+ const maxLength = DATA_DESCRIPTOR_RECORD_ZIP_64_LENGTH + DATA_DESCRIPTOR_RECORD_SIGNATURE_LENGTH;
6175
+ const length = Math.min(maxLength, Math.max(0, reader.size - offset));
6176
+ const dataDescriptorArray = length ? await readUint8Array(reader, offset, length) : EMPTY_UINT8_ARRAY;
6177
+ const dataDescriptorView = getDataView(dataDescriptorArray);
6178
+ const candidates = [[zip64, true], [zip64, false], [!zip64, true], [!zip64, false]]
6179
+ .map(([zip64Layout, signature]) => readDataDescriptor(dataDescriptorView, zip64Layout, signature))
6180
+ .filter(candidate => candidate && candidate.compressedSize == compressedSize && candidate.uncompressedSize == uncompressedSize);
6181
+ return candidates.find(candidate => candidate.crc32 == crc32) || candidates[0] ||
6182
+ readDataDescriptor(dataDescriptorView, zip64, true) || readDataDescriptor(dataDescriptorView, zip64, false);
6183
+ }
6184
+
6185
+ async function getEntryDataDescriptorLength(reader, offset, { crc32, compressedSize, uncompressedSize, extraFieldZip64 }) {
6186
+ const dataDescriptor = await readLocalDataDescriptor(reader, offset, { crc32, compressedSize, uncompressedSize, zip64: Boolean(extraFieldZip64) });
6187
+ if (dataDescriptor && dataDescriptor.compressedSize == compressedSize && dataDescriptor.uncompressedSize == uncompressedSize) {
6188
+ return getDataDescriptorLength(dataDescriptor.zip64, dataDescriptor.signature);
6189
+ }
6190
+ }
6191
+
6111
6192
  function readDataDescriptor(dataDescriptorView, zip64, signature) {
6112
6193
  const offset = signature ? DATA_DESCRIPTOR_RECORD_SIGNATURE_LENGTH : 0;
6113
6194
  if (dataDescriptorView.byteLength < getDataDescriptorLength(zip64, signature) ||
@@ -6367,6 +6448,18 @@
6367
6448
  }
6368
6449
  }
6369
6450
 
6451
+ function validateDataDescriptor(zipEntry, localDirectory, warnings) {
6452
+ const { dataDescriptor } = localDirectory;
6453
+ const maskedLocalDirectory = zipEntry.decryptedDirectory &&
6454
+ (localDirectory.rawBitFlag & BITFLAG_MASKED_LOCAL_HEADERS) == BITFLAG_MASKED_LOCAL_HEADERS;
6455
+ if (dataDescriptor && !maskedLocalDirectory &&
6456
+ ((zipEntry.crc32 !== UNDEFINED_VALUE && dataDescriptor.crc32 != zipEntry.crc32) ||
6457
+ dataDescriptor.compressedSize != zipEntry.compressedSize ||
6458
+ dataDescriptor.uncompressedSize != zipEntry.uncompressedSize)) {
6459
+ reportAmbiguity(!warnings, warnings, WARNING_MISMATCHED_LOCAL_FILE_HEADER_CRC32_OR_SIZES);
6460
+ }
6461
+ }
6462
+
6370
6463
  function reportAmbiguity(reject, warnings, reason) {
6371
6464
  if (reject) {
6372
6465
  throwAmbiguousArchive(reason);
@@ -6469,6 +6562,7 @@
6469
6562
  WARNING_WRAPPED_ENTRIES_COUNT: WARNING_WRAPPED_ENTRIES_COUNT,
6470
6563
  ZipReader: ZipReader,
6471
6564
  ZipReaderStream: ZipReaderStream,
6565
+ getEntryDataDescriptorLength: getEntryDataDescriptorLength,
6472
6566
  isZipFile: isZipFile
6473
6567
  });
6474
6568
 
@@ -6592,136 +6686,7 @@
6592
6686
  }
6593
6687
 
6594
6688
  appendZip(reader, options = {}) {
6595
- return watchPromiseError(this, this.appendZipEntries(reader, options));
6596
- }
6597
-
6598
- async appendZipEntries(reader, options = {}) {
6599
- const zipWriter = this;
6600
- const { pendingAddFileCalls, filenames, fileEntries } = zipWriter;
6601
- const filter = checkFunctionOption(options.filter);
6602
- while (pendingAddFileCalls.size) {
6603
- await Promise.allSettled(Array.from(pendingAddFileCalls));
6604
- }
6605
- let resolveAppendZip;
6606
- const promiseAppendZip = new Promise(resolve => resolveAppendZip = resolve);
6607
- pendingAddFileCalls.add(promiseAppendZip);
6608
- const appendedFilenames = [];
6609
- let releaseLockWriter;
6610
- try {
6611
- reader = new GenericReader(reader);
6612
- await initStream(reader);
6613
- if (reader.size === UNDEFINED_VALUE || !reader.readUint8Array) {
6614
- reader = new BlobReader(await streamToBlob(reader.readable));
6615
- await initStream(reader);
6616
- }
6617
- const { ZipReader } = await Promise.resolve().then(function () { return zipReader; });
6618
- const zipReader$1 = new ZipReader(reader);
6619
- const entries = await zipReader$1.getEntries();
6620
- const keptEntries = [];
6621
- for (const entry of entries) {
6622
- if (!filter || await filter(entry)) {
6623
- keptEntries.push(entry);
6624
- }
6625
- }
6626
- await zipReader$1.close();
6627
- await initStream(zipWriter.writer);
6628
- const { directoryOffset } = zipReader$1;
6629
- keptEntries.forEach(({ filename }) => {
6630
- if (filenames.has(filename)) {
6631
- throw new Error(ERR_DUPLICATED_NAME);
6632
- }
6633
- filenames.add(filename);
6634
- appendedFilenames.push(filename);
6635
- });
6636
- zipWriter.writerLocked = true;
6637
- const { lockWriter } = zipWriter;
6638
- zipWriter.lockWriter = new Promise(resolve => releaseLockWriter = () => {
6639
- zipWriter.writerLocked = false;
6640
- resolve();
6641
- });
6642
- await lockWriter;
6643
- if (zipWriter.addSplitZipSignature) {
6644
- delete zipWriter.addSplitZipSignature;
6645
- if (!await startsWithSplitZipSignature(reader)) {
6646
- await writeData(zipWriter.writer, getSplitZipSignatureArray());
6647
- zipWriter.offset += SPLIT_ZIP_FILE_SIGNATURE_LENGTH;
6648
- }
6649
- }
6650
- const entryPositions = await copyZipData(zipWriter, reader, entries, keptEntries, directoryOffset, Boolean(filter));
6651
- keptEntries.forEach(entry => {
6652
- const {
6653
- version,
6654
- rawLastModDate,
6655
- rawFilename,
6656
- bitFlag,
6657
- encrypted,
6658
- uncompressedSize,
6659
- compressedSize,
6660
- extraFieldZip64
6661
- } = entry;
6662
- let {
6663
- compressionMethod,
6664
- rawExtraField,
6665
- } = entry;
6666
- const { level, languageEncodingFlag, dataDescriptor } = bitFlag;
6667
- rawExtraField = removeExtraFieldZip64(rawExtraField || EMPTY_UINT8_ARRAY);
6668
- if (entry.extraFieldAES) {
6669
- compressionMethod = COMPRESSION_METHOD_AES;
6670
- }
6671
- const extraFieldLength = getLength(rawExtraField);
6672
- const zip64UncompressedSize = Boolean(extraFieldZip64) && extraFieldZip64.uncompressedSize !== UNDEFINED_VALUE;
6673
- const zip64CompressedSize = Boolean(extraFieldZip64) && extraFieldZip64.compressedSize !== UNDEFINED_VALUE;
6674
- const bitFlagValue = (getBitFlag(level, languageEncodingFlag, dataDescriptor, encrypted, compressionMethod) & ~BITFLAG_LEVEL) | (level << 1);
6675
- const {
6676
- headerArray,
6677
- headerView
6678
- } = getHeaderArrayData({
6679
- version,
6680
- bitFlag: bitFlagValue,
6681
- compressionMethod,
6682
- uncompressedSize,
6683
- compressedSize,
6684
- rawLastModDate,
6685
- rawFilename,
6686
- zip64CompressedSize,
6687
- zip64UncompressedSize,
6688
- extraFieldLength
6689
- });
6690
- const { crc32 } = entry;
6691
- if (crc32 !== UNDEFINED_VALUE) {
6692
- setUint32(headerView, HEADER_OFFSET_SIGNATURE, crc32);
6693
- }
6694
- const { offset, diskNumberStart } = entryPositions.get(entry);
6695
- Object.assign(entry, {
6696
- zip64Enabled: true,
6697
- zip64UncompressedSize,
6698
- zip64CompressedSize,
6699
- offset,
6700
- diskNumberStart,
6701
- zip64DiskNumberStart: false,
6702
- rawExtraFieldZip64: EMPTY_UINT8_ARRAY,
6703
- rawExtraFieldAES: EMPTY_UINT8_ARRAY,
6704
- rawExtraFieldExtendedTimestamp: EMPTY_UINT8_ARRAY,
6705
- rawExtraFieldNTFS: EMPTY_UINT8_ARRAY,
6706
- rawExtraFieldUnix: EMPTY_UINT8_ARRAY,
6707
- rawCentralExtraFieldUnix: EMPTY_UINT8_ARRAY,
6708
- rawExtraField,
6709
- rawCentralExtraField: EMPTY_UINT8_ARRAY,
6710
- headerArray,
6711
- headerView
6712
- });
6713
- fileEntries.set(entry.filename, entry);
6714
- });
6715
- } catch (error) {
6716
- appendedFilenames.forEach(filename => filenames.delete(filename));
6717
- throw error;
6718
- } finally {
6719
- resolveAppendZip();
6720
- pendingAddFileCalls.delete(promiseAppendZip);
6721
- if (releaseLockWriter) {
6722
- releaseLockWriter();
6723
- }
6724
- }
6689
+ return watchPromiseError(this, appendZipEntries(this, reader, options));
6725
6690
  }
6726
6691
 
6727
6692
  add(name = "", reader, options = {}) {
@@ -6883,11 +6848,149 @@
6883
6848
  return watchedPromise;
6884
6849
  }
6885
6850
 
6851
+ async function appendZipEntries(zipWriter, reader, options = {}) {
6852
+ const { pendingAddFileCalls, filenames, fileEntries } = zipWriter;
6853
+ const filter = checkFunctionOption(options.filter);
6854
+ const readerOptions = checkReaderOptionsObject(options.readerOptions);
6855
+ while (pendingAddFileCalls.size) {
6856
+ await Promise.allSettled(Array.from(pendingAddFileCalls));
6857
+ }
6858
+ let resolveAppendZip;
6859
+ const promiseAppendZip = new Promise(resolve => resolveAppendZip = resolve);
6860
+ pendingAddFileCalls.add(promiseAppendZip);
6861
+ const appendedFilenames = [];
6862
+ let releaseLockWriter;
6863
+ try {
6864
+ reader = new GenericReader(reader);
6865
+ await initStream(reader);
6866
+ if (reader.size === UNDEFINED_VALUE || !reader.readUint8Array) {
6867
+ reader = new BlobReader(await streamToBlob(reader.readable));
6868
+ await initStream(reader);
6869
+ }
6870
+ const { ZipReader, getEntryDataDescriptorLength } = await Promise.resolve().then(function () { return zipReader; });
6871
+ const zipReader$1 = new ZipReader(reader, readerOptions);
6872
+ const keptEntries = [];
6873
+ let entries;
6874
+ try {
6875
+ entries = await zipReader$1.getEntries();
6876
+ for (const entry of entries) {
6877
+ if (!filter || await filter(entry, getExistingEntry(fileEntries, entry.filename))) {
6878
+ keptEntries.push(entry);
6879
+ }
6880
+ }
6881
+ } finally {
6882
+ await zipReader$1.close();
6883
+ }
6884
+ await initStream(zipWriter.writer);
6885
+ const { directoryOffset, entriesMissingZip64ExtraField } = zipReader$1;
6886
+ keptEntries.forEach(entry => {
6887
+ const { filename } = entry;
6888
+ if (entriesMissingZip64ExtraField.has(entry)) {
6889
+ throw new Error(ERR_EXTRAFIELD_ZIP64_NOT_FOUND);
6890
+ }
6891
+ if (filenames.has(filename)) {
6892
+ throw new Error(ERR_DUPLICATED_NAME);
6893
+ }
6894
+ filenames.add(filename);
6895
+ appendedFilenames.push(filename);
6896
+ });
6897
+ zipWriter.writerLocked = true;
6898
+ const { lockWriter } = zipWriter;
6899
+ zipWriter.lockWriter = new Promise(resolve => releaseLockWriter = () => {
6900
+ zipWriter.writerLocked = false;
6901
+ resolve();
6902
+ });
6903
+ await lockWriter;
6904
+ if (zipWriter.addSplitZipSignature) {
6905
+ delete zipWriter.addSplitZipSignature;
6906
+ if (filter || !await startsWithSplitZipSignature(reader)) {
6907
+ await writeData(zipWriter.writer, getSplitZipSignatureArray());
6908
+ zipWriter.offset += SPLIT_ZIP_FILE_SIGNATURE_LENGTH;
6909
+ }
6910
+ }
6911
+ const entryPositions = await copyZipData(zipWriter, reader, entries, keptEntries, directoryOffset, Boolean(filter), getEntryDataDescriptorLength);
6912
+ keptEntries.forEach(entry => {
6913
+ const {
6914
+ version,
6915
+ rawLastModDate,
6916
+ rawFilename,
6917
+ rawBitFlag,
6918
+ uncompressedSize,
6919
+ compressedSize,
6920
+ extraFieldZip64
6921
+ } = entry;
6922
+ let {
6923
+ compressionMethod,
6924
+ rawExtraField,
6925
+ } = entry;
6926
+ rawExtraField = removeExtraFieldZip64(rawExtraField || EMPTY_UINT8_ARRAY);
6927
+ if (entry.extraFieldAES) {
6928
+ compressionMethod = COMPRESSION_METHOD_AES;
6929
+ }
6930
+ const extraFieldLength = getLength(rawExtraField);
6931
+ const zip64UncompressedSize = Boolean(extraFieldZip64) && extraFieldZip64.uncompressedSize !== UNDEFINED_VALUE;
6932
+ const zip64CompressedSize = Boolean(extraFieldZip64) && extraFieldZip64.compressedSize !== UNDEFINED_VALUE;
6933
+ const {
6934
+ headerArray,
6935
+ headerView
6936
+ } = getHeaderArrayData({
6937
+ version,
6938
+ bitFlag: rawBitFlag,
6939
+ compressionMethod,
6940
+ uncompressedSize,
6941
+ compressedSize,
6942
+ rawLastModDate,
6943
+ rawFilename,
6944
+ zip64CompressedSize,
6945
+ zip64UncompressedSize,
6946
+ extraFieldLength
6947
+ });
6948
+ const { crc32 } = entry;
6949
+ if (crc32 !== UNDEFINED_VALUE) {
6950
+ setUint32(headerView, HEADER_OFFSET_SIGNATURE, crc32);
6951
+ }
6952
+ const { offset, diskNumberStart } = entryPositions.get(entry);
6953
+ fileEntries.set(entry.filename, Object.assign({}, entry, {
6954
+ zip64Enabled: true,
6955
+ zip64UncompressedSize,
6956
+ zip64CompressedSize,
6957
+ offset,
6958
+ diskNumberStart,
6959
+ zip64DiskNumberStart: false,
6960
+ rawExtraFieldZip64: EMPTY_UINT8_ARRAY,
6961
+ rawExtraFieldAES: EMPTY_UINT8_ARRAY,
6962
+ rawExtraFieldExtendedTimestamp: EMPTY_UINT8_ARRAY,
6963
+ rawExtraFieldNTFS: EMPTY_UINT8_ARRAY,
6964
+ rawExtraFieldUnix: EMPTY_UINT8_ARRAY,
6965
+ rawCentralExtraFieldUnix: EMPTY_UINT8_ARRAY,
6966
+ rawExtraField,
6967
+ rawCentralExtraField: EMPTY_UINT8_ARRAY,
6968
+ headerArray,
6969
+ headerView
6970
+ }));
6971
+ });
6972
+ } catch (error) {
6973
+ appendedFilenames.forEach(filename => filenames.delete(filename));
6974
+ throw error;
6975
+ } finally {
6976
+ resolveAppendZip();
6977
+ pendingAddFileCalls.delete(promiseAppendZip);
6978
+ if (releaseLockWriter) {
6979
+ releaseLockWriter();
6980
+ }
6981
+ }
6982
+ }
6983
+
6984
+ function getExistingEntry(fileEntries, filename) {
6985
+ const fileEntry = fileEntries.get(filename);
6986
+ return fileEntry ? new Entry(fileEntry) : UNDEFINED_VALUE;
6987
+ }
6988
+
6886
6989
  async function prependZipEntries(zipWriter, reader) {
6887
6990
  if (zipWriter.filenames.size) {
6888
6991
  throw new Error(ERR_ZIP_NOT_EMPTY);
6889
6992
  }
6890
- await zipWriter.appendZipEntries(reader);
6993
+ await appendZipEntries(zipWriter, reader);
6891
6994
  }
6892
6995
 
6893
6996
  async function addFileEntry(zipWriter, name, reader, options) {
@@ -8561,7 +8664,7 @@
8561
8664
  return rawExtraField;
8562
8665
  }
8563
8666
 
8564
- async function copyZipData(zipWriter, reader, entries, keptEntries, directoryOffset, compact) {
8667
+ async function copyZipData(zipWriter, reader, entries, keptEntries, directoryOffset, compact, getEntryDataDescriptorLength) {
8565
8668
  const { writer } = zipWriter;
8566
8669
  const entryPositions = new Map();
8567
8670
  if (writer.closeDisk || compact) {
@@ -8569,6 +8672,27 @@
8569
8672
  getSourceOffset(reader, firstEntry) - getSourceOffset(reader, secondEntry));
8570
8673
  const regionEnds = getRegionEnds(reader, sortedEntries, directoryOffset);
8571
8674
  const keptEntrySet = new Set(keptEntries);
8675
+ const localHeaderLengths = new Map();
8676
+ for (let indexEntry = 0; indexEntry < sortedEntries.length; indexEntry++) {
8677
+ const entry = sortedEntries[indexEntry];
8678
+ if (keptEntrySet.has(entry)) {
8679
+ const sourceOffset = getSourceOffset(reader, entry);
8680
+ const localHeaderLength = await getLocalHeaderLength(reader, sourceOffset);
8681
+ if (localHeaderLength === UNDEFINED_VALUE) {
8682
+ throw new Error(ERR_LOCAL_FILE_HEADER_NOT_FOUND);
8683
+ }
8684
+ let entryEnd = sourceOffset + localHeaderLength + entry.compressedSize;
8685
+ if (entry.bitFlag.dataDescriptor) {
8686
+ const dataDescriptorLength = await getEntryDataDescriptorLength(reader, entryEnd, entry);
8687
+ entryEnd = dataDescriptorLength === UNDEFINED_VALUE ? Math.max(entryEnd, regionEnds[indexEntry]) : entryEnd + dataDescriptorLength;
8688
+ }
8689
+ if (entryEnd > regionEnds[indexEntry]) {
8690
+ throw new Error(ERR_OVERLAPPING_ENTRY);
8691
+ }
8692
+ regionEnds[indexEntry] = entryEnd;
8693
+ localHeaderLengths.set(entry, localHeaderLength);
8694
+ }
8695
+ }
8572
8696
  let copiedOffset = 0;
8573
8697
  let lastPosition;
8574
8698
  for (let indexEntry = 0; indexEntry < sortedEntries.length; indexEntry++) {
@@ -8581,7 +8705,7 @@
8581
8705
  if (!compact) {
8582
8706
  await copyData(zipWriter, reader, copiedOffset, sourceOffset - copiedOffset);
8583
8707
  }
8584
- if (writer.closeDisk && exceedsAvailableSize(writer, await getLocalHeaderLength(reader, sourceOffset))) {
8708
+ if (writer.closeDisk && exceedsAvailableSize(writer, localHeaderLengths.get(entry))) {
8585
8709
  await writer.closeDisk();
8586
8710
  }
8587
8711
  lastPosition = {
@@ -8615,7 +8739,7 @@
8615
8739
  const sourceOffset = getSourceOffset(reader, sortedEntries[indexEntry]);
8616
8740
  const nextEntry = sortedEntries[indexEntry + 1];
8617
8741
  if (nextEntry && getSourceOffset(reader, nextEntry) > sourceOffset) {
8618
- regionEnd = getSourceOffset(reader, nextEntry);
8742
+ regionEnd = Math.min(getSourceOffset(reader, nextEntry), directoryOffset);
8619
8743
  }
8620
8744
  regionEnds[indexEntry] = regionEnd;
8621
8745
  }
@@ -8629,11 +8753,13 @@
8629
8753
  try {
8630
8754
  await flushBufferedData(createReadable(reader, { offset, size }), writer, UNDEFINED_VALUE, chunkLength => copiedLength += chunkLength);
8631
8755
  } catch (error) {
8632
- zipWriter.hasCorruptedEntries = true;
8633
- try {
8634
- error.corruptedEntry = true;
8635
- } catch {
8636
- // ignored
8756
+ if (copiedLength) {
8757
+ zipWriter.hasCorruptedEntries = true;
8758
+ try {
8759
+ error.corruptedEntry = true;
8760
+ } catch {
8761
+ // ignored
8762
+ }
8637
8763
  }
8638
8764
  throw error;
8639
8765
  } finally {
@@ -8644,11 +8770,16 @@
8644
8770
  }
8645
8771
 
8646
8772
  async function getLocalHeaderLength(reader, offset) {
8647
- const headerArray = await readUint8Array(reader, offset, HEADER_SIZE);
8773
+ const headerArray = offset >= 0 && offset + HEADER_SIZE <= reader.size ?
8774
+ await readUint8Array(reader, offset, HEADER_SIZE) :
8775
+ EMPTY_UINT8_ARRAY;
8648
8776
  if (getLength(headerArray) < HEADER_SIZE) {
8649
- return HEADER_SIZE;
8777
+ return UNDEFINED_VALUE;
8650
8778
  }
8651
8779
  const headerView = getDataView(headerArray);
8780
+ if (getUint32(headerView, 0) != LOCAL_FILE_HEADER_SIGNATURE) {
8781
+ return UNDEFINED_VALUE;
8782
+ }
8652
8783
  return HEADER_SIZE +
8653
8784
  getUint16(headerView, HEADER_OFFSET_FILENAME_LENGTH + LOCAL_HEADER_COMMON_OFFSET) +
8654
8785
  getUint16(headerView, HEADER_OFFSET_EXTRAFIELD_LENGTH + LOCAL_HEADER_COMMON_OFFSET);
@@ -8999,7 +9130,7 @@
8999
9130
  EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
9000
9131
  */
9001
9132
 
9002
- const VERSION = "2.20.0";
9133
+ const VERSION = "2.22.0";
9003
9134
 
9004
9135
  /*
9005
9136
  Copyright (c) 2025 Gildas Lormeau. All rights reserved.
@@ -9497,6 +9628,7 @@
9497
9628
  exports.ERR_INVALID_PASSWORD_TYPE = ERR_INVALID_PASSWORD_TYPE;
9498
9629
  exports.ERR_INVALID_PASS_THROUGH_VALUE = ERR_INVALID_PASS_THROUGH_VALUE;
9499
9630
  exports.ERR_INVALID_READER = ERR_INVALID_READER;
9631
+ exports.ERR_INVALID_READER_OPTIONS = ERR_INVALID_READER_OPTIONS;
9500
9632
  exports.ERR_INVALID_SIGNAL = ERR_INVALID_SIGNAL;
9501
9633
  exports.ERR_INVALID_SIGNATURE_DATA = ERR_INVALID_SIGNATURE_DATA;
9502
9634
  exports.ERR_INVALID_STRICTNESS = ERR_INVALID_STRICTNESS;