@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.
@@ -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",
@@ -4757,12 +4767,9 @@
4757
4767
  const ERR_EOCDR_NOT_FOUND = "End of central directory not found";
4758
4768
  const ERR_EOCDR_LOCATOR_ZIP64_NOT_FOUND = "End of Zip64 central directory locator not found";
4759
4769
  const ERR_CENTRAL_DIRECTORY_NOT_FOUND = "Central directory header not found";
4760
- const ERR_LOCAL_FILE_HEADER_NOT_FOUND = "Local file header not found";
4761
- const ERR_EXTRAFIELD_ZIP64_NOT_FOUND = "Zip64 extra field not found";
4762
4770
  const ERR_ENCRYPTED = "File contains encrypted entry";
4763
4771
  const ERR_UNSUPPORTED_ENCRYPTION = "Encryption method not supported";
4764
4772
  const ERR_SPLIT_ZIP_FILE = "Split zip file";
4765
- const ERR_OVERLAPPING_ENTRY = "Overlapping entry found";
4766
4773
  const ERR_ENTRY_DATA_OUT_OF_BOUNDS = "Entry data out of bounds";
4767
4774
  const ERR_AMBIGUOUS_ARCHIVE = "Ambiguous archive";
4768
4775
  const ERR_ENCRYPTED_CENTRAL_DIRECTORY = "Encrypted central directory is not supported";
@@ -4826,8 +4833,9 @@
4826
4833
  constructor(reader, options = {}) {
4827
4834
  Object.assign(this, {
4828
4835
  reader: new GenericReader(reader),
4829
- options,
4830
- readRanges: { indexes: new Set(), sortedRanges: [], pendingRanges: [] }
4836
+ options: options || {},
4837
+ readRanges: { indexes: new Set(), sortedRanges: [], pendingRanges: [] },
4838
+ entriesMissingZip64ExtraField: new WeakSet()
4831
4839
  });
4832
4840
  }
4833
4841
 
@@ -4898,16 +4906,22 @@
4898
4906
  directoryDataOffset = getDiskOffset$1(reader, getUint32$1(endOfDirectoryLocatorView, 4)) + getBigUint64(endOfDirectoryLocatorView, 8);
4899
4907
  let endOfDirectoryArray = await readUint8Array(reader, directoryDataOffset, ZIP64_END_OF_CENTRAL_DIR_LENGTH);
4900
4908
  let endOfDirectoryView = getDataView(endOfDirectoryArray);
4901
- const expectedDirectoryDataOffset = endOfDirectoryInfo.offset - ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH - ZIP64_END_OF_CENTRAL_DIR_LENGTH;
4902
- if ((endOfDirectoryArray.length < ZIP64_END_OF_CENTRAL_DIR_LENGTH || getUint32$1(endOfDirectoryView, 0) != ZIP64_END_OF_CENTRAL_DIR_SIGNATURE) &&
4903
- directoryDataOffset != expectedDirectoryDataOffset && expectedDirectoryDataOffset >= 0) {
4904
- const originalDirectoryDataOffset = directoryDataOffset;
4905
- directoryDataOffset = expectedDirectoryDataOffset;
4906
- if (directoryDataOffset > originalDirectoryDataOffset) {
4907
- prependedDataLength = directoryDataOffset - originalDirectoryDataOffset;
4909
+ if (endOfDirectoryArray.length < ZIP64_END_OF_CENTRAL_DIR_LENGTH || getUint32$1(endOfDirectoryView, 0) != ZIP64_END_OF_CENTRAL_DIR_SIGNATURE) {
4910
+ const locatorOffset = endOfDirectoryInfo.offset - ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH;
4911
+ let expectedDirectoryDataOffset = locatorOffset - ZIP64_END_OF_CENTRAL_DIR_LENGTH;
4912
+ if (!await startsWithSignature(reader, expectedDirectoryDataOffset, ZIP64_END_OF_CENTRAL_DIR_SIGNATURE)) {
4913
+ expectedDirectoryDataOffset = await findZip64EndOfDirectoryOffset(reader, locatorOffset);
4914
+ }
4915
+ if (expectedDirectoryDataOffset !== UNDEFINED_VALUE && expectedDirectoryDataOffset >= 0 &&
4916
+ directoryDataOffset != expectedDirectoryDataOffset) {
4917
+ const originalDirectoryDataOffset = directoryDataOffset;
4918
+ directoryDataOffset = expectedDirectoryDataOffset;
4919
+ if (directoryDataOffset > originalDirectoryDataOffset) {
4920
+ prependedDataLength = directoryDataOffset - originalDirectoryDataOffset;
4921
+ }
4922
+ endOfDirectoryArray = await readUint8Array(reader, directoryDataOffset, ZIP64_END_OF_CENTRAL_DIR_LENGTH);
4923
+ endOfDirectoryView = getDataView(endOfDirectoryArray);
4908
4924
  }
4909
- endOfDirectoryArray = await readUint8Array(reader, directoryDataOffset, ZIP64_END_OF_CENTRAL_DIR_LENGTH);
4910
- endOfDirectoryView = getDataView(endOfDirectoryArray);
4911
4925
  }
4912
4926
  if (endOfDirectoryArray.length < ZIP64_END_OF_CENTRAL_DIR_LENGTH || getUint32$1(endOfDirectoryView, 0) != ZIP64_END_OF_CENTRAL_DIR_SIGNATURE) {
4913
4927
  throw new Error(ERR_EOCDR_LOCATOR_ZIP64_NOT_FOUND);
@@ -4952,10 +4966,6 @@
4952
4966
  let declaredDirectoryDataLength = directoryDataLength;
4953
4967
  const centralDirectoryEndOffset = endOfDirectoryInfo.offset -
4954
4968
  (zip64EndOfDirectory ? zip64EndOfDirectoryLength + ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH : 0);
4955
- if (directoryDataOffset >= reader.size) {
4956
- prependedDataLength = reader.size - directoryDataOffset - directoryDataLength - END_OF_CENTRAL_DIR_LENGTH;
4957
- directoryDataOffset = reader.size - directoryDataLength - END_OF_CENTRAL_DIR_LENGTH;
4958
- }
4959
4969
  if (expectedLastDiskNumber != lastDiskNumber) {
4960
4970
  throw new Error(ERR_SPLIT_ZIP_FILE);
4961
4971
  }
@@ -4963,52 +4973,64 @@
4963
4973
  throw new Error(ERR_BAD_FORMAT);
4964
4974
  }
4965
4975
  let offset = 0;
4966
- let directoryArray = await readUint8Array(reader, directoryDataOffset, directoryDataLength);
4976
+ let directoryArray = directoryDataOffset < reader.size ?
4977
+ await readUint8Array(reader, directoryDataOffset, directoryDataLength) :
4978
+ EMPTY_UINT8_ARRAY;
4967
4979
  let directoryView = getDataView(directoryArray);
4968
4980
  if (directoryDataLength) {
4969
- if (directoryArray.length < 4) {
4970
- throw new Error(ERR_BAD_FORMAT);
4971
- }
4972
4981
  let expectedDirectoryDataOffset = centralDirectoryEndOffset - directoryDataLength;
4973
4982
  if (directoryDataOffset != expectedDirectoryDataOffset && diskNumber == lastDiskNumber) {
4974
- const storedPointsAtDirectory = getUint32$1(directoryView, offset) == CENTRAL_FILE_HEADER_SIGNATURE ||
4983
+ const storedPointsAtDirectory = directoryArray.length >= 4 && (
4984
+ getUint32$1(directoryView, offset) == CENTRAL_FILE_HEADER_SIGNATURE ||
4975
4985
  Boolean(directoryEncryptionInfo && directoryEncryptionInfo.compressedSize) ||
4976
- detectEncryptedCentralDirectory(directoryView);
4986
+ detectEncryptedCentralDirectory(directoryView));
4987
+ if (!storedPointsAtDirectory && expectedDirectoryDataOffset < 0) {
4988
+ throw new Error(ERR_BAD_FORMAT);
4989
+ }
4977
4990
  let reconcile = !storedPointsAtDirectory;
4978
4991
  if (expectedDirectoryDataOffset >= 0 && expectedDirectoryDataOffset + 4 <= reader.size) {
4979
- const expectedPointsAtDirectory = await pointsAtDirectory(reader, expectedDirectoryDataOffset);
4980
- if (storedPointsAtDirectory) {
4981
- reconcile = expectedPointsAtDirectory;
4982
- } else if (!expectedPointsAtDirectory) {
4992
+ let expectedPointsAtDirectory = await pointsAtDirectory(reader, expectedDirectoryDataOffset);
4993
+ if (!expectedPointsAtDirectory) {
4983
4994
  const signatureRecordOffset = await findDigitalSignatureRecordOffset(reader, centralDirectoryEndOffset);
4984
4995
  const signedDirectoryDataOffset = signatureRecordOffset - directoryDataLength;
4985
4996
  if (signatureRecordOffset !== UNDEFINED_VALUE && signedDirectoryDataOffset >= 0 &&
4986
4997
  await pointsAtDirectory(reader, signedDirectoryDataOffset)) {
4987
4998
  expectedDirectoryDataOffset = signedDirectoryDataOffset;
4999
+ expectedPointsAtDirectory = true;
4988
5000
  }
4989
5001
  }
5002
+ if (storedPointsAtDirectory) {
5003
+ reconcile = expectedPointsAtDirectory;
5004
+ }
4990
5005
  }
4991
- if (reconcile) {
5006
+ if (reconcile && expectedDirectoryDataOffset != directoryDataOffset) {
4992
5007
  const originalDirectoryDataOffset = directoryDataOffset;
4993
5008
  directoryDataOffset = expectedDirectoryDataOffset;
4994
5009
  directoryArray = await readUint8Array(reader, directoryDataOffset, directoryDataLength);
4995
5010
  directoryView = getDataView(directoryArray);
4996
- if (directoryDataOffset > originalDirectoryDataOffset) {
4997
- prependedDataLength += directoryDataOffset - originalDirectoryDataOffset;
5011
+ const offsetDelta = directoryDataOffset - originalDirectoryDataOffset;
5012
+ const localHeaderOffset = getFirstLocalHeaderOffset(directoryArray, directoryView);
5013
+ const localHeaderFound = localHeaderOffset !== UNDEFINED_VALUE &&
5014
+ await startsWithSignature(reader, localHeaderOffset, LOCAL_FILE_HEADER_SIGNATURE);
5015
+ const shiftedLocalHeaderFound = localHeaderOffset !== UNDEFINED_VALUE &&
5016
+ await startsWithSignature(reader, localHeaderOffset + offsetDelta, LOCAL_FILE_HEADER_SIGNATURE);
5017
+ if (offsetDelta > 0 && !(localHeaderFound && !shiftedLocalHeaderFound)) {
5018
+ prependedDataLength += offsetDelta;
4998
5019
  prependedCentralDirectory = storedPointsAtDirectory;
4999
5020
  } else {
5000
5021
  reportAmbiguity(checkAmbiguity, warnings, WARNING_MISMATCHED_CENTRAL_DIRECTORY_OFFSET);
5001
- const offsetDelta = directoryDataOffset - originalDirectoryDataOffset;
5002
- if (directoryArray.length >= CENTRAL_FILE_HEADER_LENGTH) {
5003
- const localHeaderOffset = getUint32$1(directoryView, 42);
5004
- if (!await startsWithSignature(reader, localHeaderOffset, LOCAL_FILE_HEADER_SIGNATURE) &&
5005
- await startsWithSignature(reader, localHeaderOffset + offsetDelta, LOCAL_FILE_HEADER_SIGNATURE)) {
5006
- prependedDataLength += offsetDelta;
5007
- }
5022
+ if (offsetDelta < 0 && !localHeaderFound && shiftedLocalHeaderFound) {
5023
+ prependedDataLength += offsetDelta;
5008
5024
  }
5009
5025
  }
5010
5026
  }
5011
5027
  }
5028
+ if (directoryArray.length < 4) {
5029
+ throw new Error(ERR_BAD_FORMAT);
5030
+ }
5031
+ } else if (!filesLength && directoryDataOffset < centralDirectoryEndOffset && diskNumber == lastDiskNumber) {
5032
+ prependedDataLength += centralDirectoryEndOffset - directoryDataOffset;
5033
+ directoryDataOffset = centralDirectoryEndOffset;
5012
5034
  }
5013
5035
  const expectedDirectoryDataLength = centralDirectoryEndOffset - directoryDataOffset;
5014
5036
  if (directoryDataLength != expectedDirectoryDataLength && expectedDirectoryDataLength >= 0 && diskNumber == lastDiskNumber) {
@@ -5050,8 +5072,10 @@
5050
5072
  addWarning(warnings, WARNING_WRAPPED_ENTRIES_COUNT);
5051
5073
  }
5052
5074
  }
5075
+ const entryOptions = Object.assign({}, zipReader.options, options, { [OPTION_STRICTNESS]: strictness });
5076
+ delete entryOptions[OPTION_CHECK_AMBIGUITY];
5053
5077
  for (let indexFile = 0; indexFile < filesLength; indexFile++) {
5054
- const fileEntry = new ZipEntry(reader, zipReader.options);
5078
+ const fileEntry = new ZipEntry(reader, entryOptions);
5055
5079
  if (offset + CENTRAL_FILE_HEADER_LENGTH > directoryArray.length || getUint32$1(directoryView, offset) != CENTRAL_FILE_HEADER_SIGNATURE) {
5056
5080
  if (indexFile == 0 && !decryptedDirectory && (zip64EndOfDirectoryVersion2 || detectEncryptedCentralDirectory(directoryView))) {
5057
5081
  throw new Error(ERR_ENCRYPTED_CENTRAL_DIRECTORY);
@@ -5142,13 +5166,17 @@
5142
5166
  if (malformedExtraField) {
5143
5167
  addWarning(warnings, WARNING_MALFORMED_EXTRA_FIELD, filename);
5144
5168
  }
5145
- fileEntry.offset += prependedDataLength;
5146
- const entryPosition = getDiskOffset$1(reader, fileEntry.diskNumberStart) + fileEntry.offset;
5147
- startOffset = Math.min(entryPosition, startOffset);
5148
- if (entryPosition < previousEntryPosition) {
5149
- addWarning(warnings, WARNING_UNSORTED_CENTRAL_DIRECTORY, filename);
5169
+ if (fileEntry.zip64ExtraFieldMissing && fileEntry.offset == MAX_32_BITS) {
5170
+ startOffset = 0;
5171
+ } else {
5172
+ fileEntry.offset += prependedDataLength;
5173
+ const entryPosition = getDiskOffset$1(reader, fileEntry.diskNumberStart) + fileEntry.offset;
5174
+ startOffset = Math.min(entryPosition, startOffset);
5175
+ if (entryPosition < previousEntryPosition) {
5176
+ addWarning(warnings, WARNING_UNSORTED_CENTRAL_DIRECTORY, filename);
5177
+ }
5178
+ previousEntryPosition = entryPosition;
5150
5179
  }
5151
- previousEntryPosition = entryPosition;
5152
5180
  if ((fileEntry.version & MAX_8_BITS) > MAX_KNOWN_VERSION) {
5153
5181
  addWarning(warnings, WARNING_UNKNOWN_VERSION, filename);
5154
5182
  }
@@ -5185,12 +5213,15 @@
5185
5213
  zipCrypto: fileEntry.encrypted && !fileEntry.extraFieldAES
5186
5214
  });
5187
5215
  const entry = new Entry(fileEntry);
5188
- entry.getData = (writer, options) => fileEntry.getData(writer, entry, zipReader.readRanges, options);
5216
+ if (fileEntry.zip64ExtraFieldMissing) {
5217
+ zipReader.entriesMissingZip64ExtraField.add(entry);
5218
+ }
5219
+ entry.getData = (writer, options) => fileEntry.getData(writer, entry, zipReader, options);
5189
5220
  entry.arrayBuffer = async options => {
5190
5221
  const writer = new TransformStream();
5191
5222
  const arrayBufferPromise = streamToBlob(writer.readable).then(blob => blob.arrayBuffer());
5192
5223
  arrayBufferPromise.catch(() => { });
5193
- await fileEntry.getData(writer, entry, zipReader.readRanges,
5224
+ await fileEntry.getData(writer, entry, zipReader,
5194
5225
  Object.assign({}, options, { preventClose: false }));
5195
5226
  return arrayBufferPromise;
5196
5227
  };
@@ -5398,8 +5429,9 @@
5398
5429
  });
5399
5430
  }
5400
5431
 
5401
- async getData(writer, fileEntry, readRanges, options = {}) {
5432
+ async getData(writer, fileEntry, zipReader, options = {}) {
5402
5433
  const zipEntry = this;
5434
+ const { readRanges, directoryOffset } = zipReader;
5403
5435
  if (zipEntry.zip64ExtraFieldMissing) {
5404
5436
  throw new Error(ERR_EXTRAFIELD_ZIP64_NOT_FOUND);
5405
5437
  }
@@ -5473,10 +5505,10 @@
5473
5505
  }
5474
5506
  validateLocalDirectory(zipEntry, localDirectory, rawLocalFilename, checkLocalFilename, checkLocalDirectory ? UNDEFINED_VALUE : warnings);
5475
5507
  const { lastAccessDate, creationDate, uid, gid } = localDirectory;
5476
- if (lastAccessDate) {
5508
+ if (lastAccessDate && fileEntry.lastAccessDate === UNDEFINED_VALUE) {
5477
5509
  fileEntry.lastAccessDate = lastAccessDate;
5478
5510
  }
5479
- if (creationDate) {
5511
+ if (creationDate && fileEntry.creationDate === UNDEFINED_VALUE) {
5480
5512
  fileEntry.creationDate = creationDate;
5481
5513
  }
5482
5514
  if (uid !== UNDEFINED_VALUE && fileEntry.uid === UNDEFINED_VALUE) {
@@ -5505,7 +5537,7 @@
5505
5537
  throw new Error(ERR_ENCRYPTED);
5506
5538
  }
5507
5539
  }
5508
- if (dataOffset + compressedSize > reader.size) {
5540
+ if (dataOffset + compressedSize > Math.min(reader.size, directoryOffset)) {
5509
5541
  throw new Error(ERR_ENTRY_DATA_OUT_OF_BOUNDS);
5510
5542
  }
5511
5543
  const size = compressedSize;
@@ -5571,6 +5603,7 @@
5571
5603
  extraFieldZip64: extraFieldZip64 || localDirectory.extraFieldZip64,
5572
5604
  readRanges
5573
5605
  });
5606
+ validateDataDescriptor(zipEntry, localDirectory, checkLocalDirectory ? UNDEFINED_VALUE : warnings);
5574
5607
  }
5575
5608
  let writable, abortError, aborted;
5576
5609
  try {
@@ -5590,10 +5623,7 @@
5590
5623
  writer.size += writtenSize;
5591
5624
  }
5592
5625
  } catch (error) {
5593
- const { outputSize: failedOutputSize } = workerOptions;
5594
- if (failedOutputSize !== UNDEFINED_VALUE) {
5595
- writer.size += failedOutputSize;
5596
- } else if (isErrorObject(error) && error.outputSize !== UNDEFINED_VALUE) {
5626
+ if (isErrorObject(error) && error.outputSize !== UNDEFINED_VALUE) {
5597
5627
  writer.size += error.outputSize;
5598
5628
  }
5599
5629
  if (!checkPasswordOnly || !isErrorObject(error) || error.message != ERR_ABORT_CHECK_PASSWORD) {
@@ -5621,13 +5651,7 @@
5621
5651
  }
5622
5652
 
5623
5653
  function detectEncryptedCentralDirectory(directoryView) {
5624
- const maxOffset = Math.min(directoryView.byteLength, 1024) - 3;
5625
- for (let offset = 0; offset < maxOffset; offset++) {
5626
- if (getUint32$1(directoryView, offset) == ARCHIVE_EXTRA_DATA_SIGNATURE) {
5627
- return true;
5628
- }
5629
- }
5630
- return false;
5654
+ return directoryView.byteLength >= 4 && getUint32$1(directoryView, 0) == ARCHIVE_EXTRA_DATA_SIGNATURE;
5631
5655
  }
5632
5656
 
5633
5657
  function getWrappedFilesLength(directoryView, directoryArray, offset) {
@@ -5664,6 +5688,46 @@
5664
5688
  }
5665
5689
  }
5666
5690
 
5691
+ async function findZip64EndOfDirectoryOffset(reader, endOffset) {
5692
+ const startOffset = Math.max(0, endOffset - (ZIP64_END_OF_CENTRAL_DIR_LENGTH + MAX_16_BITS));
5693
+ const tailArray = await readUint8Array(reader, startOffset, endOffset - startOffset);
5694
+ const tailView = getDataView(tailArray);
5695
+ for (let indexByte = tailArray.length - ZIP64_END_OF_CENTRAL_DIR_LENGTH; indexByte >= 0; indexByte--) {
5696
+ if (getUint32$1(tailView, indexByte) == ZIP64_END_OF_CENTRAL_DIR_SIGNATURE &&
5697
+ indexByte + 12 + Number(tailView.getBigUint64(indexByte + 4, true)) == tailArray.length) {
5698
+ return startOffset + indexByte;
5699
+ }
5700
+ }
5701
+ }
5702
+
5703
+ function getFirstLocalHeaderOffset(directoryArray, directoryView) {
5704
+ if (directoryArray.length < CENTRAL_FILE_HEADER_LENGTH) {
5705
+ return UNDEFINED_VALUE;
5706
+ }
5707
+ const localHeaderOffset = getUint32$1(directoryView, 42);
5708
+ if (localHeaderOffset != MAX_32_BITS) {
5709
+ return localHeaderOffset;
5710
+ }
5711
+ let offsetExtraField = CENTRAL_FILE_HEADER_LENGTH + getUint16$1(directoryView, 28);
5712
+ const endExtraField = Math.min(offsetExtraField + getUint16$1(directoryView, 30), directoryArray.length);
5713
+ while (offsetExtraField + 4 <= endExtraField) {
5714
+ const type = getUint16$1(directoryView, offsetExtraField);
5715
+ const size = getUint16$1(directoryView, offsetExtraField + 2);
5716
+ if (type == EXTRAFIELD_TYPE_ZIP64) {
5717
+ let offsetValue = offsetExtraField + 4;
5718
+ if (getUint32$1(directoryView, 24) == MAX_32_BITS) {
5719
+ offsetValue += 8;
5720
+ }
5721
+ if (getUint32$1(directoryView, 20) == MAX_32_BITS) {
5722
+ offsetValue += 8;
5723
+ }
5724
+ return offsetValue + 8 <= endExtraField ? getBigUint64(directoryView, offsetValue) : UNDEFINED_VALUE;
5725
+ }
5726
+ offsetExtraField += 4 + size;
5727
+ }
5728
+ return UNDEFINED_VALUE;
5729
+ }
5730
+
5667
5731
  function readDigitalSignature(signatureRecordArray) {
5668
5732
  if (signatureRecordArray.length >= 6) {
5669
5733
  const signatureRecordView = getDataView(signatureRecordArray);
@@ -5753,6 +5817,7 @@
5753
5817
  uncompressedSize: getUint32$1(dataView, offset + HEADER_OFFSET_UNCOMPRESSED_SIZE)
5754
5818
  });
5755
5819
  const extraFieldZip64 = extraField.get(EXTRAFIELD_TYPE_ZIP64);
5820
+ let extraFieldZip64Missing;
5756
5821
  if (extraFieldZip64) {
5757
5822
  if (!readExtraFieldZip64(extraFieldZip64, directory, localDirectory)) {
5758
5823
  malformedExtraField = true;
@@ -5762,7 +5827,7 @@
5762
5827
  if (localDirectory) {
5763
5828
  malformedExtraField = true;
5764
5829
  } else {
5765
- throw new Error(ERR_EXTRAFIELD_ZIP64_NOT_FOUND);
5830
+ extraFieldZip64Missing = true;
5766
5831
  }
5767
5832
  }
5768
5833
  const extraFieldUnicodePath = extraField.get(EXTRAFIELD_TYPE_UNICODE_PATH);
@@ -5820,6 +5885,9 @@
5820
5885
  if (extraFieldUSDZ) {
5821
5886
  directory.extraFieldUSDZ = extraFieldUSDZ;
5822
5887
  }
5888
+ if (extraFieldZip64Missing) {
5889
+ throw new Error(ERR_EXTRAFIELD_ZIP64_NOT_FOUND);
5890
+ }
5823
5891
  return malformedExtraField;
5824
5892
  }
5825
5893
 
@@ -6034,13 +6102,7 @@
6034
6102
  let dataDescriptorLength = 0;
6035
6103
  if (dataDescriptor) {
6036
6104
  const zip64 = Boolean(extraFieldZip64);
6037
- const dataDescriptorArray = await readUint8Array(reader, dataOffset + compressedSize, DATA_DESCRIPTOR_RECORD_ZIP_64_LENGTH + DATA_DESCRIPTOR_RECORD_SIGNATURE_LENGTH);
6038
- const dataDescriptorView = getDataView(dataDescriptorArray);
6039
- const candidates = [[zip64, true], [zip64, false], [!zip64, true], [!zip64, false]]
6040
- .map(([zip64Layout, signature]) => readDataDescriptor(dataDescriptorView, zip64Layout, signature))
6041
- .filter(candidate => candidate && candidate.compressedSize == compressedSize && candidate.uncompressedSize == uncompressedSize);
6042
- const localDataDescriptor = candidates.find(candidate => candidate.crc32 == crc32) || candidates[0] ||
6043
- readDataDescriptor(dataDescriptorView, zip64, true) || readDataDescriptor(dataDescriptorView, zip64, false);
6105
+ const localDataDescriptor = await readLocalDataDescriptor(reader, dataOffset + compressedSize, { crc32, compressedSize, uncompressedSize, zip64 });
6044
6106
  if (localDataDescriptor) {
6045
6107
  fileEntry.localDirectory.dataDescriptor = localDataDescriptor;
6046
6108
  dataDescriptorLength = getDataDescriptorLength(localDataDescriptor.zip64, localDataDescriptor.signature);
@@ -6110,6 +6172,25 @@
6110
6172
  return mergedRanges;
6111
6173
  }
6112
6174
 
6175
+ async function readLocalDataDescriptor(reader, offset, { crc32, compressedSize, uncompressedSize, zip64 }) {
6176
+ const maxLength = DATA_DESCRIPTOR_RECORD_ZIP_64_LENGTH + DATA_DESCRIPTOR_RECORD_SIGNATURE_LENGTH;
6177
+ const length = Math.min(maxLength, Math.max(0, reader.size - offset));
6178
+ const dataDescriptorArray = length ? await readUint8Array(reader, offset, length) : EMPTY_UINT8_ARRAY;
6179
+ const dataDescriptorView = getDataView(dataDescriptorArray);
6180
+ const candidates = [[zip64, true], [zip64, false], [!zip64, true], [!zip64, false]]
6181
+ .map(([zip64Layout, signature]) => readDataDescriptor(dataDescriptorView, zip64Layout, signature))
6182
+ .filter(candidate => candidate && candidate.compressedSize == compressedSize && candidate.uncompressedSize == uncompressedSize);
6183
+ return candidates.find(candidate => candidate.crc32 == crc32) || candidates[0] ||
6184
+ readDataDescriptor(dataDescriptorView, zip64, true) || readDataDescriptor(dataDescriptorView, zip64, false);
6185
+ }
6186
+
6187
+ async function getEntryDataDescriptorLength(reader, offset, { crc32, compressedSize, uncompressedSize, extraFieldZip64 }) {
6188
+ const dataDescriptor = await readLocalDataDescriptor(reader, offset, { crc32, compressedSize, uncompressedSize, zip64: Boolean(extraFieldZip64) });
6189
+ if (dataDescriptor && dataDescriptor.compressedSize == compressedSize && dataDescriptor.uncompressedSize == uncompressedSize) {
6190
+ return getDataDescriptorLength(dataDescriptor.zip64, dataDescriptor.signature);
6191
+ }
6192
+ }
6193
+
6113
6194
  function readDataDescriptor(dataDescriptorView, zip64, signature) {
6114
6195
  const offset = signature ? DATA_DESCRIPTOR_RECORD_SIGNATURE_LENGTH : 0;
6115
6196
  if (dataDescriptorView.byteLength < getDataDescriptorLength(zip64, signature) ||
@@ -6369,6 +6450,18 @@
6369
6450
  }
6370
6451
  }
6371
6452
 
6453
+ function validateDataDescriptor(zipEntry, localDirectory, warnings) {
6454
+ const { dataDescriptor } = localDirectory;
6455
+ const maskedLocalDirectory = zipEntry.decryptedDirectory &&
6456
+ (localDirectory.rawBitFlag & BITFLAG_MASKED_LOCAL_HEADERS) == BITFLAG_MASKED_LOCAL_HEADERS;
6457
+ if (dataDescriptor && !maskedLocalDirectory &&
6458
+ ((zipEntry.crc32 !== UNDEFINED_VALUE && dataDescriptor.crc32 != zipEntry.crc32) ||
6459
+ dataDescriptor.compressedSize != zipEntry.compressedSize ||
6460
+ dataDescriptor.uncompressedSize != zipEntry.uncompressedSize)) {
6461
+ reportAmbiguity(!warnings, warnings, WARNING_MISMATCHED_LOCAL_FILE_HEADER_CRC32_OR_SIZES);
6462
+ }
6463
+ }
6464
+
6372
6465
  function reportAmbiguity(reject, warnings, reason) {
6373
6466
  if (reject) {
6374
6467
  throwAmbiguousArchive(reason);
@@ -6471,6 +6564,7 @@
6471
6564
  WARNING_WRAPPED_ENTRIES_COUNT: WARNING_WRAPPED_ENTRIES_COUNT,
6472
6565
  ZipReader: ZipReader,
6473
6566
  ZipReaderStream: ZipReaderStream,
6567
+ getEntryDataDescriptorLength: getEntryDataDescriptorLength,
6474
6568
  isZipFile: isZipFile
6475
6569
  });
6476
6570
 
@@ -6594,136 +6688,7 @@
6594
6688
  }
6595
6689
 
6596
6690
  appendZip(reader, options = {}) {
6597
- return watchPromiseError(this, this.appendZipEntries(reader, options));
6598
- }
6599
-
6600
- async appendZipEntries(reader, options = {}) {
6601
- const zipWriter = this;
6602
- const { pendingAddFileCalls, filenames, fileEntries } = zipWriter;
6603
- const filter = checkFunctionOption(options.filter);
6604
- while (pendingAddFileCalls.size) {
6605
- await Promise.allSettled(Array.from(pendingAddFileCalls));
6606
- }
6607
- let resolveAppendZip;
6608
- const promiseAppendZip = new Promise(resolve => resolveAppendZip = resolve);
6609
- pendingAddFileCalls.add(promiseAppendZip);
6610
- const appendedFilenames = [];
6611
- let releaseLockWriter;
6612
- try {
6613
- reader = new GenericReader(reader);
6614
- await initStream(reader);
6615
- if (reader.size === UNDEFINED_VALUE || !reader.readUint8Array) {
6616
- reader = new BlobReader(await streamToBlob(reader.readable));
6617
- await initStream(reader);
6618
- }
6619
- const { ZipReader } = await Promise.resolve().then(function () { return zipReader; });
6620
- const zipReader$1 = new ZipReader(reader);
6621
- const entries = await zipReader$1.getEntries();
6622
- const keptEntries = [];
6623
- for (const entry of entries) {
6624
- if (!filter || await filter(entry)) {
6625
- keptEntries.push(entry);
6626
- }
6627
- }
6628
- await zipReader$1.close();
6629
- await initStream(zipWriter.writer);
6630
- const { directoryOffset } = zipReader$1;
6631
- keptEntries.forEach(({ filename }) => {
6632
- if (filenames.has(filename)) {
6633
- throw new Error(ERR_DUPLICATED_NAME);
6634
- }
6635
- filenames.add(filename);
6636
- appendedFilenames.push(filename);
6637
- });
6638
- zipWriter.writerLocked = true;
6639
- const { lockWriter } = zipWriter;
6640
- zipWriter.lockWriter = new Promise(resolve => releaseLockWriter = () => {
6641
- zipWriter.writerLocked = false;
6642
- resolve();
6643
- });
6644
- await lockWriter;
6645
- if (zipWriter.addSplitZipSignature) {
6646
- delete zipWriter.addSplitZipSignature;
6647
- if (!await startsWithSplitZipSignature(reader)) {
6648
- await writeData(zipWriter.writer, getSplitZipSignatureArray());
6649
- zipWriter.offset += SPLIT_ZIP_FILE_SIGNATURE_LENGTH;
6650
- }
6651
- }
6652
- const entryPositions = await copyZipData(zipWriter, reader, entries, keptEntries, directoryOffset, Boolean(filter));
6653
- keptEntries.forEach(entry => {
6654
- const {
6655
- version,
6656
- rawLastModDate,
6657
- rawFilename,
6658
- bitFlag,
6659
- encrypted,
6660
- uncompressedSize,
6661
- compressedSize,
6662
- extraFieldZip64
6663
- } = entry;
6664
- let {
6665
- compressionMethod,
6666
- rawExtraField,
6667
- } = entry;
6668
- const { level, languageEncodingFlag, dataDescriptor } = bitFlag;
6669
- rawExtraField = removeExtraFieldZip64(rawExtraField || EMPTY_UINT8_ARRAY);
6670
- if (entry.extraFieldAES) {
6671
- compressionMethod = COMPRESSION_METHOD_AES;
6672
- }
6673
- const extraFieldLength = getLength(rawExtraField);
6674
- const zip64UncompressedSize = Boolean(extraFieldZip64) && extraFieldZip64.uncompressedSize !== UNDEFINED_VALUE;
6675
- const zip64CompressedSize = Boolean(extraFieldZip64) && extraFieldZip64.compressedSize !== UNDEFINED_VALUE;
6676
- const bitFlagValue = (getBitFlag(level, languageEncodingFlag, dataDescriptor, encrypted, compressionMethod) & ~BITFLAG_LEVEL) | (level << 1);
6677
- const {
6678
- headerArray,
6679
- headerView
6680
- } = getHeaderArrayData({
6681
- version,
6682
- bitFlag: bitFlagValue,
6683
- compressionMethod,
6684
- uncompressedSize,
6685
- compressedSize,
6686
- rawLastModDate,
6687
- rawFilename,
6688
- zip64CompressedSize,
6689
- zip64UncompressedSize,
6690
- extraFieldLength
6691
- });
6692
- const { crc32 } = entry;
6693
- if (crc32 !== UNDEFINED_VALUE) {
6694
- setUint32(headerView, HEADER_OFFSET_SIGNATURE, crc32);
6695
- }
6696
- const { offset, diskNumberStart } = entryPositions.get(entry);
6697
- Object.assign(entry, {
6698
- zip64Enabled: true,
6699
- zip64UncompressedSize,
6700
- zip64CompressedSize,
6701
- offset,
6702
- diskNumberStart,
6703
- zip64DiskNumberStart: false,
6704
- rawExtraFieldZip64: EMPTY_UINT8_ARRAY,
6705
- rawExtraFieldAES: EMPTY_UINT8_ARRAY,
6706
- rawExtraFieldExtendedTimestamp: EMPTY_UINT8_ARRAY,
6707
- rawExtraFieldNTFS: EMPTY_UINT8_ARRAY,
6708
- rawExtraFieldUnix: EMPTY_UINT8_ARRAY,
6709
- rawCentralExtraFieldUnix: EMPTY_UINT8_ARRAY,
6710
- rawExtraField,
6711
- rawCentralExtraField: EMPTY_UINT8_ARRAY,
6712
- headerArray,
6713
- headerView
6714
- });
6715
- fileEntries.set(entry.filename, entry);
6716
- });
6717
- } catch (error) {
6718
- appendedFilenames.forEach(filename => filenames.delete(filename));
6719
- throw error;
6720
- } finally {
6721
- resolveAppendZip();
6722
- pendingAddFileCalls.delete(promiseAppendZip);
6723
- if (releaseLockWriter) {
6724
- releaseLockWriter();
6725
- }
6726
- }
6691
+ return watchPromiseError(this, appendZipEntries(this, reader, options));
6727
6692
  }
6728
6693
 
6729
6694
  add(name = "", reader, options = {}) {
@@ -6885,11 +6850,149 @@
6885
6850
  return watchedPromise;
6886
6851
  }
6887
6852
 
6853
+ async function appendZipEntries(zipWriter, reader, options = {}) {
6854
+ const { pendingAddFileCalls, filenames, fileEntries } = zipWriter;
6855
+ const filter = checkFunctionOption(options.filter);
6856
+ const readerOptions = checkReaderOptionsObject(options.readerOptions);
6857
+ while (pendingAddFileCalls.size) {
6858
+ await Promise.allSettled(Array.from(pendingAddFileCalls));
6859
+ }
6860
+ let resolveAppendZip;
6861
+ const promiseAppendZip = new Promise(resolve => resolveAppendZip = resolve);
6862
+ pendingAddFileCalls.add(promiseAppendZip);
6863
+ const appendedFilenames = [];
6864
+ let releaseLockWriter;
6865
+ try {
6866
+ reader = new GenericReader(reader);
6867
+ await initStream(reader);
6868
+ if (reader.size === UNDEFINED_VALUE || !reader.readUint8Array) {
6869
+ reader = new BlobReader(await streamToBlob(reader.readable));
6870
+ await initStream(reader);
6871
+ }
6872
+ const { ZipReader, getEntryDataDescriptorLength } = await Promise.resolve().then(function () { return zipReader; });
6873
+ const zipReader$1 = new ZipReader(reader, readerOptions);
6874
+ const keptEntries = [];
6875
+ let entries;
6876
+ try {
6877
+ entries = await zipReader$1.getEntries();
6878
+ for (const entry of entries) {
6879
+ if (!filter || await filter(entry, getExistingEntry(fileEntries, entry.filename))) {
6880
+ keptEntries.push(entry);
6881
+ }
6882
+ }
6883
+ } finally {
6884
+ await zipReader$1.close();
6885
+ }
6886
+ await initStream(zipWriter.writer);
6887
+ const { directoryOffset, entriesMissingZip64ExtraField } = zipReader$1;
6888
+ keptEntries.forEach(entry => {
6889
+ const { filename } = entry;
6890
+ if (entriesMissingZip64ExtraField.has(entry)) {
6891
+ throw new Error(ERR_EXTRAFIELD_ZIP64_NOT_FOUND);
6892
+ }
6893
+ if (filenames.has(filename)) {
6894
+ throw new Error(ERR_DUPLICATED_NAME);
6895
+ }
6896
+ filenames.add(filename);
6897
+ appendedFilenames.push(filename);
6898
+ });
6899
+ zipWriter.writerLocked = true;
6900
+ const { lockWriter } = zipWriter;
6901
+ zipWriter.lockWriter = new Promise(resolve => releaseLockWriter = () => {
6902
+ zipWriter.writerLocked = false;
6903
+ resolve();
6904
+ });
6905
+ await lockWriter;
6906
+ if (zipWriter.addSplitZipSignature) {
6907
+ delete zipWriter.addSplitZipSignature;
6908
+ if (filter || !await startsWithSplitZipSignature(reader)) {
6909
+ await writeData(zipWriter.writer, getSplitZipSignatureArray());
6910
+ zipWriter.offset += SPLIT_ZIP_FILE_SIGNATURE_LENGTH;
6911
+ }
6912
+ }
6913
+ const entryPositions = await copyZipData(zipWriter, reader, entries, keptEntries, directoryOffset, Boolean(filter), getEntryDataDescriptorLength);
6914
+ keptEntries.forEach(entry => {
6915
+ const {
6916
+ version,
6917
+ rawLastModDate,
6918
+ rawFilename,
6919
+ rawBitFlag,
6920
+ uncompressedSize,
6921
+ compressedSize,
6922
+ extraFieldZip64
6923
+ } = entry;
6924
+ let {
6925
+ compressionMethod,
6926
+ rawExtraField,
6927
+ } = entry;
6928
+ rawExtraField = removeExtraFieldZip64(rawExtraField || EMPTY_UINT8_ARRAY);
6929
+ if (entry.extraFieldAES) {
6930
+ compressionMethod = COMPRESSION_METHOD_AES;
6931
+ }
6932
+ const extraFieldLength = getLength(rawExtraField);
6933
+ const zip64UncompressedSize = Boolean(extraFieldZip64) && extraFieldZip64.uncompressedSize !== UNDEFINED_VALUE;
6934
+ const zip64CompressedSize = Boolean(extraFieldZip64) && extraFieldZip64.compressedSize !== UNDEFINED_VALUE;
6935
+ const {
6936
+ headerArray,
6937
+ headerView
6938
+ } = getHeaderArrayData({
6939
+ version,
6940
+ bitFlag: rawBitFlag,
6941
+ compressionMethod,
6942
+ uncompressedSize,
6943
+ compressedSize,
6944
+ rawLastModDate,
6945
+ rawFilename,
6946
+ zip64CompressedSize,
6947
+ zip64UncompressedSize,
6948
+ extraFieldLength
6949
+ });
6950
+ const { crc32 } = entry;
6951
+ if (crc32 !== UNDEFINED_VALUE) {
6952
+ setUint32(headerView, HEADER_OFFSET_SIGNATURE, crc32);
6953
+ }
6954
+ const { offset, diskNumberStart } = entryPositions.get(entry);
6955
+ fileEntries.set(entry.filename, Object.assign({}, entry, {
6956
+ zip64Enabled: true,
6957
+ zip64UncompressedSize,
6958
+ zip64CompressedSize,
6959
+ offset,
6960
+ diskNumberStart,
6961
+ zip64DiskNumberStart: false,
6962
+ rawExtraFieldZip64: EMPTY_UINT8_ARRAY,
6963
+ rawExtraFieldAES: EMPTY_UINT8_ARRAY,
6964
+ rawExtraFieldExtendedTimestamp: EMPTY_UINT8_ARRAY,
6965
+ rawExtraFieldNTFS: EMPTY_UINT8_ARRAY,
6966
+ rawExtraFieldUnix: EMPTY_UINT8_ARRAY,
6967
+ rawCentralExtraFieldUnix: EMPTY_UINT8_ARRAY,
6968
+ rawExtraField,
6969
+ rawCentralExtraField: EMPTY_UINT8_ARRAY,
6970
+ headerArray,
6971
+ headerView
6972
+ }));
6973
+ });
6974
+ } catch (error) {
6975
+ appendedFilenames.forEach(filename => filenames.delete(filename));
6976
+ throw error;
6977
+ } finally {
6978
+ resolveAppendZip();
6979
+ pendingAddFileCalls.delete(promiseAppendZip);
6980
+ if (releaseLockWriter) {
6981
+ releaseLockWriter();
6982
+ }
6983
+ }
6984
+ }
6985
+
6986
+ function getExistingEntry(fileEntries, filename) {
6987
+ const fileEntry = fileEntries.get(filename);
6988
+ return fileEntry ? new Entry(fileEntry) : UNDEFINED_VALUE;
6989
+ }
6990
+
6888
6991
  async function prependZipEntries(zipWriter, reader) {
6889
6992
  if (zipWriter.filenames.size) {
6890
6993
  throw new Error(ERR_ZIP_NOT_EMPTY);
6891
6994
  }
6892
- await zipWriter.appendZipEntries(reader);
6995
+ await appendZipEntries(zipWriter, reader);
6893
6996
  }
6894
6997
 
6895
6998
  async function addFileEntry(zipWriter, name, reader, options) {
@@ -8563,7 +8666,7 @@
8563
8666
  return rawExtraField;
8564
8667
  }
8565
8668
 
8566
- async function copyZipData(zipWriter, reader, entries, keptEntries, directoryOffset, compact) {
8669
+ async function copyZipData(zipWriter, reader, entries, keptEntries, directoryOffset, compact, getEntryDataDescriptorLength) {
8567
8670
  const { writer } = zipWriter;
8568
8671
  const entryPositions = new Map();
8569
8672
  if (writer.closeDisk || compact) {
@@ -8571,6 +8674,27 @@
8571
8674
  getSourceOffset(reader, firstEntry) - getSourceOffset(reader, secondEntry));
8572
8675
  const regionEnds = getRegionEnds(reader, sortedEntries, directoryOffset);
8573
8676
  const keptEntrySet = new Set(keptEntries);
8677
+ const localHeaderLengths = new Map();
8678
+ for (let indexEntry = 0; indexEntry < sortedEntries.length; indexEntry++) {
8679
+ const entry = sortedEntries[indexEntry];
8680
+ if (keptEntrySet.has(entry)) {
8681
+ const sourceOffset = getSourceOffset(reader, entry);
8682
+ const localHeaderLength = await getLocalHeaderLength(reader, sourceOffset);
8683
+ if (localHeaderLength === UNDEFINED_VALUE) {
8684
+ throw new Error(ERR_LOCAL_FILE_HEADER_NOT_FOUND);
8685
+ }
8686
+ let entryEnd = sourceOffset + localHeaderLength + entry.compressedSize;
8687
+ if (entry.bitFlag.dataDescriptor) {
8688
+ const dataDescriptorLength = await getEntryDataDescriptorLength(reader, entryEnd, entry);
8689
+ entryEnd = dataDescriptorLength === UNDEFINED_VALUE ? Math.max(entryEnd, regionEnds[indexEntry]) : entryEnd + dataDescriptorLength;
8690
+ }
8691
+ if (entryEnd > regionEnds[indexEntry]) {
8692
+ throw new Error(ERR_OVERLAPPING_ENTRY);
8693
+ }
8694
+ regionEnds[indexEntry] = entryEnd;
8695
+ localHeaderLengths.set(entry, localHeaderLength);
8696
+ }
8697
+ }
8574
8698
  let copiedOffset = 0;
8575
8699
  let lastPosition;
8576
8700
  for (let indexEntry = 0; indexEntry < sortedEntries.length; indexEntry++) {
@@ -8583,7 +8707,7 @@
8583
8707
  if (!compact) {
8584
8708
  await copyData(zipWriter, reader, copiedOffset, sourceOffset - copiedOffset);
8585
8709
  }
8586
- if (writer.closeDisk && exceedsAvailableSize(writer, await getLocalHeaderLength(reader, sourceOffset))) {
8710
+ if (writer.closeDisk && exceedsAvailableSize(writer, localHeaderLengths.get(entry))) {
8587
8711
  await writer.closeDisk();
8588
8712
  }
8589
8713
  lastPosition = {
@@ -8617,7 +8741,7 @@
8617
8741
  const sourceOffset = getSourceOffset(reader, sortedEntries[indexEntry]);
8618
8742
  const nextEntry = sortedEntries[indexEntry + 1];
8619
8743
  if (nextEntry && getSourceOffset(reader, nextEntry) > sourceOffset) {
8620
- regionEnd = getSourceOffset(reader, nextEntry);
8744
+ regionEnd = Math.min(getSourceOffset(reader, nextEntry), directoryOffset);
8621
8745
  }
8622
8746
  regionEnds[indexEntry] = regionEnd;
8623
8747
  }
@@ -8631,11 +8755,13 @@
8631
8755
  try {
8632
8756
  await flushBufferedData(createReadable(reader, { offset, size }), writer, UNDEFINED_VALUE, chunkLength => copiedLength += chunkLength);
8633
8757
  } catch (error) {
8634
- zipWriter.hasCorruptedEntries = true;
8635
- try {
8636
- error.corruptedEntry = true;
8637
- } catch {
8638
- // ignored
8758
+ if (copiedLength) {
8759
+ zipWriter.hasCorruptedEntries = true;
8760
+ try {
8761
+ error.corruptedEntry = true;
8762
+ } catch {
8763
+ // ignored
8764
+ }
8639
8765
  }
8640
8766
  throw error;
8641
8767
  } finally {
@@ -8646,11 +8772,16 @@
8646
8772
  }
8647
8773
 
8648
8774
  async function getLocalHeaderLength(reader, offset) {
8649
- const headerArray = await readUint8Array(reader, offset, HEADER_SIZE);
8775
+ const headerArray = offset >= 0 && offset + HEADER_SIZE <= reader.size ?
8776
+ await readUint8Array(reader, offset, HEADER_SIZE) :
8777
+ EMPTY_UINT8_ARRAY;
8650
8778
  if (getLength(headerArray) < HEADER_SIZE) {
8651
- return HEADER_SIZE;
8779
+ return UNDEFINED_VALUE;
8652
8780
  }
8653
8781
  const headerView = getDataView(headerArray);
8782
+ if (getUint32(headerView, 0) != LOCAL_FILE_HEADER_SIGNATURE) {
8783
+ return UNDEFINED_VALUE;
8784
+ }
8654
8785
  return HEADER_SIZE +
8655
8786
  getUint16(headerView, HEADER_OFFSET_FILENAME_LENGTH + LOCAL_HEADER_COMMON_OFFSET) +
8656
8787
  getUint16(headerView, HEADER_OFFSET_EXTRAFIELD_LENGTH + LOCAL_HEADER_COMMON_OFFSET);
@@ -9001,7 +9132,7 @@
9001
9132
  EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
9002
9133
  */
9003
9134
 
9004
- const VERSION = "2.20.0";
9135
+ const VERSION = "2.22.0";
9005
9136
 
9006
9137
  /*
9007
9138
  Copyright (c) 2025 Gildas Lormeau. All rights reserved.
@@ -9530,6 +9661,7 @@
9530
9661
  exports.ERR_INVALID_PASSWORD_TYPE = ERR_INVALID_PASSWORD_TYPE;
9531
9662
  exports.ERR_INVALID_PASS_THROUGH_VALUE = ERR_INVALID_PASS_THROUGH_VALUE;
9532
9663
  exports.ERR_INVALID_READER = ERR_INVALID_READER;
9664
+ exports.ERR_INVALID_READER_OPTIONS = ERR_INVALID_READER_OPTIONS;
9533
9665
  exports.ERR_INVALID_SIGNAL = ERR_INVALID_SIGNAL;
9534
9666
  exports.ERR_INVALID_SIGNATURE_DATA = ERR_INVALID_SIGNATURE_DATA;
9535
9667
  exports.ERR_INVALID_STRICTNESS = ERR_INVALID_STRICTNESS;