@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.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",
@@ -4765,12 +4775,9 @@
4765
4775
  const ERR_EOCDR_NOT_FOUND = "End of central directory not found";
4766
4776
  const ERR_EOCDR_LOCATOR_ZIP64_NOT_FOUND = "End of Zip64 central directory locator not found";
4767
4777
  const ERR_CENTRAL_DIRECTORY_NOT_FOUND = "Central directory header not found";
4768
- const ERR_LOCAL_FILE_HEADER_NOT_FOUND = "Local file header not found";
4769
- const ERR_EXTRAFIELD_ZIP64_NOT_FOUND = "Zip64 extra field not found";
4770
4778
  const ERR_ENCRYPTED = "File contains encrypted entry";
4771
4779
  const ERR_UNSUPPORTED_ENCRYPTION = "Encryption method not supported";
4772
4780
  const ERR_SPLIT_ZIP_FILE = "Split zip file";
4773
- const ERR_OVERLAPPING_ENTRY = "Overlapping entry found";
4774
4781
  const ERR_ENTRY_DATA_OUT_OF_BOUNDS = "Entry data out of bounds";
4775
4782
  const ERR_AMBIGUOUS_ARCHIVE = "Ambiguous archive";
4776
4783
  const ERR_ENCRYPTED_CENTRAL_DIRECTORY = "Encrypted central directory is not supported";
@@ -4834,8 +4841,9 @@
4834
4841
  constructor(reader, options = {}) {
4835
4842
  Object.assign(this, {
4836
4843
  reader: new GenericReader(reader),
4837
- options,
4838
- readRanges: { indexes: new Set(), sortedRanges: [], pendingRanges: [] }
4844
+ options: options || {},
4845
+ readRanges: { indexes: new Set(), sortedRanges: [], pendingRanges: [] },
4846
+ entriesMissingZip64ExtraField: new WeakSet()
4839
4847
  });
4840
4848
  }
4841
4849
 
@@ -4906,16 +4914,22 @@
4906
4914
  directoryDataOffset = getDiskOffset$1(reader, getUint32$1(endOfDirectoryLocatorView, 4)) + getBigUint64(endOfDirectoryLocatorView, 8);
4907
4915
  let endOfDirectoryArray = await readUint8Array(reader, directoryDataOffset, ZIP64_END_OF_CENTRAL_DIR_LENGTH);
4908
4916
  let endOfDirectoryView = getDataView(endOfDirectoryArray);
4909
- const expectedDirectoryDataOffset = endOfDirectoryInfo.offset - ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH - ZIP64_END_OF_CENTRAL_DIR_LENGTH;
4910
- if ((endOfDirectoryArray.length < ZIP64_END_OF_CENTRAL_DIR_LENGTH || getUint32$1(endOfDirectoryView, 0) != ZIP64_END_OF_CENTRAL_DIR_SIGNATURE) &&
4911
- directoryDataOffset != expectedDirectoryDataOffset && expectedDirectoryDataOffset >= 0) {
4912
- const originalDirectoryDataOffset = directoryDataOffset;
4913
- directoryDataOffset = expectedDirectoryDataOffset;
4914
- if (directoryDataOffset > originalDirectoryDataOffset) {
4915
- prependedDataLength = directoryDataOffset - originalDirectoryDataOffset;
4917
+ if (endOfDirectoryArray.length < ZIP64_END_OF_CENTRAL_DIR_LENGTH || getUint32$1(endOfDirectoryView, 0) != ZIP64_END_OF_CENTRAL_DIR_SIGNATURE) {
4918
+ const locatorOffset = endOfDirectoryInfo.offset - ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH;
4919
+ let expectedDirectoryDataOffset = locatorOffset - ZIP64_END_OF_CENTRAL_DIR_LENGTH;
4920
+ if (!await startsWithSignature(reader, expectedDirectoryDataOffset, ZIP64_END_OF_CENTRAL_DIR_SIGNATURE)) {
4921
+ expectedDirectoryDataOffset = await findZip64EndOfDirectoryOffset(reader, locatorOffset);
4922
+ }
4923
+ if (expectedDirectoryDataOffset !== UNDEFINED_VALUE && expectedDirectoryDataOffset >= 0 &&
4924
+ directoryDataOffset != expectedDirectoryDataOffset) {
4925
+ const originalDirectoryDataOffset = directoryDataOffset;
4926
+ directoryDataOffset = expectedDirectoryDataOffset;
4927
+ if (directoryDataOffset > originalDirectoryDataOffset) {
4928
+ prependedDataLength = directoryDataOffset - originalDirectoryDataOffset;
4929
+ }
4930
+ endOfDirectoryArray = await readUint8Array(reader, directoryDataOffset, ZIP64_END_OF_CENTRAL_DIR_LENGTH);
4931
+ endOfDirectoryView = getDataView(endOfDirectoryArray);
4916
4932
  }
4917
- endOfDirectoryArray = await readUint8Array(reader, directoryDataOffset, ZIP64_END_OF_CENTRAL_DIR_LENGTH);
4918
- endOfDirectoryView = getDataView(endOfDirectoryArray);
4919
4933
  }
4920
4934
  if (endOfDirectoryArray.length < ZIP64_END_OF_CENTRAL_DIR_LENGTH || getUint32$1(endOfDirectoryView, 0) != ZIP64_END_OF_CENTRAL_DIR_SIGNATURE) {
4921
4935
  throw new Error(ERR_EOCDR_LOCATOR_ZIP64_NOT_FOUND);
@@ -4960,10 +4974,6 @@
4960
4974
  let declaredDirectoryDataLength = directoryDataLength;
4961
4975
  const centralDirectoryEndOffset = endOfDirectoryInfo.offset -
4962
4976
  (zip64EndOfDirectory ? zip64EndOfDirectoryLength + ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH : 0);
4963
- if (directoryDataOffset >= reader.size) {
4964
- prependedDataLength = reader.size - directoryDataOffset - directoryDataLength - END_OF_CENTRAL_DIR_LENGTH;
4965
- directoryDataOffset = reader.size - directoryDataLength - END_OF_CENTRAL_DIR_LENGTH;
4966
- }
4967
4977
  if (expectedLastDiskNumber != lastDiskNumber) {
4968
4978
  throw new Error(ERR_SPLIT_ZIP_FILE);
4969
4979
  }
@@ -4971,52 +4981,64 @@
4971
4981
  throw new Error(ERR_BAD_FORMAT);
4972
4982
  }
4973
4983
  let offset = 0;
4974
- let directoryArray = await readUint8Array(reader, directoryDataOffset, directoryDataLength);
4984
+ let directoryArray = directoryDataOffset < reader.size ?
4985
+ await readUint8Array(reader, directoryDataOffset, directoryDataLength) :
4986
+ EMPTY_UINT8_ARRAY;
4975
4987
  let directoryView = getDataView(directoryArray);
4976
4988
  if (directoryDataLength) {
4977
- if (directoryArray.length < 4) {
4978
- throw new Error(ERR_BAD_FORMAT);
4979
- }
4980
4989
  let expectedDirectoryDataOffset = centralDirectoryEndOffset - directoryDataLength;
4981
4990
  if (directoryDataOffset != expectedDirectoryDataOffset && diskNumber == lastDiskNumber) {
4982
- const storedPointsAtDirectory = getUint32$1(directoryView, offset) == CENTRAL_FILE_HEADER_SIGNATURE ||
4991
+ const storedPointsAtDirectory = directoryArray.length >= 4 && (
4992
+ getUint32$1(directoryView, offset) == CENTRAL_FILE_HEADER_SIGNATURE ||
4983
4993
  Boolean(directoryEncryptionInfo && directoryEncryptionInfo.compressedSize) ||
4984
- detectEncryptedCentralDirectory(directoryView);
4994
+ detectEncryptedCentralDirectory(directoryView));
4995
+ if (!storedPointsAtDirectory && expectedDirectoryDataOffset < 0) {
4996
+ throw new Error(ERR_BAD_FORMAT);
4997
+ }
4985
4998
  let reconcile = !storedPointsAtDirectory;
4986
4999
  if (expectedDirectoryDataOffset >= 0 && expectedDirectoryDataOffset + 4 <= reader.size) {
4987
- const expectedPointsAtDirectory = await pointsAtDirectory(reader, expectedDirectoryDataOffset);
4988
- if (storedPointsAtDirectory) {
4989
- reconcile = expectedPointsAtDirectory;
4990
- } else if (!expectedPointsAtDirectory) {
5000
+ let expectedPointsAtDirectory = await pointsAtDirectory(reader, expectedDirectoryDataOffset);
5001
+ if (!expectedPointsAtDirectory) {
4991
5002
  const signatureRecordOffset = await findDigitalSignatureRecordOffset(reader, centralDirectoryEndOffset);
4992
5003
  const signedDirectoryDataOffset = signatureRecordOffset - directoryDataLength;
4993
5004
  if (signatureRecordOffset !== UNDEFINED_VALUE && signedDirectoryDataOffset >= 0 &&
4994
5005
  await pointsAtDirectory(reader, signedDirectoryDataOffset)) {
4995
5006
  expectedDirectoryDataOffset = signedDirectoryDataOffset;
5007
+ expectedPointsAtDirectory = true;
4996
5008
  }
4997
5009
  }
5010
+ if (storedPointsAtDirectory) {
5011
+ reconcile = expectedPointsAtDirectory;
5012
+ }
4998
5013
  }
4999
- if (reconcile) {
5014
+ if (reconcile && expectedDirectoryDataOffset != directoryDataOffset) {
5000
5015
  const originalDirectoryDataOffset = directoryDataOffset;
5001
5016
  directoryDataOffset = expectedDirectoryDataOffset;
5002
5017
  directoryArray = await readUint8Array(reader, directoryDataOffset, directoryDataLength);
5003
5018
  directoryView = getDataView(directoryArray);
5004
- if (directoryDataOffset > originalDirectoryDataOffset) {
5005
- prependedDataLength += directoryDataOffset - originalDirectoryDataOffset;
5019
+ const offsetDelta = directoryDataOffset - originalDirectoryDataOffset;
5020
+ const localHeaderOffset = getFirstLocalHeaderOffset(directoryArray, directoryView);
5021
+ const localHeaderFound = localHeaderOffset !== UNDEFINED_VALUE &&
5022
+ await startsWithSignature(reader, localHeaderOffset, LOCAL_FILE_HEADER_SIGNATURE);
5023
+ const shiftedLocalHeaderFound = localHeaderOffset !== UNDEFINED_VALUE &&
5024
+ await startsWithSignature(reader, localHeaderOffset + offsetDelta, LOCAL_FILE_HEADER_SIGNATURE);
5025
+ if (offsetDelta > 0 && !(localHeaderFound && !shiftedLocalHeaderFound)) {
5026
+ prependedDataLength += offsetDelta;
5006
5027
  prependedCentralDirectory = storedPointsAtDirectory;
5007
5028
  } else {
5008
5029
  reportAmbiguity(checkAmbiguity, warnings, WARNING_MISMATCHED_CENTRAL_DIRECTORY_OFFSET);
5009
- const offsetDelta = directoryDataOffset - originalDirectoryDataOffset;
5010
- if (directoryArray.length >= CENTRAL_FILE_HEADER_LENGTH) {
5011
- const localHeaderOffset = getUint32$1(directoryView, 42);
5012
- if (!await startsWithSignature(reader, localHeaderOffset, LOCAL_FILE_HEADER_SIGNATURE) &&
5013
- await startsWithSignature(reader, localHeaderOffset + offsetDelta, LOCAL_FILE_HEADER_SIGNATURE)) {
5014
- prependedDataLength += offsetDelta;
5015
- }
5030
+ if (offsetDelta < 0 && !localHeaderFound && shiftedLocalHeaderFound) {
5031
+ prependedDataLength += offsetDelta;
5016
5032
  }
5017
5033
  }
5018
5034
  }
5019
5035
  }
5036
+ if (directoryArray.length < 4) {
5037
+ throw new Error(ERR_BAD_FORMAT);
5038
+ }
5039
+ } else if (!filesLength && directoryDataOffset < centralDirectoryEndOffset && diskNumber == lastDiskNumber) {
5040
+ prependedDataLength += centralDirectoryEndOffset - directoryDataOffset;
5041
+ directoryDataOffset = centralDirectoryEndOffset;
5020
5042
  }
5021
5043
  const expectedDirectoryDataLength = centralDirectoryEndOffset - directoryDataOffset;
5022
5044
  if (directoryDataLength != expectedDirectoryDataLength && expectedDirectoryDataLength >= 0 && diskNumber == lastDiskNumber) {
@@ -5058,8 +5080,10 @@
5058
5080
  addWarning(warnings, WARNING_WRAPPED_ENTRIES_COUNT);
5059
5081
  }
5060
5082
  }
5083
+ const entryOptions = Object.assign({}, zipReader.options, options, { [OPTION_STRICTNESS]: strictness });
5084
+ delete entryOptions[OPTION_CHECK_AMBIGUITY];
5061
5085
  for (let indexFile = 0; indexFile < filesLength; indexFile++) {
5062
- const fileEntry = new ZipEntry(reader, zipReader.options);
5086
+ const fileEntry = new ZipEntry(reader, entryOptions);
5063
5087
  if (offset + CENTRAL_FILE_HEADER_LENGTH > directoryArray.length || getUint32$1(directoryView, offset) != CENTRAL_FILE_HEADER_SIGNATURE) {
5064
5088
  if (indexFile == 0 && !decryptedDirectory && (zip64EndOfDirectoryVersion2 || detectEncryptedCentralDirectory(directoryView))) {
5065
5089
  throw new Error(ERR_ENCRYPTED_CENTRAL_DIRECTORY);
@@ -5150,13 +5174,17 @@
5150
5174
  if (malformedExtraField) {
5151
5175
  addWarning(warnings, WARNING_MALFORMED_EXTRA_FIELD, filename);
5152
5176
  }
5153
- fileEntry.offset += prependedDataLength;
5154
- const entryPosition = getDiskOffset$1(reader, fileEntry.diskNumberStart) + fileEntry.offset;
5155
- startOffset = Math.min(entryPosition, startOffset);
5156
- if (entryPosition < previousEntryPosition) {
5157
- addWarning(warnings, WARNING_UNSORTED_CENTRAL_DIRECTORY, filename);
5177
+ if (fileEntry.zip64ExtraFieldMissing && fileEntry.offset == MAX_32_BITS) {
5178
+ startOffset = 0;
5179
+ } else {
5180
+ fileEntry.offset += prependedDataLength;
5181
+ const entryPosition = getDiskOffset$1(reader, fileEntry.diskNumberStart) + fileEntry.offset;
5182
+ startOffset = Math.min(entryPosition, startOffset);
5183
+ if (entryPosition < previousEntryPosition) {
5184
+ addWarning(warnings, WARNING_UNSORTED_CENTRAL_DIRECTORY, filename);
5185
+ }
5186
+ previousEntryPosition = entryPosition;
5158
5187
  }
5159
- previousEntryPosition = entryPosition;
5160
5188
  if ((fileEntry.version & MAX_8_BITS) > MAX_KNOWN_VERSION) {
5161
5189
  addWarning(warnings, WARNING_UNKNOWN_VERSION, filename);
5162
5190
  }
@@ -5193,12 +5221,15 @@
5193
5221
  zipCrypto: fileEntry.encrypted && !fileEntry.extraFieldAES
5194
5222
  });
5195
5223
  const entry = new Entry(fileEntry);
5196
- entry.getData = (writer, options) => fileEntry.getData(writer, entry, zipReader.readRanges, options);
5224
+ if (fileEntry.zip64ExtraFieldMissing) {
5225
+ zipReader.entriesMissingZip64ExtraField.add(entry);
5226
+ }
5227
+ entry.getData = (writer, options) => fileEntry.getData(writer, entry, zipReader, options);
5197
5228
  entry.arrayBuffer = async options => {
5198
5229
  const writer = new TransformStream();
5199
5230
  const arrayBufferPromise = streamToBlob(writer.readable).then(blob => blob.arrayBuffer());
5200
5231
  arrayBufferPromise.catch(() => { });
5201
- await fileEntry.getData(writer, entry, zipReader.readRanges,
5232
+ await fileEntry.getData(writer, entry, zipReader,
5202
5233
  Object.assign({}, options, { preventClose: false }));
5203
5234
  return arrayBufferPromise;
5204
5235
  };
@@ -5406,8 +5437,9 @@
5406
5437
  });
5407
5438
  }
5408
5439
 
5409
- async getData(writer, fileEntry, readRanges, options = {}) {
5440
+ async getData(writer, fileEntry, zipReader, options = {}) {
5410
5441
  const zipEntry = this;
5442
+ const { readRanges, directoryOffset } = zipReader;
5411
5443
  if (zipEntry.zip64ExtraFieldMissing) {
5412
5444
  throw new Error(ERR_EXTRAFIELD_ZIP64_NOT_FOUND);
5413
5445
  }
@@ -5481,10 +5513,10 @@
5481
5513
  }
5482
5514
  validateLocalDirectory(zipEntry, localDirectory, rawLocalFilename, checkLocalFilename, checkLocalDirectory ? UNDEFINED_VALUE : warnings);
5483
5515
  const { lastAccessDate, creationDate, uid, gid } = localDirectory;
5484
- if (lastAccessDate) {
5516
+ if (lastAccessDate && fileEntry.lastAccessDate === UNDEFINED_VALUE) {
5485
5517
  fileEntry.lastAccessDate = lastAccessDate;
5486
5518
  }
5487
- if (creationDate) {
5519
+ if (creationDate && fileEntry.creationDate === UNDEFINED_VALUE) {
5488
5520
  fileEntry.creationDate = creationDate;
5489
5521
  }
5490
5522
  if (uid !== UNDEFINED_VALUE && fileEntry.uid === UNDEFINED_VALUE) {
@@ -5513,7 +5545,7 @@
5513
5545
  throw new Error(ERR_ENCRYPTED);
5514
5546
  }
5515
5547
  }
5516
- if (dataOffset + compressedSize > reader.size) {
5548
+ if (dataOffset + compressedSize > Math.min(reader.size, directoryOffset)) {
5517
5549
  throw new Error(ERR_ENTRY_DATA_OUT_OF_BOUNDS);
5518
5550
  }
5519
5551
  const size = compressedSize;
@@ -5579,6 +5611,7 @@
5579
5611
  extraFieldZip64: extraFieldZip64 || localDirectory.extraFieldZip64,
5580
5612
  readRanges
5581
5613
  });
5614
+ validateDataDescriptor(zipEntry, localDirectory, checkLocalDirectory ? UNDEFINED_VALUE : warnings);
5582
5615
  }
5583
5616
  let writable, abortError, aborted;
5584
5617
  try {
@@ -5598,10 +5631,7 @@
5598
5631
  writer.size += writtenSize;
5599
5632
  }
5600
5633
  } catch (error) {
5601
- const { outputSize: failedOutputSize } = workerOptions;
5602
- if (failedOutputSize !== UNDEFINED_VALUE) {
5603
- writer.size += failedOutputSize;
5604
- } else if (isErrorObject(error) && error.outputSize !== UNDEFINED_VALUE) {
5634
+ if (isErrorObject(error) && error.outputSize !== UNDEFINED_VALUE) {
5605
5635
  writer.size += error.outputSize;
5606
5636
  }
5607
5637
  if (!checkPasswordOnly || !isErrorObject(error) || error.message != ERR_ABORT_CHECK_PASSWORD) {
@@ -5629,13 +5659,7 @@
5629
5659
  }
5630
5660
 
5631
5661
  function detectEncryptedCentralDirectory(directoryView) {
5632
- const maxOffset = Math.min(directoryView.byteLength, 1024) - 3;
5633
- for (let offset = 0; offset < maxOffset; offset++) {
5634
- if (getUint32$1(directoryView, offset) == ARCHIVE_EXTRA_DATA_SIGNATURE) {
5635
- return true;
5636
- }
5637
- }
5638
- return false;
5662
+ return directoryView.byteLength >= 4 && getUint32$1(directoryView, 0) == ARCHIVE_EXTRA_DATA_SIGNATURE;
5639
5663
  }
5640
5664
 
5641
5665
  function getWrappedFilesLength(directoryView, directoryArray, offset) {
@@ -5672,6 +5696,46 @@
5672
5696
  }
5673
5697
  }
5674
5698
 
5699
+ async function findZip64EndOfDirectoryOffset(reader, endOffset) {
5700
+ const startOffset = Math.max(0, endOffset - (ZIP64_END_OF_CENTRAL_DIR_LENGTH + MAX_16_BITS));
5701
+ const tailArray = await readUint8Array(reader, startOffset, endOffset - startOffset);
5702
+ const tailView = getDataView(tailArray);
5703
+ for (let indexByte = tailArray.length - ZIP64_END_OF_CENTRAL_DIR_LENGTH; indexByte >= 0; indexByte--) {
5704
+ if (getUint32$1(tailView, indexByte) == ZIP64_END_OF_CENTRAL_DIR_SIGNATURE &&
5705
+ indexByte + 12 + Number(tailView.getBigUint64(indexByte + 4, true)) == tailArray.length) {
5706
+ return startOffset + indexByte;
5707
+ }
5708
+ }
5709
+ }
5710
+
5711
+ function getFirstLocalHeaderOffset(directoryArray, directoryView) {
5712
+ if (directoryArray.length < CENTRAL_FILE_HEADER_LENGTH) {
5713
+ return UNDEFINED_VALUE;
5714
+ }
5715
+ const localHeaderOffset = getUint32$1(directoryView, 42);
5716
+ if (localHeaderOffset != MAX_32_BITS) {
5717
+ return localHeaderOffset;
5718
+ }
5719
+ let offsetExtraField = CENTRAL_FILE_HEADER_LENGTH + getUint16$1(directoryView, 28);
5720
+ const endExtraField = Math.min(offsetExtraField + getUint16$1(directoryView, 30), directoryArray.length);
5721
+ while (offsetExtraField + 4 <= endExtraField) {
5722
+ const type = getUint16$1(directoryView, offsetExtraField);
5723
+ const size = getUint16$1(directoryView, offsetExtraField + 2);
5724
+ if (type == EXTRAFIELD_TYPE_ZIP64) {
5725
+ let offsetValue = offsetExtraField + 4;
5726
+ if (getUint32$1(directoryView, 24) == MAX_32_BITS) {
5727
+ offsetValue += 8;
5728
+ }
5729
+ if (getUint32$1(directoryView, 20) == MAX_32_BITS) {
5730
+ offsetValue += 8;
5731
+ }
5732
+ return offsetValue + 8 <= endExtraField ? getBigUint64(directoryView, offsetValue) : UNDEFINED_VALUE;
5733
+ }
5734
+ offsetExtraField += 4 + size;
5735
+ }
5736
+ return UNDEFINED_VALUE;
5737
+ }
5738
+
5675
5739
  function readDigitalSignature(signatureRecordArray) {
5676
5740
  if (signatureRecordArray.length >= 6) {
5677
5741
  const signatureRecordView = getDataView(signatureRecordArray);
@@ -5761,6 +5825,7 @@
5761
5825
  uncompressedSize: getUint32$1(dataView, offset + HEADER_OFFSET_UNCOMPRESSED_SIZE)
5762
5826
  });
5763
5827
  const extraFieldZip64 = extraField.get(EXTRAFIELD_TYPE_ZIP64);
5828
+ let extraFieldZip64Missing;
5764
5829
  if (extraFieldZip64) {
5765
5830
  if (!readExtraFieldZip64(extraFieldZip64, directory, localDirectory)) {
5766
5831
  malformedExtraField = true;
@@ -5770,7 +5835,7 @@
5770
5835
  if (localDirectory) {
5771
5836
  malformedExtraField = true;
5772
5837
  } else {
5773
- throw new Error(ERR_EXTRAFIELD_ZIP64_NOT_FOUND);
5838
+ extraFieldZip64Missing = true;
5774
5839
  }
5775
5840
  }
5776
5841
  const extraFieldUnicodePath = extraField.get(EXTRAFIELD_TYPE_UNICODE_PATH);
@@ -5828,6 +5893,9 @@
5828
5893
  if (extraFieldUSDZ) {
5829
5894
  directory.extraFieldUSDZ = extraFieldUSDZ;
5830
5895
  }
5896
+ if (extraFieldZip64Missing) {
5897
+ throw new Error(ERR_EXTRAFIELD_ZIP64_NOT_FOUND);
5898
+ }
5831
5899
  return malformedExtraField;
5832
5900
  }
5833
5901
 
@@ -6042,13 +6110,7 @@
6042
6110
  let dataDescriptorLength = 0;
6043
6111
  if (dataDescriptor) {
6044
6112
  const zip64 = Boolean(extraFieldZip64);
6045
- const dataDescriptorArray = await readUint8Array(reader, dataOffset + compressedSize, DATA_DESCRIPTOR_RECORD_ZIP_64_LENGTH + DATA_DESCRIPTOR_RECORD_SIGNATURE_LENGTH);
6046
- const dataDescriptorView = getDataView(dataDescriptorArray);
6047
- const candidates = [[zip64, true], [zip64, false], [!zip64, true], [!zip64, false]]
6048
- .map(([zip64Layout, signature]) => readDataDescriptor(dataDescriptorView, zip64Layout, signature))
6049
- .filter(candidate => candidate && candidate.compressedSize == compressedSize && candidate.uncompressedSize == uncompressedSize);
6050
- const localDataDescriptor = candidates.find(candidate => candidate.crc32 == crc32) || candidates[0] ||
6051
- readDataDescriptor(dataDescriptorView, zip64, true) || readDataDescriptor(dataDescriptorView, zip64, false);
6113
+ const localDataDescriptor = await readLocalDataDescriptor(reader, dataOffset + compressedSize, { crc32, compressedSize, uncompressedSize, zip64 });
6052
6114
  if (localDataDescriptor) {
6053
6115
  fileEntry.localDirectory.dataDescriptor = localDataDescriptor;
6054
6116
  dataDescriptorLength = getDataDescriptorLength(localDataDescriptor.zip64, localDataDescriptor.signature);
@@ -6118,6 +6180,25 @@
6118
6180
  return mergedRanges;
6119
6181
  }
6120
6182
 
6183
+ async function readLocalDataDescriptor(reader, offset, { crc32, compressedSize, uncompressedSize, zip64 }) {
6184
+ const maxLength = DATA_DESCRIPTOR_RECORD_ZIP_64_LENGTH + DATA_DESCRIPTOR_RECORD_SIGNATURE_LENGTH;
6185
+ const length = Math.min(maxLength, Math.max(0, reader.size - offset));
6186
+ const dataDescriptorArray = length ? await readUint8Array(reader, offset, length) : EMPTY_UINT8_ARRAY;
6187
+ const dataDescriptorView = getDataView(dataDescriptorArray);
6188
+ const candidates = [[zip64, true], [zip64, false], [!zip64, true], [!zip64, false]]
6189
+ .map(([zip64Layout, signature]) => readDataDescriptor(dataDescriptorView, zip64Layout, signature))
6190
+ .filter(candidate => candidate && candidate.compressedSize == compressedSize && candidate.uncompressedSize == uncompressedSize);
6191
+ return candidates.find(candidate => candidate.crc32 == crc32) || candidates[0] ||
6192
+ readDataDescriptor(dataDescriptorView, zip64, true) || readDataDescriptor(dataDescriptorView, zip64, false);
6193
+ }
6194
+
6195
+ async function getEntryDataDescriptorLength(reader, offset, { crc32, compressedSize, uncompressedSize, extraFieldZip64 }) {
6196
+ const dataDescriptor = await readLocalDataDescriptor(reader, offset, { crc32, compressedSize, uncompressedSize, zip64: Boolean(extraFieldZip64) });
6197
+ if (dataDescriptor && dataDescriptor.compressedSize == compressedSize && dataDescriptor.uncompressedSize == uncompressedSize) {
6198
+ return getDataDescriptorLength(dataDescriptor.zip64, dataDescriptor.signature);
6199
+ }
6200
+ }
6201
+
6121
6202
  function readDataDescriptor(dataDescriptorView, zip64, signature) {
6122
6203
  const offset = signature ? DATA_DESCRIPTOR_RECORD_SIGNATURE_LENGTH : 0;
6123
6204
  if (dataDescriptorView.byteLength < getDataDescriptorLength(zip64, signature) ||
@@ -6377,6 +6458,18 @@
6377
6458
  }
6378
6459
  }
6379
6460
 
6461
+ function validateDataDescriptor(zipEntry, localDirectory, warnings) {
6462
+ const { dataDescriptor } = localDirectory;
6463
+ const maskedLocalDirectory = zipEntry.decryptedDirectory &&
6464
+ (localDirectory.rawBitFlag & BITFLAG_MASKED_LOCAL_HEADERS) == BITFLAG_MASKED_LOCAL_HEADERS;
6465
+ if (dataDescriptor && !maskedLocalDirectory &&
6466
+ ((zipEntry.crc32 !== UNDEFINED_VALUE && dataDescriptor.crc32 != zipEntry.crc32) ||
6467
+ dataDescriptor.compressedSize != zipEntry.compressedSize ||
6468
+ dataDescriptor.uncompressedSize != zipEntry.uncompressedSize)) {
6469
+ reportAmbiguity(!warnings, warnings, WARNING_MISMATCHED_LOCAL_FILE_HEADER_CRC32_OR_SIZES);
6470
+ }
6471
+ }
6472
+
6380
6473
  function reportAmbiguity(reject, warnings, reason) {
6381
6474
  if (reject) {
6382
6475
  throwAmbiguousArchive(reason);
@@ -6479,6 +6572,7 @@
6479
6572
  WARNING_WRAPPED_ENTRIES_COUNT: WARNING_WRAPPED_ENTRIES_COUNT,
6480
6573
  ZipReader: ZipReader,
6481
6574
  ZipReaderStream: ZipReaderStream,
6575
+ getEntryDataDescriptorLength: getEntryDataDescriptorLength,
6482
6576
  isZipFile: isZipFile
6483
6577
  });
6484
6578
 
@@ -6602,136 +6696,7 @@
6602
6696
  }
6603
6697
 
6604
6698
  appendZip(reader, options = {}) {
6605
- return watchPromiseError(this, this.appendZipEntries(reader, options));
6606
- }
6607
-
6608
- async appendZipEntries(reader, options = {}) {
6609
- const zipWriter = this;
6610
- const { pendingAddFileCalls, filenames, fileEntries } = zipWriter;
6611
- const filter = checkFunctionOption(options.filter);
6612
- while (pendingAddFileCalls.size) {
6613
- await Promise.allSettled(Array.from(pendingAddFileCalls));
6614
- }
6615
- let resolveAppendZip;
6616
- const promiseAppendZip = new Promise(resolve => resolveAppendZip = resolve);
6617
- pendingAddFileCalls.add(promiseAppendZip);
6618
- const appendedFilenames = [];
6619
- let releaseLockWriter;
6620
- try {
6621
- reader = new GenericReader(reader);
6622
- await initStream(reader);
6623
- if (reader.size === UNDEFINED_VALUE || !reader.readUint8Array) {
6624
- reader = new BlobReader(await streamToBlob(reader.readable));
6625
- await initStream(reader);
6626
- }
6627
- const { ZipReader } = await Promise.resolve().then(function () { return zipReader; });
6628
- const zipReader$1 = new ZipReader(reader);
6629
- const entries = await zipReader$1.getEntries();
6630
- const keptEntries = [];
6631
- for (const entry of entries) {
6632
- if (!filter || await filter(entry)) {
6633
- keptEntries.push(entry);
6634
- }
6635
- }
6636
- await zipReader$1.close();
6637
- await initStream(zipWriter.writer);
6638
- const { directoryOffset } = zipReader$1;
6639
- keptEntries.forEach(({ filename }) => {
6640
- if (filenames.has(filename)) {
6641
- throw new Error(ERR_DUPLICATED_NAME);
6642
- }
6643
- filenames.add(filename);
6644
- appendedFilenames.push(filename);
6645
- });
6646
- zipWriter.writerLocked = true;
6647
- const { lockWriter } = zipWriter;
6648
- zipWriter.lockWriter = new Promise(resolve => releaseLockWriter = () => {
6649
- zipWriter.writerLocked = false;
6650
- resolve();
6651
- });
6652
- await lockWriter;
6653
- if (zipWriter.addSplitZipSignature) {
6654
- delete zipWriter.addSplitZipSignature;
6655
- if (!await startsWithSplitZipSignature(reader)) {
6656
- await writeData(zipWriter.writer, getSplitZipSignatureArray());
6657
- zipWriter.offset += SPLIT_ZIP_FILE_SIGNATURE_LENGTH;
6658
- }
6659
- }
6660
- const entryPositions = await copyZipData(zipWriter, reader, entries, keptEntries, directoryOffset, Boolean(filter));
6661
- keptEntries.forEach(entry => {
6662
- const {
6663
- version,
6664
- rawLastModDate,
6665
- rawFilename,
6666
- bitFlag,
6667
- encrypted,
6668
- uncompressedSize,
6669
- compressedSize,
6670
- extraFieldZip64
6671
- } = entry;
6672
- let {
6673
- compressionMethod,
6674
- rawExtraField,
6675
- } = entry;
6676
- const { level, languageEncodingFlag, dataDescriptor } = bitFlag;
6677
- rawExtraField = removeExtraFieldZip64(rawExtraField || EMPTY_UINT8_ARRAY);
6678
- if (entry.extraFieldAES) {
6679
- compressionMethod = COMPRESSION_METHOD_AES;
6680
- }
6681
- const extraFieldLength = getLength(rawExtraField);
6682
- const zip64UncompressedSize = Boolean(extraFieldZip64) && extraFieldZip64.uncompressedSize !== UNDEFINED_VALUE;
6683
- const zip64CompressedSize = Boolean(extraFieldZip64) && extraFieldZip64.compressedSize !== UNDEFINED_VALUE;
6684
- const bitFlagValue = (getBitFlag(level, languageEncodingFlag, dataDescriptor, encrypted, compressionMethod) & ~BITFLAG_LEVEL) | (level << 1);
6685
- const {
6686
- headerArray,
6687
- headerView
6688
- } = getHeaderArrayData({
6689
- version,
6690
- bitFlag: bitFlagValue,
6691
- compressionMethod,
6692
- uncompressedSize,
6693
- compressedSize,
6694
- rawLastModDate,
6695
- rawFilename,
6696
- zip64CompressedSize,
6697
- zip64UncompressedSize,
6698
- extraFieldLength
6699
- });
6700
- const { crc32 } = entry;
6701
- if (crc32 !== UNDEFINED_VALUE) {
6702
- setUint32(headerView, HEADER_OFFSET_SIGNATURE, crc32);
6703
- }
6704
- const { offset, diskNumberStart } = entryPositions.get(entry);
6705
- Object.assign(entry, {
6706
- zip64Enabled: true,
6707
- zip64UncompressedSize,
6708
- zip64CompressedSize,
6709
- offset,
6710
- diskNumberStart,
6711
- zip64DiskNumberStart: false,
6712
- rawExtraFieldZip64: EMPTY_UINT8_ARRAY,
6713
- rawExtraFieldAES: EMPTY_UINT8_ARRAY,
6714
- rawExtraFieldExtendedTimestamp: EMPTY_UINT8_ARRAY,
6715
- rawExtraFieldNTFS: EMPTY_UINT8_ARRAY,
6716
- rawExtraFieldUnix: EMPTY_UINT8_ARRAY,
6717
- rawCentralExtraFieldUnix: EMPTY_UINT8_ARRAY,
6718
- rawExtraField,
6719
- rawCentralExtraField: EMPTY_UINT8_ARRAY,
6720
- headerArray,
6721
- headerView
6722
- });
6723
- fileEntries.set(entry.filename, entry);
6724
- });
6725
- } catch (error) {
6726
- appendedFilenames.forEach(filename => filenames.delete(filename));
6727
- throw error;
6728
- } finally {
6729
- resolveAppendZip();
6730
- pendingAddFileCalls.delete(promiseAppendZip);
6731
- if (releaseLockWriter) {
6732
- releaseLockWriter();
6733
- }
6734
- }
6699
+ return watchPromiseError(this, appendZipEntries(this, reader, options));
6735
6700
  }
6736
6701
 
6737
6702
  add(name = "", reader, options = {}) {
@@ -6893,11 +6858,149 @@
6893
6858
  return watchedPromise;
6894
6859
  }
6895
6860
 
6861
+ async function appendZipEntries(zipWriter, reader, options = {}) {
6862
+ const { pendingAddFileCalls, filenames, fileEntries } = zipWriter;
6863
+ const filter = checkFunctionOption(options.filter);
6864
+ const readerOptions = checkReaderOptionsObject(options.readerOptions);
6865
+ while (pendingAddFileCalls.size) {
6866
+ await Promise.allSettled(Array.from(pendingAddFileCalls));
6867
+ }
6868
+ let resolveAppendZip;
6869
+ const promiseAppendZip = new Promise(resolve => resolveAppendZip = resolve);
6870
+ pendingAddFileCalls.add(promiseAppendZip);
6871
+ const appendedFilenames = [];
6872
+ let releaseLockWriter;
6873
+ try {
6874
+ reader = new GenericReader(reader);
6875
+ await initStream(reader);
6876
+ if (reader.size === UNDEFINED_VALUE || !reader.readUint8Array) {
6877
+ reader = new BlobReader(await streamToBlob(reader.readable));
6878
+ await initStream(reader);
6879
+ }
6880
+ const { ZipReader, getEntryDataDescriptorLength } = await Promise.resolve().then(function () { return zipReader; });
6881
+ const zipReader$1 = new ZipReader(reader, readerOptions);
6882
+ const keptEntries = [];
6883
+ let entries;
6884
+ try {
6885
+ entries = await zipReader$1.getEntries();
6886
+ for (const entry of entries) {
6887
+ if (!filter || await filter(entry, getExistingEntry(fileEntries, entry.filename))) {
6888
+ keptEntries.push(entry);
6889
+ }
6890
+ }
6891
+ } finally {
6892
+ await zipReader$1.close();
6893
+ }
6894
+ await initStream(zipWriter.writer);
6895
+ const { directoryOffset, entriesMissingZip64ExtraField } = zipReader$1;
6896
+ keptEntries.forEach(entry => {
6897
+ const { filename } = entry;
6898
+ if (entriesMissingZip64ExtraField.has(entry)) {
6899
+ throw new Error(ERR_EXTRAFIELD_ZIP64_NOT_FOUND);
6900
+ }
6901
+ if (filenames.has(filename)) {
6902
+ throw new Error(ERR_DUPLICATED_NAME);
6903
+ }
6904
+ filenames.add(filename);
6905
+ appendedFilenames.push(filename);
6906
+ });
6907
+ zipWriter.writerLocked = true;
6908
+ const { lockWriter } = zipWriter;
6909
+ zipWriter.lockWriter = new Promise(resolve => releaseLockWriter = () => {
6910
+ zipWriter.writerLocked = false;
6911
+ resolve();
6912
+ });
6913
+ await lockWriter;
6914
+ if (zipWriter.addSplitZipSignature) {
6915
+ delete zipWriter.addSplitZipSignature;
6916
+ if (filter || !await startsWithSplitZipSignature(reader)) {
6917
+ await writeData(zipWriter.writer, getSplitZipSignatureArray());
6918
+ zipWriter.offset += SPLIT_ZIP_FILE_SIGNATURE_LENGTH;
6919
+ }
6920
+ }
6921
+ const entryPositions = await copyZipData(zipWriter, reader, entries, keptEntries, directoryOffset, Boolean(filter), getEntryDataDescriptorLength);
6922
+ keptEntries.forEach(entry => {
6923
+ const {
6924
+ version,
6925
+ rawLastModDate,
6926
+ rawFilename,
6927
+ rawBitFlag,
6928
+ uncompressedSize,
6929
+ compressedSize,
6930
+ extraFieldZip64
6931
+ } = entry;
6932
+ let {
6933
+ compressionMethod,
6934
+ rawExtraField,
6935
+ } = entry;
6936
+ rawExtraField = removeExtraFieldZip64(rawExtraField || EMPTY_UINT8_ARRAY);
6937
+ if (entry.extraFieldAES) {
6938
+ compressionMethod = COMPRESSION_METHOD_AES;
6939
+ }
6940
+ const extraFieldLength = getLength(rawExtraField);
6941
+ const zip64UncompressedSize = Boolean(extraFieldZip64) && extraFieldZip64.uncompressedSize !== UNDEFINED_VALUE;
6942
+ const zip64CompressedSize = Boolean(extraFieldZip64) && extraFieldZip64.compressedSize !== UNDEFINED_VALUE;
6943
+ const {
6944
+ headerArray,
6945
+ headerView
6946
+ } = getHeaderArrayData({
6947
+ version,
6948
+ bitFlag: rawBitFlag,
6949
+ compressionMethod,
6950
+ uncompressedSize,
6951
+ compressedSize,
6952
+ rawLastModDate,
6953
+ rawFilename,
6954
+ zip64CompressedSize,
6955
+ zip64UncompressedSize,
6956
+ extraFieldLength
6957
+ });
6958
+ const { crc32 } = entry;
6959
+ if (crc32 !== UNDEFINED_VALUE) {
6960
+ setUint32(headerView, HEADER_OFFSET_SIGNATURE, crc32);
6961
+ }
6962
+ const { offset, diskNumberStart } = entryPositions.get(entry);
6963
+ fileEntries.set(entry.filename, Object.assign({}, entry, {
6964
+ zip64Enabled: true,
6965
+ zip64UncompressedSize,
6966
+ zip64CompressedSize,
6967
+ offset,
6968
+ diskNumberStart,
6969
+ zip64DiskNumberStart: false,
6970
+ rawExtraFieldZip64: EMPTY_UINT8_ARRAY,
6971
+ rawExtraFieldAES: EMPTY_UINT8_ARRAY,
6972
+ rawExtraFieldExtendedTimestamp: EMPTY_UINT8_ARRAY,
6973
+ rawExtraFieldNTFS: EMPTY_UINT8_ARRAY,
6974
+ rawExtraFieldUnix: EMPTY_UINT8_ARRAY,
6975
+ rawCentralExtraFieldUnix: EMPTY_UINT8_ARRAY,
6976
+ rawExtraField,
6977
+ rawCentralExtraField: EMPTY_UINT8_ARRAY,
6978
+ headerArray,
6979
+ headerView
6980
+ }));
6981
+ });
6982
+ } catch (error) {
6983
+ appendedFilenames.forEach(filename => filenames.delete(filename));
6984
+ throw error;
6985
+ } finally {
6986
+ resolveAppendZip();
6987
+ pendingAddFileCalls.delete(promiseAppendZip);
6988
+ if (releaseLockWriter) {
6989
+ releaseLockWriter();
6990
+ }
6991
+ }
6992
+ }
6993
+
6994
+ function getExistingEntry(fileEntries, filename) {
6995
+ const fileEntry = fileEntries.get(filename);
6996
+ return fileEntry ? new Entry(fileEntry) : UNDEFINED_VALUE;
6997
+ }
6998
+
6896
6999
  async function prependZipEntries(zipWriter, reader) {
6897
7000
  if (zipWriter.filenames.size) {
6898
7001
  throw new Error(ERR_ZIP_NOT_EMPTY);
6899
7002
  }
6900
- await zipWriter.appendZipEntries(reader);
7003
+ await appendZipEntries(zipWriter, reader);
6901
7004
  }
6902
7005
 
6903
7006
  async function addFileEntry(zipWriter, name, reader, options) {
@@ -8571,7 +8674,7 @@
8571
8674
  return rawExtraField;
8572
8675
  }
8573
8676
 
8574
- async function copyZipData(zipWriter, reader, entries, keptEntries, directoryOffset, compact) {
8677
+ async function copyZipData(zipWriter, reader, entries, keptEntries, directoryOffset, compact, getEntryDataDescriptorLength) {
8575
8678
  const { writer } = zipWriter;
8576
8679
  const entryPositions = new Map();
8577
8680
  if (writer.closeDisk || compact) {
@@ -8579,6 +8682,27 @@
8579
8682
  getSourceOffset(reader, firstEntry) - getSourceOffset(reader, secondEntry));
8580
8683
  const regionEnds = getRegionEnds(reader, sortedEntries, directoryOffset);
8581
8684
  const keptEntrySet = new Set(keptEntries);
8685
+ const localHeaderLengths = new Map();
8686
+ for (let indexEntry = 0; indexEntry < sortedEntries.length; indexEntry++) {
8687
+ const entry = sortedEntries[indexEntry];
8688
+ if (keptEntrySet.has(entry)) {
8689
+ const sourceOffset = getSourceOffset(reader, entry);
8690
+ const localHeaderLength = await getLocalHeaderLength(reader, sourceOffset);
8691
+ if (localHeaderLength === UNDEFINED_VALUE) {
8692
+ throw new Error(ERR_LOCAL_FILE_HEADER_NOT_FOUND);
8693
+ }
8694
+ let entryEnd = sourceOffset + localHeaderLength + entry.compressedSize;
8695
+ if (entry.bitFlag.dataDescriptor) {
8696
+ const dataDescriptorLength = await getEntryDataDescriptorLength(reader, entryEnd, entry);
8697
+ entryEnd = dataDescriptorLength === UNDEFINED_VALUE ? Math.max(entryEnd, regionEnds[indexEntry]) : entryEnd + dataDescriptorLength;
8698
+ }
8699
+ if (entryEnd > regionEnds[indexEntry]) {
8700
+ throw new Error(ERR_OVERLAPPING_ENTRY);
8701
+ }
8702
+ regionEnds[indexEntry] = entryEnd;
8703
+ localHeaderLengths.set(entry, localHeaderLength);
8704
+ }
8705
+ }
8582
8706
  let copiedOffset = 0;
8583
8707
  let lastPosition;
8584
8708
  for (let indexEntry = 0; indexEntry < sortedEntries.length; indexEntry++) {
@@ -8591,7 +8715,7 @@
8591
8715
  if (!compact) {
8592
8716
  await copyData(zipWriter, reader, copiedOffset, sourceOffset - copiedOffset);
8593
8717
  }
8594
- if (writer.closeDisk && exceedsAvailableSize(writer, await getLocalHeaderLength(reader, sourceOffset))) {
8718
+ if (writer.closeDisk && exceedsAvailableSize(writer, localHeaderLengths.get(entry))) {
8595
8719
  await writer.closeDisk();
8596
8720
  }
8597
8721
  lastPosition = {
@@ -8625,7 +8749,7 @@
8625
8749
  const sourceOffset = getSourceOffset(reader, sortedEntries[indexEntry]);
8626
8750
  const nextEntry = sortedEntries[indexEntry + 1];
8627
8751
  if (nextEntry && getSourceOffset(reader, nextEntry) > sourceOffset) {
8628
- regionEnd = getSourceOffset(reader, nextEntry);
8752
+ regionEnd = Math.min(getSourceOffset(reader, nextEntry), directoryOffset);
8629
8753
  }
8630
8754
  regionEnds[indexEntry] = regionEnd;
8631
8755
  }
@@ -8639,11 +8763,13 @@
8639
8763
  try {
8640
8764
  await flushBufferedData(createReadable(reader, { offset, size }), writer, UNDEFINED_VALUE, chunkLength => copiedLength += chunkLength);
8641
8765
  } catch (error) {
8642
- zipWriter.hasCorruptedEntries = true;
8643
- try {
8644
- error.corruptedEntry = true;
8645
- } catch {
8646
- // ignored
8766
+ if (copiedLength) {
8767
+ zipWriter.hasCorruptedEntries = true;
8768
+ try {
8769
+ error.corruptedEntry = true;
8770
+ } catch {
8771
+ // ignored
8772
+ }
8647
8773
  }
8648
8774
  throw error;
8649
8775
  } finally {
@@ -8654,11 +8780,16 @@
8654
8780
  }
8655
8781
 
8656
8782
  async function getLocalHeaderLength(reader, offset) {
8657
- const headerArray = await readUint8Array(reader, offset, HEADER_SIZE);
8783
+ const headerArray = offset >= 0 && offset + HEADER_SIZE <= reader.size ?
8784
+ await readUint8Array(reader, offset, HEADER_SIZE) :
8785
+ EMPTY_UINT8_ARRAY;
8658
8786
  if (getLength(headerArray) < HEADER_SIZE) {
8659
- return HEADER_SIZE;
8787
+ return UNDEFINED_VALUE;
8660
8788
  }
8661
8789
  const headerView = getDataView(headerArray);
8790
+ if (getUint32(headerView, 0) != LOCAL_FILE_HEADER_SIGNATURE) {
8791
+ return UNDEFINED_VALUE;
8792
+ }
8662
8793
  return HEADER_SIZE +
8663
8794
  getUint16(headerView, HEADER_OFFSET_FILENAME_LENGTH + LOCAL_HEADER_COMMON_OFFSET) +
8664
8795
  getUint16(headerView, HEADER_OFFSET_EXTRAFIELD_LENGTH + LOCAL_HEADER_COMMON_OFFSET);
@@ -9009,7 +9140,7 @@
9009
9140
  EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
9010
9141
  */
9011
9142
 
9012
- const VERSION = "2.20.0";
9143
+ const VERSION = "2.22.0";
9013
9144
 
9014
9145
  /*
9015
9146
  Copyright (c) 2025 Gildas Lormeau. All rights reserved.
@@ -10122,6 +10253,7 @@
10122
10253
  exports.ERR_INVALID_PASSWORD_TYPE = ERR_INVALID_PASSWORD_TYPE;
10123
10254
  exports.ERR_INVALID_PASS_THROUGH_VALUE = ERR_INVALID_PASS_THROUGH_VALUE;
10124
10255
  exports.ERR_INVALID_READER = ERR_INVALID_READER;
10256
+ exports.ERR_INVALID_READER_OPTIONS = ERR_INVALID_READER_OPTIONS;
10125
10257
  exports.ERR_INVALID_SIGNAL = ERR_INVALID_SIGNAL;
10126
10258
  exports.ERR_INVALID_SIGNATURE_DATA = ERR_INVALID_SIGNATURE_DATA;
10127
10259
  exports.ERR_INVALID_STRICTNESS = ERR_INVALID_STRICTNESS;