@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.
@@ -117,6 +117,10 @@ const MIN_DATE = new Date(1980, 0, 1);
117
117
 
118
118
  const UNDEFINED_VALUE = undefined;
119
119
  const INFINITY_VALUE = Infinity;
120
+ const ERR_LOCAL_FILE_HEADER_NOT_FOUND = "Local file header not found";
121
+ const ERR_OVERLAPPING_ENTRY = "Overlapping entry found";
122
+ const ERR_EXTRAFIELD_ZIP64_NOT_FOUND = "Zip64 extra field not found";
123
+
120
124
  const UNDEFINED_TYPE = "undefined";
121
125
  const FUNCTION_TYPE = "function";
122
126
  const OBJECT_TYPE = "object";
@@ -212,6 +216,7 @@ const ERR_INVALID_FUNCTION_OPTION = "Invalid option (must be a function)";
212
216
  const ERR_INVALID_SIGNAL = "Invalid signal (must be an AbortSignal instance)";
213
217
  const ERR_INVALID_PASSWORD_TYPE = "Invalid password (password must be a string, rawPassword must be a Uint8Array)";
214
218
  const ERR_INVALID_PASS_THROUGH_VALUE = "Invalid passThrough option (must be a boolean or 'compressed')";
219
+ const ERR_INVALID_READER_OPTIONS = "Invalid readerOptions (must be an object)";
215
220
  const ERR_ABORTED = "The operation was aborted";
216
221
  const ABORT_ERROR_NAME = "AbortError";
217
222
 
@@ -222,6 +227,13 @@ function checkFunctionOption(value) {
222
227
  return value;
223
228
  }
224
229
 
230
+ function checkReaderOptionsObject(readerOptions) {
231
+ if (readerOptions && (typeof readerOptions != OBJECT_TYPE || Array.isArray(readerOptions))) {
232
+ throw new Error(ERR_INVALID_READER_OPTIONS);
233
+ }
234
+ return readerOptions;
235
+ }
236
+
225
237
  function checkSignalOption(signal) {
226
238
  if (signal && (typeof signal.addEventListener != FUNCTION_TYPE || typeof signal.aborted != BOOLEAN_TYPE)) {
227
239
  throw new Error(ERR_INVALID_SIGNAL);
@@ -317,7 +329,6 @@ const DEFAULT_CONFIGURATION = {
317
329
  workerStartupTimeout: 5000,
318
330
  useWebWorkers: true,
319
331
  useCompressionStream: true,
320
- transferStreams: true,
321
332
  CompressionStream: typeof CompressionStream != UNDEFINED_TYPE && CompressionStream,
322
333
  DecompressionStream: typeof DecompressionStream != UNDEFINED_TYPE && DecompressionStream
323
334
  };
@@ -331,8 +342,7 @@ const URI_PROPERTY_NAMES = [
331
342
  ];
332
343
  const BOOLEAN_PROPERTY_NAMES = [
333
344
  "useCompressionStream",
334
- "useWebWorkers",
335
- "transferStreams"
345
+ "useWebWorkers"
336
346
  ];
337
347
  const NUMBER_PROPERTY_NAMES = [
338
348
  "chunkSize",
@@ -4790,12 +4800,9 @@ const ERR_BAD_FORMAT = "File format is not recognized";
4790
4800
  const ERR_EOCDR_NOT_FOUND = "End of central directory not found";
4791
4801
  const ERR_EOCDR_LOCATOR_ZIP64_NOT_FOUND = "End of Zip64 central directory locator not found";
4792
4802
  const ERR_CENTRAL_DIRECTORY_NOT_FOUND = "Central directory header not found";
4793
- const ERR_LOCAL_FILE_HEADER_NOT_FOUND = "Local file header not found";
4794
- const ERR_EXTRAFIELD_ZIP64_NOT_FOUND = "Zip64 extra field not found";
4795
4803
  const ERR_ENCRYPTED = "File contains encrypted entry";
4796
4804
  const ERR_UNSUPPORTED_ENCRYPTION = "Encryption method not supported";
4797
4805
  const ERR_SPLIT_ZIP_FILE = "Split zip file";
4798
- const ERR_OVERLAPPING_ENTRY = "Overlapping entry found";
4799
4806
  const ERR_ENTRY_DATA_OUT_OF_BOUNDS = "Entry data out of bounds";
4800
4807
  const ERR_AMBIGUOUS_ARCHIVE = "Ambiguous archive";
4801
4808
  const ERR_ENCRYPTED_CENTRAL_DIRECTORY = "Encrypted central directory is not supported";
@@ -4859,8 +4866,9 @@ class ZipReader {
4859
4866
  constructor(reader, options = {}) {
4860
4867
  Object.assign(this, {
4861
4868
  reader: new GenericReader(reader),
4862
- options,
4863
- readRanges: { indexes: new Set(), sortedRanges: [], pendingRanges: [] }
4869
+ options: options || {},
4870
+ readRanges: { indexes: new Set(), sortedRanges: [], pendingRanges: [] },
4871
+ entriesMissingZip64ExtraField: new WeakSet()
4864
4872
  });
4865
4873
  }
4866
4874
 
@@ -4931,16 +4939,22 @@ class ZipReader {
4931
4939
  directoryDataOffset = getDiskOffset$1(reader, getUint32$1(endOfDirectoryLocatorView, 4)) + getBigUint64(endOfDirectoryLocatorView, 8);
4932
4940
  let endOfDirectoryArray = await readUint8Array(reader, directoryDataOffset, ZIP64_END_OF_CENTRAL_DIR_LENGTH);
4933
4941
  let endOfDirectoryView = getDataView(endOfDirectoryArray);
4934
- const expectedDirectoryDataOffset = endOfDirectoryInfo.offset - ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH - ZIP64_END_OF_CENTRAL_DIR_LENGTH;
4935
- if ((endOfDirectoryArray.length < ZIP64_END_OF_CENTRAL_DIR_LENGTH || getUint32$1(endOfDirectoryView, 0) != ZIP64_END_OF_CENTRAL_DIR_SIGNATURE) &&
4936
- directoryDataOffset != expectedDirectoryDataOffset && expectedDirectoryDataOffset >= 0) {
4937
- const originalDirectoryDataOffset = directoryDataOffset;
4938
- directoryDataOffset = expectedDirectoryDataOffset;
4939
- if (directoryDataOffset > originalDirectoryDataOffset) {
4940
- prependedDataLength = directoryDataOffset - originalDirectoryDataOffset;
4942
+ if (endOfDirectoryArray.length < ZIP64_END_OF_CENTRAL_DIR_LENGTH || getUint32$1(endOfDirectoryView, 0) != ZIP64_END_OF_CENTRAL_DIR_SIGNATURE) {
4943
+ const locatorOffset = endOfDirectoryInfo.offset - ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH;
4944
+ let expectedDirectoryDataOffset = locatorOffset - ZIP64_END_OF_CENTRAL_DIR_LENGTH;
4945
+ if (!await startsWithSignature(reader, expectedDirectoryDataOffset, ZIP64_END_OF_CENTRAL_DIR_SIGNATURE)) {
4946
+ expectedDirectoryDataOffset = await findZip64EndOfDirectoryOffset(reader, locatorOffset);
4947
+ }
4948
+ if (expectedDirectoryDataOffset !== UNDEFINED_VALUE && expectedDirectoryDataOffset >= 0 &&
4949
+ directoryDataOffset != expectedDirectoryDataOffset) {
4950
+ const originalDirectoryDataOffset = directoryDataOffset;
4951
+ directoryDataOffset = expectedDirectoryDataOffset;
4952
+ if (directoryDataOffset > originalDirectoryDataOffset) {
4953
+ prependedDataLength = directoryDataOffset - originalDirectoryDataOffset;
4954
+ }
4955
+ endOfDirectoryArray = await readUint8Array(reader, directoryDataOffset, ZIP64_END_OF_CENTRAL_DIR_LENGTH);
4956
+ endOfDirectoryView = getDataView(endOfDirectoryArray);
4941
4957
  }
4942
- endOfDirectoryArray = await readUint8Array(reader, directoryDataOffset, ZIP64_END_OF_CENTRAL_DIR_LENGTH);
4943
- endOfDirectoryView = getDataView(endOfDirectoryArray);
4944
4958
  }
4945
4959
  if (endOfDirectoryArray.length < ZIP64_END_OF_CENTRAL_DIR_LENGTH || getUint32$1(endOfDirectoryView, 0) != ZIP64_END_OF_CENTRAL_DIR_SIGNATURE) {
4946
4960
  throw new Error(ERR_EOCDR_LOCATOR_ZIP64_NOT_FOUND);
@@ -4985,10 +4999,6 @@ class ZipReader {
4985
4999
  let declaredDirectoryDataLength = directoryDataLength;
4986
5000
  const centralDirectoryEndOffset = endOfDirectoryInfo.offset -
4987
5001
  (zip64EndOfDirectory ? zip64EndOfDirectoryLength + ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH : 0);
4988
- if (directoryDataOffset >= reader.size) {
4989
- prependedDataLength = reader.size - directoryDataOffset - directoryDataLength - END_OF_CENTRAL_DIR_LENGTH;
4990
- directoryDataOffset = reader.size - directoryDataLength - END_OF_CENTRAL_DIR_LENGTH;
4991
- }
4992
5002
  if (expectedLastDiskNumber != lastDiskNumber) {
4993
5003
  throw new Error(ERR_SPLIT_ZIP_FILE);
4994
5004
  }
@@ -4996,52 +5006,64 @@ class ZipReader {
4996
5006
  throw new Error(ERR_BAD_FORMAT);
4997
5007
  }
4998
5008
  let offset = 0;
4999
- let directoryArray = await readUint8Array(reader, directoryDataOffset, directoryDataLength);
5009
+ let directoryArray = directoryDataOffset < reader.size ?
5010
+ await readUint8Array(reader, directoryDataOffset, directoryDataLength) :
5011
+ EMPTY_UINT8_ARRAY;
5000
5012
  let directoryView = getDataView(directoryArray);
5001
5013
  if (directoryDataLength) {
5002
- if (directoryArray.length < 4) {
5003
- throw new Error(ERR_BAD_FORMAT);
5004
- }
5005
5014
  let expectedDirectoryDataOffset = centralDirectoryEndOffset - directoryDataLength;
5006
5015
  if (directoryDataOffset != expectedDirectoryDataOffset && diskNumber == lastDiskNumber) {
5007
- const storedPointsAtDirectory = getUint32$1(directoryView, offset) == CENTRAL_FILE_HEADER_SIGNATURE ||
5016
+ const storedPointsAtDirectory = directoryArray.length >= 4 && (
5017
+ getUint32$1(directoryView, offset) == CENTRAL_FILE_HEADER_SIGNATURE ||
5008
5018
  Boolean(directoryEncryptionInfo && directoryEncryptionInfo.compressedSize) ||
5009
- detectEncryptedCentralDirectory(directoryView);
5019
+ detectEncryptedCentralDirectory(directoryView));
5020
+ if (!storedPointsAtDirectory && expectedDirectoryDataOffset < 0) {
5021
+ throw new Error(ERR_BAD_FORMAT);
5022
+ }
5010
5023
  let reconcile = !storedPointsAtDirectory;
5011
5024
  if (expectedDirectoryDataOffset >= 0 && expectedDirectoryDataOffset + 4 <= reader.size) {
5012
- const expectedPointsAtDirectory = await pointsAtDirectory(reader, expectedDirectoryDataOffset);
5013
- if (storedPointsAtDirectory) {
5014
- reconcile = expectedPointsAtDirectory;
5015
- } else if (!expectedPointsAtDirectory) {
5025
+ let expectedPointsAtDirectory = await pointsAtDirectory(reader, expectedDirectoryDataOffset);
5026
+ if (!expectedPointsAtDirectory) {
5016
5027
  const signatureRecordOffset = await findDigitalSignatureRecordOffset(reader, centralDirectoryEndOffset);
5017
5028
  const signedDirectoryDataOffset = signatureRecordOffset - directoryDataLength;
5018
5029
  if (signatureRecordOffset !== UNDEFINED_VALUE && signedDirectoryDataOffset >= 0 &&
5019
5030
  await pointsAtDirectory(reader, signedDirectoryDataOffset)) {
5020
5031
  expectedDirectoryDataOffset = signedDirectoryDataOffset;
5032
+ expectedPointsAtDirectory = true;
5021
5033
  }
5022
5034
  }
5035
+ if (storedPointsAtDirectory) {
5036
+ reconcile = expectedPointsAtDirectory;
5037
+ }
5023
5038
  }
5024
- if (reconcile) {
5039
+ if (reconcile && expectedDirectoryDataOffset != directoryDataOffset) {
5025
5040
  const originalDirectoryDataOffset = directoryDataOffset;
5026
5041
  directoryDataOffset = expectedDirectoryDataOffset;
5027
5042
  directoryArray = await readUint8Array(reader, directoryDataOffset, directoryDataLength);
5028
5043
  directoryView = getDataView(directoryArray);
5029
- if (directoryDataOffset > originalDirectoryDataOffset) {
5030
- prependedDataLength += directoryDataOffset - originalDirectoryDataOffset;
5044
+ const offsetDelta = directoryDataOffset - originalDirectoryDataOffset;
5045
+ const localHeaderOffset = getFirstLocalHeaderOffset(directoryArray, directoryView);
5046
+ const localHeaderFound = localHeaderOffset !== UNDEFINED_VALUE &&
5047
+ await startsWithSignature(reader, localHeaderOffset, LOCAL_FILE_HEADER_SIGNATURE);
5048
+ const shiftedLocalHeaderFound = localHeaderOffset !== UNDEFINED_VALUE &&
5049
+ await startsWithSignature(reader, localHeaderOffset + offsetDelta, LOCAL_FILE_HEADER_SIGNATURE);
5050
+ if (offsetDelta > 0 && !(localHeaderFound && !shiftedLocalHeaderFound)) {
5051
+ prependedDataLength += offsetDelta;
5031
5052
  prependedCentralDirectory = storedPointsAtDirectory;
5032
5053
  } else {
5033
5054
  reportAmbiguity(checkAmbiguity, warnings, WARNING_MISMATCHED_CENTRAL_DIRECTORY_OFFSET);
5034
- const offsetDelta = directoryDataOffset - originalDirectoryDataOffset;
5035
- if (directoryArray.length >= CENTRAL_FILE_HEADER_LENGTH) {
5036
- const localHeaderOffset = getUint32$1(directoryView, 42);
5037
- if (!await startsWithSignature(reader, localHeaderOffset, LOCAL_FILE_HEADER_SIGNATURE) &&
5038
- await startsWithSignature(reader, localHeaderOffset + offsetDelta, LOCAL_FILE_HEADER_SIGNATURE)) {
5039
- prependedDataLength += offsetDelta;
5040
- }
5055
+ if (offsetDelta < 0 && !localHeaderFound && shiftedLocalHeaderFound) {
5056
+ prependedDataLength += offsetDelta;
5041
5057
  }
5042
5058
  }
5043
5059
  }
5044
5060
  }
5061
+ if (directoryArray.length < 4) {
5062
+ throw new Error(ERR_BAD_FORMAT);
5063
+ }
5064
+ } else if (!filesLength && directoryDataOffset < centralDirectoryEndOffset && diskNumber == lastDiskNumber) {
5065
+ prependedDataLength += centralDirectoryEndOffset - directoryDataOffset;
5066
+ directoryDataOffset = centralDirectoryEndOffset;
5045
5067
  }
5046
5068
  const expectedDirectoryDataLength = centralDirectoryEndOffset - directoryDataOffset;
5047
5069
  if (directoryDataLength != expectedDirectoryDataLength && expectedDirectoryDataLength >= 0 && diskNumber == lastDiskNumber) {
@@ -5083,8 +5105,10 @@ class ZipReader {
5083
5105
  addWarning(warnings, WARNING_WRAPPED_ENTRIES_COUNT);
5084
5106
  }
5085
5107
  }
5108
+ const entryOptions = Object.assign({}, zipReader.options, options, { [OPTION_STRICTNESS]: strictness });
5109
+ delete entryOptions[OPTION_CHECK_AMBIGUITY];
5086
5110
  for (let indexFile = 0; indexFile < filesLength; indexFile++) {
5087
- const fileEntry = new ZipEntry(reader, zipReader.options);
5111
+ const fileEntry = new ZipEntry(reader, entryOptions);
5088
5112
  if (offset + CENTRAL_FILE_HEADER_LENGTH > directoryArray.length || getUint32$1(directoryView, offset) != CENTRAL_FILE_HEADER_SIGNATURE) {
5089
5113
  if (indexFile == 0 && !decryptedDirectory && (zip64EndOfDirectoryVersion2 || detectEncryptedCentralDirectory(directoryView))) {
5090
5114
  throw new Error(ERR_ENCRYPTED_CENTRAL_DIRECTORY);
@@ -5175,13 +5199,17 @@ class ZipReader {
5175
5199
  if (malformedExtraField) {
5176
5200
  addWarning(warnings, WARNING_MALFORMED_EXTRA_FIELD, filename);
5177
5201
  }
5178
- fileEntry.offset += prependedDataLength;
5179
- const entryPosition = getDiskOffset$1(reader, fileEntry.diskNumberStart) + fileEntry.offset;
5180
- startOffset = Math.min(entryPosition, startOffset);
5181
- if (entryPosition < previousEntryPosition) {
5182
- addWarning(warnings, WARNING_UNSORTED_CENTRAL_DIRECTORY, filename);
5202
+ if (fileEntry.zip64ExtraFieldMissing && fileEntry.offset == MAX_32_BITS) {
5203
+ startOffset = 0;
5204
+ } else {
5205
+ fileEntry.offset += prependedDataLength;
5206
+ const entryPosition = getDiskOffset$1(reader, fileEntry.diskNumberStart) + fileEntry.offset;
5207
+ startOffset = Math.min(entryPosition, startOffset);
5208
+ if (entryPosition < previousEntryPosition) {
5209
+ addWarning(warnings, WARNING_UNSORTED_CENTRAL_DIRECTORY, filename);
5210
+ }
5211
+ previousEntryPosition = entryPosition;
5183
5212
  }
5184
- previousEntryPosition = entryPosition;
5185
5213
  if ((fileEntry.version & MAX_8_BITS) > MAX_KNOWN_VERSION) {
5186
5214
  addWarning(warnings, WARNING_UNKNOWN_VERSION, filename);
5187
5215
  }
@@ -5218,12 +5246,15 @@ class ZipReader {
5218
5246
  zipCrypto: fileEntry.encrypted && !fileEntry.extraFieldAES
5219
5247
  });
5220
5248
  const entry = new Entry(fileEntry);
5221
- entry.getData = (writer, options) => fileEntry.getData(writer, entry, zipReader.readRanges, options);
5249
+ if (fileEntry.zip64ExtraFieldMissing) {
5250
+ zipReader.entriesMissingZip64ExtraField.add(entry);
5251
+ }
5252
+ entry.getData = (writer, options) => fileEntry.getData(writer, entry, zipReader, options);
5222
5253
  entry.arrayBuffer = async options => {
5223
5254
  const writer = new TransformStream();
5224
5255
  const arrayBufferPromise = streamToBlob(writer.readable).then(blob => blob.arrayBuffer());
5225
5256
  arrayBufferPromise.catch(() => { });
5226
- await fileEntry.getData(writer, entry, zipReader.readRanges,
5257
+ await fileEntry.getData(writer, entry, zipReader,
5227
5258
  Object.assign({}, options, { preventClose: false }));
5228
5259
  return arrayBufferPromise;
5229
5260
  };
@@ -5431,8 +5462,9 @@ class ZipEntry {
5431
5462
  });
5432
5463
  }
5433
5464
 
5434
- async getData(writer, fileEntry, readRanges, options = {}) {
5465
+ async getData(writer, fileEntry, zipReader, options = {}) {
5435
5466
  const zipEntry = this;
5467
+ const { readRanges, directoryOffset } = zipReader;
5436
5468
  if (zipEntry.zip64ExtraFieldMissing) {
5437
5469
  throw new Error(ERR_EXTRAFIELD_ZIP64_NOT_FOUND);
5438
5470
  }
@@ -5506,10 +5538,10 @@ class ZipEntry {
5506
5538
  }
5507
5539
  validateLocalDirectory(zipEntry, localDirectory, rawLocalFilename, checkLocalFilename, checkLocalDirectory ? UNDEFINED_VALUE : warnings);
5508
5540
  const { lastAccessDate, creationDate, uid, gid } = localDirectory;
5509
- if (lastAccessDate) {
5541
+ if (lastAccessDate && fileEntry.lastAccessDate === UNDEFINED_VALUE) {
5510
5542
  fileEntry.lastAccessDate = lastAccessDate;
5511
5543
  }
5512
- if (creationDate) {
5544
+ if (creationDate && fileEntry.creationDate === UNDEFINED_VALUE) {
5513
5545
  fileEntry.creationDate = creationDate;
5514
5546
  }
5515
5547
  if (uid !== UNDEFINED_VALUE && fileEntry.uid === UNDEFINED_VALUE) {
@@ -5538,7 +5570,7 @@ class ZipEntry {
5538
5570
  throw new Error(ERR_ENCRYPTED);
5539
5571
  }
5540
5572
  }
5541
- if (dataOffset + compressedSize > reader.size) {
5573
+ if (dataOffset + compressedSize > Math.min(reader.size, directoryOffset)) {
5542
5574
  throw new Error(ERR_ENTRY_DATA_OUT_OF_BOUNDS);
5543
5575
  }
5544
5576
  const size = compressedSize;
@@ -5604,6 +5636,7 @@ class ZipEntry {
5604
5636
  extraFieldZip64: extraFieldZip64 || localDirectory.extraFieldZip64,
5605
5637
  readRanges
5606
5638
  });
5639
+ validateDataDescriptor(zipEntry, localDirectory, checkLocalDirectory ? UNDEFINED_VALUE : warnings);
5607
5640
  }
5608
5641
  let writable, abortError, aborted;
5609
5642
  try {
@@ -5623,10 +5656,7 @@ class ZipEntry {
5623
5656
  writer.size += writtenSize;
5624
5657
  }
5625
5658
  } catch (error) {
5626
- const { outputSize: failedOutputSize } = workerOptions;
5627
- if (failedOutputSize !== UNDEFINED_VALUE) {
5628
- writer.size += failedOutputSize;
5629
- } else if (isErrorObject(error) && error.outputSize !== UNDEFINED_VALUE) {
5659
+ if (isErrorObject(error) && error.outputSize !== UNDEFINED_VALUE) {
5630
5660
  writer.size += error.outputSize;
5631
5661
  }
5632
5662
  if (!checkPasswordOnly || !isErrorObject(error) || error.message != ERR_ABORT_CHECK_PASSWORD) {
@@ -5654,13 +5684,7 @@ class ZipEntry {
5654
5684
  }
5655
5685
 
5656
5686
  function detectEncryptedCentralDirectory(directoryView) {
5657
- const maxOffset = Math.min(directoryView.byteLength, 1024) - 3;
5658
- for (let offset = 0; offset < maxOffset; offset++) {
5659
- if (getUint32$1(directoryView, offset) == ARCHIVE_EXTRA_DATA_SIGNATURE) {
5660
- return true;
5661
- }
5662
- }
5663
- return false;
5687
+ return directoryView.byteLength >= 4 && getUint32$1(directoryView, 0) == ARCHIVE_EXTRA_DATA_SIGNATURE;
5664
5688
  }
5665
5689
 
5666
5690
  function getWrappedFilesLength(directoryView, directoryArray, offset) {
@@ -5697,6 +5721,46 @@ async function findDigitalSignatureRecordOffset(reader, endOffset) {
5697
5721
  }
5698
5722
  }
5699
5723
 
5724
+ async function findZip64EndOfDirectoryOffset(reader, endOffset) {
5725
+ const startOffset = Math.max(0, endOffset - (ZIP64_END_OF_CENTRAL_DIR_LENGTH + MAX_16_BITS));
5726
+ const tailArray = await readUint8Array(reader, startOffset, endOffset - startOffset);
5727
+ const tailView = getDataView(tailArray);
5728
+ for (let indexByte = tailArray.length - ZIP64_END_OF_CENTRAL_DIR_LENGTH; indexByte >= 0; indexByte--) {
5729
+ if (getUint32$1(tailView, indexByte) == ZIP64_END_OF_CENTRAL_DIR_SIGNATURE &&
5730
+ indexByte + 12 + Number(tailView.getBigUint64(indexByte + 4, true)) == tailArray.length) {
5731
+ return startOffset + indexByte;
5732
+ }
5733
+ }
5734
+ }
5735
+
5736
+ function getFirstLocalHeaderOffset(directoryArray, directoryView) {
5737
+ if (directoryArray.length < CENTRAL_FILE_HEADER_LENGTH) {
5738
+ return UNDEFINED_VALUE;
5739
+ }
5740
+ const localHeaderOffset = getUint32$1(directoryView, 42);
5741
+ if (localHeaderOffset != MAX_32_BITS) {
5742
+ return localHeaderOffset;
5743
+ }
5744
+ let offsetExtraField = CENTRAL_FILE_HEADER_LENGTH + getUint16$1(directoryView, 28);
5745
+ const endExtraField = Math.min(offsetExtraField + getUint16$1(directoryView, 30), directoryArray.length);
5746
+ while (offsetExtraField + 4 <= endExtraField) {
5747
+ const type = getUint16$1(directoryView, offsetExtraField);
5748
+ const size = getUint16$1(directoryView, offsetExtraField + 2);
5749
+ if (type == EXTRAFIELD_TYPE_ZIP64) {
5750
+ let offsetValue = offsetExtraField + 4;
5751
+ if (getUint32$1(directoryView, 24) == MAX_32_BITS) {
5752
+ offsetValue += 8;
5753
+ }
5754
+ if (getUint32$1(directoryView, 20) == MAX_32_BITS) {
5755
+ offsetValue += 8;
5756
+ }
5757
+ return offsetValue + 8 <= endExtraField ? getBigUint64(directoryView, offsetValue) : UNDEFINED_VALUE;
5758
+ }
5759
+ offsetExtraField += 4 + size;
5760
+ }
5761
+ return UNDEFINED_VALUE;
5762
+ }
5763
+
5700
5764
  function readDigitalSignature(signatureRecordArray) {
5701
5765
  if (signatureRecordArray.length >= 6) {
5702
5766
  const signatureRecordView = getDataView(signatureRecordArray);
@@ -5786,6 +5850,7 @@ function readCommonFooter(fileEntry, directory, dataView, offset, localDirectory
5786
5850
  uncompressedSize: getUint32$1(dataView, offset + HEADER_OFFSET_UNCOMPRESSED_SIZE)
5787
5851
  });
5788
5852
  const extraFieldZip64 = extraField.get(EXTRAFIELD_TYPE_ZIP64);
5853
+ let extraFieldZip64Missing;
5789
5854
  if (extraFieldZip64) {
5790
5855
  if (!readExtraFieldZip64(extraFieldZip64, directory, localDirectory)) {
5791
5856
  malformedExtraField = true;
@@ -5795,7 +5860,7 @@ function readCommonFooter(fileEntry, directory, dataView, offset, localDirectory
5795
5860
  if (localDirectory) {
5796
5861
  malformedExtraField = true;
5797
5862
  } else {
5798
- throw new Error(ERR_EXTRAFIELD_ZIP64_NOT_FOUND);
5863
+ extraFieldZip64Missing = true;
5799
5864
  }
5800
5865
  }
5801
5866
  const extraFieldUnicodePath = extraField.get(EXTRAFIELD_TYPE_UNICODE_PATH);
@@ -5853,6 +5918,9 @@ function readCommonFooter(fileEntry, directory, dataView, offset, localDirectory
5853
5918
  if (extraFieldUSDZ) {
5854
5919
  directory.extraFieldUSDZ = extraFieldUSDZ;
5855
5920
  }
5921
+ if (extraFieldZip64Missing) {
5922
+ throw new Error(ERR_EXTRAFIELD_ZIP64_NOT_FOUND);
5923
+ }
5856
5924
  return malformedExtraField;
5857
5925
  }
5858
5926
 
@@ -6067,13 +6135,7 @@ async function detectOverlappingEntry({
6067
6135
  let dataDescriptorLength = 0;
6068
6136
  if (dataDescriptor) {
6069
6137
  const zip64 = Boolean(extraFieldZip64);
6070
- const dataDescriptorArray = await readUint8Array(reader, dataOffset + compressedSize, DATA_DESCRIPTOR_RECORD_ZIP_64_LENGTH + DATA_DESCRIPTOR_RECORD_SIGNATURE_LENGTH);
6071
- const dataDescriptorView = getDataView(dataDescriptorArray);
6072
- const candidates = [[zip64, true], [zip64, false], [!zip64, true], [!zip64, false]]
6073
- .map(([zip64Layout, signature]) => readDataDescriptor(dataDescriptorView, zip64Layout, signature))
6074
- .filter(candidate => candidate && candidate.compressedSize == compressedSize && candidate.uncompressedSize == uncompressedSize);
6075
- const localDataDescriptor = candidates.find(candidate => candidate.crc32 == crc32) || candidates[0] ||
6076
- readDataDescriptor(dataDescriptorView, zip64, true) || readDataDescriptor(dataDescriptorView, zip64, false);
6138
+ const localDataDescriptor = await readLocalDataDescriptor(reader, dataOffset + compressedSize, { crc32, compressedSize, uncompressedSize, zip64 });
6077
6139
  if (localDataDescriptor) {
6078
6140
  fileEntry.localDirectory.dataDescriptor = localDataDescriptor;
6079
6141
  dataDescriptorLength = getDataDescriptorLength(localDataDescriptor.zip64, localDataDescriptor.signature);
@@ -6143,6 +6205,25 @@ function mergeRanges(sortedRanges, pendingRanges) {
6143
6205
  return mergedRanges;
6144
6206
  }
6145
6207
 
6208
+ async function readLocalDataDescriptor(reader, offset, { crc32, compressedSize, uncompressedSize, zip64 }) {
6209
+ const maxLength = DATA_DESCRIPTOR_RECORD_ZIP_64_LENGTH + DATA_DESCRIPTOR_RECORD_SIGNATURE_LENGTH;
6210
+ const length = Math.min(maxLength, Math.max(0, reader.size - offset));
6211
+ const dataDescriptorArray = length ? await readUint8Array(reader, offset, length) : EMPTY_UINT8_ARRAY;
6212
+ const dataDescriptorView = getDataView(dataDescriptorArray);
6213
+ const candidates = [[zip64, true], [zip64, false], [!zip64, true], [!zip64, false]]
6214
+ .map(([zip64Layout, signature]) => readDataDescriptor(dataDescriptorView, zip64Layout, signature))
6215
+ .filter(candidate => candidate && candidate.compressedSize == compressedSize && candidate.uncompressedSize == uncompressedSize);
6216
+ return candidates.find(candidate => candidate.crc32 == crc32) || candidates[0] ||
6217
+ readDataDescriptor(dataDescriptorView, zip64, true) || readDataDescriptor(dataDescriptorView, zip64, false);
6218
+ }
6219
+
6220
+ async function getEntryDataDescriptorLength(reader, offset, { crc32, compressedSize, uncompressedSize, extraFieldZip64 }) {
6221
+ const dataDescriptor = await readLocalDataDescriptor(reader, offset, { crc32, compressedSize, uncompressedSize, zip64: Boolean(extraFieldZip64) });
6222
+ if (dataDescriptor && dataDescriptor.compressedSize == compressedSize && dataDescriptor.uncompressedSize == uncompressedSize) {
6223
+ return getDataDescriptorLength(dataDescriptor.zip64, dataDescriptor.signature);
6224
+ }
6225
+ }
6226
+
6146
6227
  function readDataDescriptor(dataDescriptorView, zip64, signature) {
6147
6228
  const offset = signature ? DATA_DESCRIPTOR_RECORD_SIGNATURE_LENGTH : 0;
6148
6229
  if (dataDescriptorView.byteLength < getDataDescriptorLength(zip64, signature) ||
@@ -6402,6 +6483,18 @@ function validateLocalDirectory(zipEntry, localDirectory, rawLocalFilename, chec
6402
6483
  }
6403
6484
  }
6404
6485
 
6486
+ function validateDataDescriptor(zipEntry, localDirectory, warnings) {
6487
+ const { dataDescriptor } = localDirectory;
6488
+ const maskedLocalDirectory = zipEntry.decryptedDirectory &&
6489
+ (localDirectory.rawBitFlag & BITFLAG_MASKED_LOCAL_HEADERS) == BITFLAG_MASKED_LOCAL_HEADERS;
6490
+ if (dataDescriptor && !maskedLocalDirectory &&
6491
+ ((zipEntry.crc32 !== UNDEFINED_VALUE && dataDescriptor.crc32 != zipEntry.crc32) ||
6492
+ dataDescriptor.compressedSize != zipEntry.compressedSize ||
6493
+ dataDescriptor.uncompressedSize != zipEntry.uncompressedSize)) {
6494
+ reportAmbiguity(!warnings, warnings, WARNING_MISMATCHED_LOCAL_FILE_HEADER_CRC32_OR_SIZES);
6495
+ }
6496
+ }
6497
+
6405
6498
  function reportAmbiguity(reject, warnings, reason) {
6406
6499
  if (reject) {
6407
6500
  throwAmbiguousArchive(reason);
@@ -6504,6 +6597,7 @@ var zipReader = /*#__PURE__*/Object.freeze({
6504
6597
  WARNING_WRAPPED_ENTRIES_COUNT: WARNING_WRAPPED_ENTRIES_COUNT,
6505
6598
  ZipReader: ZipReader,
6506
6599
  ZipReaderStream: ZipReaderStream,
6600
+ getEntryDataDescriptorLength: getEntryDataDescriptorLength,
6507
6601
  isZipFile: isZipFile
6508
6602
  });
6509
6603
 
@@ -6627,136 +6721,7 @@ class ZipWriter {
6627
6721
  }
6628
6722
 
6629
6723
  appendZip(reader, options = {}) {
6630
- return watchPromiseError(this, this.appendZipEntries(reader, options));
6631
- }
6632
-
6633
- async appendZipEntries(reader, options = {}) {
6634
- const zipWriter = this;
6635
- const { pendingAddFileCalls, filenames, fileEntries } = zipWriter;
6636
- const filter = checkFunctionOption(options.filter);
6637
- while (pendingAddFileCalls.size) {
6638
- await Promise.allSettled(Array.from(pendingAddFileCalls));
6639
- }
6640
- let resolveAppendZip;
6641
- const promiseAppendZip = new Promise(resolve => resolveAppendZip = resolve);
6642
- pendingAddFileCalls.add(promiseAppendZip);
6643
- const appendedFilenames = [];
6644
- let releaseLockWriter;
6645
- try {
6646
- reader = new GenericReader(reader);
6647
- await initStream(reader);
6648
- if (reader.size === UNDEFINED_VALUE || !reader.readUint8Array) {
6649
- reader = new BlobReader(await streamToBlob(reader.readable));
6650
- await initStream(reader);
6651
- }
6652
- const { ZipReader } = await Promise.resolve().then(function () { return zipReader; });
6653
- const zipReader$1 = new ZipReader(reader);
6654
- const entries = await zipReader$1.getEntries();
6655
- const keptEntries = [];
6656
- for (const entry of entries) {
6657
- if (!filter || await filter(entry)) {
6658
- keptEntries.push(entry);
6659
- }
6660
- }
6661
- await zipReader$1.close();
6662
- await initStream(zipWriter.writer);
6663
- const { directoryOffset } = zipReader$1;
6664
- keptEntries.forEach(({ filename }) => {
6665
- if (filenames.has(filename)) {
6666
- throw new Error(ERR_DUPLICATED_NAME);
6667
- }
6668
- filenames.add(filename);
6669
- appendedFilenames.push(filename);
6670
- });
6671
- zipWriter.writerLocked = true;
6672
- const { lockWriter } = zipWriter;
6673
- zipWriter.lockWriter = new Promise(resolve => releaseLockWriter = () => {
6674
- zipWriter.writerLocked = false;
6675
- resolve();
6676
- });
6677
- await lockWriter;
6678
- if (zipWriter.addSplitZipSignature) {
6679
- delete zipWriter.addSplitZipSignature;
6680
- if (!await startsWithSplitZipSignature(reader)) {
6681
- await writeData(zipWriter.writer, getSplitZipSignatureArray());
6682
- zipWriter.offset += SPLIT_ZIP_FILE_SIGNATURE_LENGTH;
6683
- }
6684
- }
6685
- const entryPositions = await copyZipData(zipWriter, reader, entries, keptEntries, directoryOffset, Boolean(filter));
6686
- keptEntries.forEach(entry => {
6687
- const {
6688
- version,
6689
- rawLastModDate,
6690
- rawFilename,
6691
- bitFlag,
6692
- encrypted,
6693
- uncompressedSize,
6694
- compressedSize,
6695
- extraFieldZip64
6696
- } = entry;
6697
- let {
6698
- compressionMethod,
6699
- rawExtraField,
6700
- } = entry;
6701
- const { level, languageEncodingFlag, dataDescriptor } = bitFlag;
6702
- rawExtraField = removeExtraFieldZip64(rawExtraField || EMPTY_UINT8_ARRAY);
6703
- if (entry.extraFieldAES) {
6704
- compressionMethod = COMPRESSION_METHOD_AES;
6705
- }
6706
- const extraFieldLength = getLength(rawExtraField);
6707
- const zip64UncompressedSize = Boolean(extraFieldZip64) && extraFieldZip64.uncompressedSize !== UNDEFINED_VALUE;
6708
- const zip64CompressedSize = Boolean(extraFieldZip64) && extraFieldZip64.compressedSize !== UNDEFINED_VALUE;
6709
- const bitFlagValue = (getBitFlag(level, languageEncodingFlag, dataDescriptor, encrypted, compressionMethod) & ~BITFLAG_LEVEL) | (level << 1);
6710
- const {
6711
- headerArray,
6712
- headerView
6713
- } = getHeaderArrayData({
6714
- version,
6715
- bitFlag: bitFlagValue,
6716
- compressionMethod,
6717
- uncompressedSize,
6718
- compressedSize,
6719
- rawLastModDate,
6720
- rawFilename,
6721
- zip64CompressedSize,
6722
- zip64UncompressedSize,
6723
- extraFieldLength
6724
- });
6725
- const { crc32 } = entry;
6726
- if (crc32 !== UNDEFINED_VALUE) {
6727
- setUint32(headerView, HEADER_OFFSET_SIGNATURE, crc32);
6728
- }
6729
- const { offset, diskNumberStart } = entryPositions.get(entry);
6730
- Object.assign(entry, {
6731
- zip64Enabled: true,
6732
- zip64UncompressedSize,
6733
- zip64CompressedSize,
6734
- offset,
6735
- diskNumberStart,
6736
- zip64DiskNumberStart: false,
6737
- rawExtraFieldZip64: EMPTY_UINT8_ARRAY,
6738
- rawExtraFieldAES: EMPTY_UINT8_ARRAY,
6739
- rawExtraFieldExtendedTimestamp: EMPTY_UINT8_ARRAY,
6740
- rawExtraFieldNTFS: EMPTY_UINT8_ARRAY,
6741
- rawExtraFieldUnix: EMPTY_UINT8_ARRAY,
6742
- rawCentralExtraFieldUnix: EMPTY_UINT8_ARRAY,
6743
- rawExtraField,
6744
- rawCentralExtraField: EMPTY_UINT8_ARRAY,
6745
- headerArray,
6746
- headerView
6747
- });
6748
- fileEntries.set(entry.filename, entry);
6749
- });
6750
- } catch (error) {
6751
- appendedFilenames.forEach(filename => filenames.delete(filename));
6752
- throw error;
6753
- } finally {
6754
- resolveAppendZip();
6755
- pendingAddFileCalls.delete(promiseAppendZip);
6756
- if (releaseLockWriter) {
6757
- releaseLockWriter();
6758
- }
6759
- }
6724
+ return watchPromiseError(this, appendZipEntries(this, reader, options));
6760
6725
  }
6761
6726
 
6762
6727
  add(name = "", reader, options = {}) {
@@ -6918,11 +6883,149 @@ function watchPromiseError(zipWriter, promise) {
6918
6883
  return watchedPromise;
6919
6884
  }
6920
6885
 
6886
+ async function appendZipEntries(zipWriter, reader, options = {}) {
6887
+ const { pendingAddFileCalls, filenames, fileEntries } = zipWriter;
6888
+ const filter = checkFunctionOption(options.filter);
6889
+ const readerOptions = checkReaderOptionsObject(options.readerOptions);
6890
+ while (pendingAddFileCalls.size) {
6891
+ await Promise.allSettled(Array.from(pendingAddFileCalls));
6892
+ }
6893
+ let resolveAppendZip;
6894
+ const promiseAppendZip = new Promise(resolve => resolveAppendZip = resolve);
6895
+ pendingAddFileCalls.add(promiseAppendZip);
6896
+ const appendedFilenames = [];
6897
+ let releaseLockWriter;
6898
+ try {
6899
+ reader = new GenericReader(reader);
6900
+ await initStream(reader);
6901
+ if (reader.size === UNDEFINED_VALUE || !reader.readUint8Array) {
6902
+ reader = new BlobReader(await streamToBlob(reader.readable));
6903
+ await initStream(reader);
6904
+ }
6905
+ const { ZipReader, getEntryDataDescriptorLength } = await Promise.resolve().then(function () { return zipReader; });
6906
+ const zipReader$1 = new ZipReader(reader, readerOptions);
6907
+ const keptEntries = [];
6908
+ let entries;
6909
+ try {
6910
+ entries = await zipReader$1.getEntries();
6911
+ for (const entry of entries) {
6912
+ if (!filter || await filter(entry, getExistingEntry(fileEntries, entry.filename))) {
6913
+ keptEntries.push(entry);
6914
+ }
6915
+ }
6916
+ } finally {
6917
+ await zipReader$1.close();
6918
+ }
6919
+ await initStream(zipWriter.writer);
6920
+ const { directoryOffset, entriesMissingZip64ExtraField } = zipReader$1;
6921
+ keptEntries.forEach(entry => {
6922
+ const { filename } = entry;
6923
+ if (entriesMissingZip64ExtraField.has(entry)) {
6924
+ throw new Error(ERR_EXTRAFIELD_ZIP64_NOT_FOUND);
6925
+ }
6926
+ if (filenames.has(filename)) {
6927
+ throw new Error(ERR_DUPLICATED_NAME);
6928
+ }
6929
+ filenames.add(filename);
6930
+ appendedFilenames.push(filename);
6931
+ });
6932
+ zipWriter.writerLocked = true;
6933
+ const { lockWriter } = zipWriter;
6934
+ zipWriter.lockWriter = new Promise(resolve => releaseLockWriter = () => {
6935
+ zipWriter.writerLocked = false;
6936
+ resolve();
6937
+ });
6938
+ await lockWriter;
6939
+ if (zipWriter.addSplitZipSignature) {
6940
+ delete zipWriter.addSplitZipSignature;
6941
+ if (filter || !await startsWithSplitZipSignature(reader)) {
6942
+ await writeData(zipWriter.writer, getSplitZipSignatureArray());
6943
+ zipWriter.offset += SPLIT_ZIP_FILE_SIGNATURE_LENGTH;
6944
+ }
6945
+ }
6946
+ const entryPositions = await copyZipData(zipWriter, reader, entries, keptEntries, directoryOffset, Boolean(filter), getEntryDataDescriptorLength);
6947
+ keptEntries.forEach(entry => {
6948
+ const {
6949
+ version,
6950
+ rawLastModDate,
6951
+ rawFilename,
6952
+ rawBitFlag,
6953
+ uncompressedSize,
6954
+ compressedSize,
6955
+ extraFieldZip64
6956
+ } = entry;
6957
+ let {
6958
+ compressionMethod,
6959
+ rawExtraField,
6960
+ } = entry;
6961
+ rawExtraField = removeExtraFieldZip64(rawExtraField || EMPTY_UINT8_ARRAY);
6962
+ if (entry.extraFieldAES) {
6963
+ compressionMethod = COMPRESSION_METHOD_AES;
6964
+ }
6965
+ const extraFieldLength = getLength(rawExtraField);
6966
+ const zip64UncompressedSize = Boolean(extraFieldZip64) && extraFieldZip64.uncompressedSize !== UNDEFINED_VALUE;
6967
+ const zip64CompressedSize = Boolean(extraFieldZip64) && extraFieldZip64.compressedSize !== UNDEFINED_VALUE;
6968
+ const {
6969
+ headerArray,
6970
+ headerView
6971
+ } = getHeaderArrayData({
6972
+ version,
6973
+ bitFlag: rawBitFlag,
6974
+ compressionMethod,
6975
+ uncompressedSize,
6976
+ compressedSize,
6977
+ rawLastModDate,
6978
+ rawFilename,
6979
+ zip64CompressedSize,
6980
+ zip64UncompressedSize,
6981
+ extraFieldLength
6982
+ });
6983
+ const { crc32 } = entry;
6984
+ if (crc32 !== UNDEFINED_VALUE) {
6985
+ setUint32(headerView, HEADER_OFFSET_SIGNATURE, crc32);
6986
+ }
6987
+ const { offset, diskNumberStart } = entryPositions.get(entry);
6988
+ fileEntries.set(entry.filename, Object.assign({}, entry, {
6989
+ zip64Enabled: true,
6990
+ zip64UncompressedSize,
6991
+ zip64CompressedSize,
6992
+ offset,
6993
+ diskNumberStart,
6994
+ zip64DiskNumberStart: false,
6995
+ rawExtraFieldZip64: EMPTY_UINT8_ARRAY,
6996
+ rawExtraFieldAES: EMPTY_UINT8_ARRAY,
6997
+ rawExtraFieldExtendedTimestamp: EMPTY_UINT8_ARRAY,
6998
+ rawExtraFieldNTFS: EMPTY_UINT8_ARRAY,
6999
+ rawExtraFieldUnix: EMPTY_UINT8_ARRAY,
7000
+ rawCentralExtraFieldUnix: EMPTY_UINT8_ARRAY,
7001
+ rawExtraField,
7002
+ rawCentralExtraField: EMPTY_UINT8_ARRAY,
7003
+ headerArray,
7004
+ headerView
7005
+ }));
7006
+ });
7007
+ } catch (error) {
7008
+ appendedFilenames.forEach(filename => filenames.delete(filename));
7009
+ throw error;
7010
+ } finally {
7011
+ resolveAppendZip();
7012
+ pendingAddFileCalls.delete(promiseAppendZip);
7013
+ if (releaseLockWriter) {
7014
+ releaseLockWriter();
7015
+ }
7016
+ }
7017
+ }
7018
+
7019
+ function getExistingEntry(fileEntries, filename) {
7020
+ const fileEntry = fileEntries.get(filename);
7021
+ return fileEntry ? new Entry(fileEntry) : UNDEFINED_VALUE;
7022
+ }
7023
+
6921
7024
  async function prependZipEntries(zipWriter, reader) {
6922
7025
  if (zipWriter.filenames.size) {
6923
7026
  throw new Error(ERR_ZIP_NOT_EMPTY);
6924
7027
  }
6925
- await zipWriter.appendZipEntries(reader);
7028
+ await appendZipEntries(zipWriter, reader);
6926
7029
  }
6927
7030
 
6928
7031
  async function addFileEntry(zipWriter, name, reader, options) {
@@ -8596,7 +8699,7 @@ function removeExtraFieldZip64(rawExtraField) {
8596
8699
  return rawExtraField;
8597
8700
  }
8598
8701
 
8599
- async function copyZipData(zipWriter, reader, entries, keptEntries, directoryOffset, compact) {
8702
+ async function copyZipData(zipWriter, reader, entries, keptEntries, directoryOffset, compact, getEntryDataDescriptorLength) {
8600
8703
  const { writer } = zipWriter;
8601
8704
  const entryPositions = new Map();
8602
8705
  if (writer.closeDisk || compact) {
@@ -8604,6 +8707,27 @@ async function copyZipData(zipWriter, reader, entries, keptEntries, directoryOff
8604
8707
  getSourceOffset(reader, firstEntry) - getSourceOffset(reader, secondEntry));
8605
8708
  const regionEnds = getRegionEnds(reader, sortedEntries, directoryOffset);
8606
8709
  const keptEntrySet = new Set(keptEntries);
8710
+ const localHeaderLengths = new Map();
8711
+ for (let indexEntry = 0; indexEntry < sortedEntries.length; indexEntry++) {
8712
+ const entry = sortedEntries[indexEntry];
8713
+ if (keptEntrySet.has(entry)) {
8714
+ const sourceOffset = getSourceOffset(reader, entry);
8715
+ const localHeaderLength = await getLocalHeaderLength(reader, sourceOffset);
8716
+ if (localHeaderLength === UNDEFINED_VALUE) {
8717
+ throw new Error(ERR_LOCAL_FILE_HEADER_NOT_FOUND);
8718
+ }
8719
+ let entryEnd = sourceOffset + localHeaderLength + entry.compressedSize;
8720
+ if (entry.bitFlag.dataDescriptor) {
8721
+ const dataDescriptorLength = await getEntryDataDescriptorLength(reader, entryEnd, entry);
8722
+ entryEnd = dataDescriptorLength === UNDEFINED_VALUE ? Math.max(entryEnd, regionEnds[indexEntry]) : entryEnd + dataDescriptorLength;
8723
+ }
8724
+ if (entryEnd > regionEnds[indexEntry]) {
8725
+ throw new Error(ERR_OVERLAPPING_ENTRY);
8726
+ }
8727
+ regionEnds[indexEntry] = entryEnd;
8728
+ localHeaderLengths.set(entry, localHeaderLength);
8729
+ }
8730
+ }
8607
8731
  let copiedOffset = 0;
8608
8732
  let lastPosition;
8609
8733
  for (let indexEntry = 0; indexEntry < sortedEntries.length; indexEntry++) {
@@ -8616,7 +8740,7 @@ async function copyZipData(zipWriter, reader, entries, keptEntries, directoryOff
8616
8740
  if (!compact) {
8617
8741
  await copyData(zipWriter, reader, copiedOffset, sourceOffset - copiedOffset);
8618
8742
  }
8619
- if (writer.closeDisk && exceedsAvailableSize(writer, await getLocalHeaderLength(reader, sourceOffset))) {
8743
+ if (writer.closeDisk && exceedsAvailableSize(writer, localHeaderLengths.get(entry))) {
8620
8744
  await writer.closeDisk();
8621
8745
  }
8622
8746
  lastPosition = {
@@ -8650,7 +8774,7 @@ function getRegionEnds(reader, sortedEntries, directoryOffset) {
8650
8774
  const sourceOffset = getSourceOffset(reader, sortedEntries[indexEntry]);
8651
8775
  const nextEntry = sortedEntries[indexEntry + 1];
8652
8776
  if (nextEntry && getSourceOffset(reader, nextEntry) > sourceOffset) {
8653
- regionEnd = getSourceOffset(reader, nextEntry);
8777
+ regionEnd = Math.min(getSourceOffset(reader, nextEntry), directoryOffset);
8654
8778
  }
8655
8779
  regionEnds[indexEntry] = regionEnd;
8656
8780
  }
@@ -8664,11 +8788,13 @@ async function copyData(zipWriter, reader, offset, size) {
8664
8788
  try {
8665
8789
  await flushBufferedData(createReadable(reader, { offset, size }), writer, UNDEFINED_VALUE, chunkLength => copiedLength += chunkLength);
8666
8790
  } catch (error) {
8667
- zipWriter.hasCorruptedEntries = true;
8668
- try {
8669
- error.corruptedEntry = true;
8670
- } catch {
8671
- // ignored
8791
+ if (copiedLength) {
8792
+ zipWriter.hasCorruptedEntries = true;
8793
+ try {
8794
+ error.corruptedEntry = true;
8795
+ } catch {
8796
+ // ignored
8797
+ }
8672
8798
  }
8673
8799
  throw error;
8674
8800
  } finally {
@@ -8679,11 +8805,16 @@ async function copyData(zipWriter, reader, offset, size) {
8679
8805
  }
8680
8806
 
8681
8807
  async function getLocalHeaderLength(reader, offset) {
8682
- const headerArray = await readUint8Array(reader, offset, HEADER_SIZE);
8808
+ const headerArray = offset >= 0 && offset + HEADER_SIZE <= reader.size ?
8809
+ await readUint8Array(reader, offset, HEADER_SIZE) :
8810
+ EMPTY_UINT8_ARRAY;
8683
8811
  if (getLength(headerArray) < HEADER_SIZE) {
8684
- return HEADER_SIZE;
8812
+ return UNDEFINED_VALUE;
8685
8813
  }
8686
8814
  const headerView = getDataView(headerArray);
8815
+ if (getUint32(headerView, 0) != LOCAL_FILE_HEADER_SIGNATURE) {
8816
+ return UNDEFINED_VALUE;
8817
+ }
8687
8818
  return HEADER_SIZE +
8688
8819
  getUint16(headerView, HEADER_OFFSET_FILENAME_LENGTH + LOCAL_HEADER_COMMON_OFFSET) +
8689
8820
  getUint16(headerView, HEADER_OFFSET_EXTRAFIELD_LENGTH + LOCAL_HEADER_COMMON_OFFSET);
@@ -9034,7 +9165,7 @@ function formatSupported(StreamClass, format) {
9034
9165
  EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
9035
9166
  */
9036
9167
 
9037
- const VERSION = "2.20.0";
9168
+ const VERSION = "2.22.0";
9038
9169
 
9039
9170
  /*
9040
9171
  Copyright (c) 2025 Gildas Lormeau. All rights reserved.
@@ -10039,4 +10170,4 @@ async function terminateWorkersAndModule() {
10039
10170
 
10040
10171
  configureExternalAssets();
10041
10172
 
10042
- export { BlobReader, BlobWriter, Data64URIReader, Data64URIWriter, ERR_ABORTED, ERR_AMBIGUOUS_ARCHIVE, ERR_BAD_FORMAT, ERR_CENTRAL_DIRECTORY_NOT_FOUND, ERR_CODEC_OUT_OF_MEMORY, ERR_DUPLICATED_NAME, ERR_ENCRYPTED, ERR_ENCRYPTED_CENTRAL_DIRECTORY, ERR_ENTRY_DATA_OUT_OF_BOUNDS, ERR_EOCDR_LOCATOR_ZIP64_NOT_FOUND, ERR_EOCDR_NOT_FOUND, ERR_EXTRAFIELD_ZIP64_NOT_FOUND, ERR_HTTP_RANGE, ERR_HTTP_RESOURCE_CHANGED, ERR_HTTP_STATUS, ERR_INVALID_AUTHENTICATION_CODE, ERR_INVALID_BASE_URI, ERR_INVALID_CODEC_DEFINITION, ERR_INVALID_CODEC_MODULE, ERR_INVALID_COMMENT, ERR_INVALID_COMMENT_TYPE, ERR_INVALID_COMPRESSED_DATA, ERR_INVALID_CRC32, ERR_INVALID_DATE, ERR_INVALID_ENCRYPTION_STRENGTH, ERR_INVALID_ENTRY, ERR_INVALID_ENTRY_COMMENT, ERR_INVALID_ENTRY_COMMENT_TYPE, ERR_INVALID_ENTRY_NAME, ERR_INVALID_EXTRAFIELD, ERR_INVALID_EXTRAFIELD_DATA, ERR_INVALID_EXTRAFIELD_DATA_TYPE, ERR_INVALID_EXTRAFIELD_TYPE, ERR_INVALID_FILENAME_VALIDATION, ERR_INVALID_FUNCTION_OPTION, ERR_INVALID_GID, ERR_INVALID_LEVEL, ERR_INVALID_MAX_APPENDED_DATA_SIZE, ERR_INVALID_MAX_WORKERS, ERR_INVALID_MSDOS_ATTRIBUTES, ERR_INVALID_MSDOS_DATA, ERR_INVALID_PASSWORD, ERR_INVALID_PASSWORD_TYPE, ERR_INVALID_PASS_THROUGH_VALUE, ERR_INVALID_READER, ERR_INVALID_SIGNAL, ERR_INVALID_SIGNATURE_DATA, ERR_INVALID_STRICTNESS, ERR_INVALID_UID, ERR_INVALID_UNCOMPRESSED_SIZE, ERR_INVALID_UNIX_EXTRA_FIELD_TYPE, ERR_INVALID_UNIX_ID_SIZE, ERR_INVALID_UNIX_MODE, ERR_INVALID_URI, ERR_INVALID_VERSION, ERR_ITERATOR_COMPLETED_TOO_SOON, ERR_LOCAL_FILE_HEADER_NOT_FOUND, ERR_OVERLAPPING_ENTRY, ERR_RESERVED_COMPRESSION_METHOD, ERR_SPLIT_ZIP_FILE, ERR_UNDEFINED_COMPRESSION_METHOD, ERR_UNDEFINED_CRC32, ERR_UNDEFINED_READER, ERR_UNDEFINED_UNCOMPRESSED_SIZE, ERR_UNDETERMINED_SIZE, ERR_UNSAFE_FILENAME, ERR_UNSUPPORTED_COMPRESSION, ERR_UNSUPPORTED_CONTEXT, ERR_UNSUPPORTED_CRYPTO_API, ERR_UNSUPPORTED_ENCRYPTION, ERR_UNSUPPORTED_ENCRYPTION_PASS_THROUGH, ERR_UNSUPPORTED_ENCRYPTION_USDZ, ERR_UNSUPPORTED_FORMAT, ERR_UNSUPPORTED_SPLIT_USDZ, ERR_UNSUPPORTED_UINT64, ERR_WORKER_STARTUP_TIMEOUT, ERR_WRITER_NOT_INITIALIZED, ERR_WRITER_SIZE_NOT_WRITABLE, ERR_ZIP_CRYPTO_LAST_MOD_DATE, ERR_ZIP_NOT_EMPTY, HttpRangeReader, HttpReader, Reader, SplitDataReader, SplitDataWriter, TextReader, TextWriter, Uint8ArrayReader, Uint8ArrayWriter, VERSION, WARNING_APPENDED_DATA, WARNING_CLAMPED_LAST_MODIFICATION_DATE, WARNING_COMPRESSED_PATCHED_DATA, WARNING_COMPRESSION_UNAVAILABLE, WARNING_DUPLICATE_FILENAME, WARNING_MALFORMED_EXTRA_FIELD, WARNING_MISMATCHED_CENTRAL_DIRECTORY_OFFSET, WARNING_MISMATCHED_LOCAL_FILE_HEADER_BIT_FLAG, WARNING_MISMATCHED_LOCAL_FILE_HEADER_COMPRESSION_METHOD, WARNING_MISMATCHED_LOCAL_FILE_HEADER_CRC32_OR_SIZES, WARNING_MISMATCHED_LOCAL_FILE_HEADER_FILENAME, WARNING_MISMATCHED_ZIP64_END_OF_CENTRAL_DIRECTORY, WARNING_MISSING_ZIP64_EXTRA_FIELD, WARNING_MULTIPLE_END_OF_CENTRAL_DIRECTORY, WARNING_PREPENDED_CENTRAL_DIRECTORY, WARNING_PREPENDED_DATA, WARNING_TRAILING_CENTRAL_DIRECTORY_DATA, WARNING_UNKNOWN_VERSION, WARNING_UNKNOWN_ZIP64_EXTENSIBLE_DATA, WARNING_UNSORTED_CENTRAL_DIRECTORY, WARNING_WRAPPED_ENTRIES_COUNT, Writer, ZipReader, ZipReaderStream, ZipWriter, ZipWriterStream, configure, createBlobTempStream, createOPFSTempStream, createSyncAccessHandleTempStream, getMimeType, getRegisteredCodecs, getSupportedCompressionMethods, isZipFile, registerCodec, resetConfiguration, terminateWorkersAndModule as terminateWorkers, unregisterCodec };
10173
+ export { BlobReader, BlobWriter, Data64URIReader, Data64URIWriter, ERR_ABORTED, ERR_AMBIGUOUS_ARCHIVE, ERR_BAD_FORMAT, ERR_CENTRAL_DIRECTORY_NOT_FOUND, ERR_CODEC_OUT_OF_MEMORY, ERR_DUPLICATED_NAME, ERR_ENCRYPTED, ERR_ENCRYPTED_CENTRAL_DIRECTORY, ERR_ENTRY_DATA_OUT_OF_BOUNDS, ERR_EOCDR_LOCATOR_ZIP64_NOT_FOUND, ERR_EOCDR_NOT_FOUND, ERR_EXTRAFIELD_ZIP64_NOT_FOUND, ERR_HTTP_RANGE, ERR_HTTP_RESOURCE_CHANGED, ERR_HTTP_STATUS, ERR_INVALID_AUTHENTICATION_CODE, ERR_INVALID_BASE_URI, ERR_INVALID_CODEC_DEFINITION, ERR_INVALID_CODEC_MODULE, ERR_INVALID_COMMENT, ERR_INVALID_COMMENT_TYPE, ERR_INVALID_COMPRESSED_DATA, ERR_INVALID_CRC32, ERR_INVALID_DATE, ERR_INVALID_ENCRYPTION_STRENGTH, ERR_INVALID_ENTRY, ERR_INVALID_ENTRY_COMMENT, ERR_INVALID_ENTRY_COMMENT_TYPE, ERR_INVALID_ENTRY_NAME, ERR_INVALID_EXTRAFIELD, ERR_INVALID_EXTRAFIELD_DATA, ERR_INVALID_EXTRAFIELD_DATA_TYPE, ERR_INVALID_EXTRAFIELD_TYPE, ERR_INVALID_FILENAME_VALIDATION, ERR_INVALID_FUNCTION_OPTION, ERR_INVALID_GID, ERR_INVALID_LEVEL, ERR_INVALID_MAX_APPENDED_DATA_SIZE, ERR_INVALID_MAX_WORKERS, ERR_INVALID_MSDOS_ATTRIBUTES, ERR_INVALID_MSDOS_DATA, ERR_INVALID_PASSWORD, ERR_INVALID_PASSWORD_TYPE, ERR_INVALID_PASS_THROUGH_VALUE, ERR_INVALID_READER, ERR_INVALID_READER_OPTIONS, ERR_INVALID_SIGNAL, ERR_INVALID_SIGNATURE_DATA, ERR_INVALID_STRICTNESS, ERR_INVALID_UID, ERR_INVALID_UNCOMPRESSED_SIZE, ERR_INVALID_UNIX_EXTRA_FIELD_TYPE, ERR_INVALID_UNIX_ID_SIZE, ERR_INVALID_UNIX_MODE, ERR_INVALID_URI, ERR_INVALID_VERSION, ERR_ITERATOR_COMPLETED_TOO_SOON, ERR_LOCAL_FILE_HEADER_NOT_FOUND, ERR_OVERLAPPING_ENTRY, ERR_RESERVED_COMPRESSION_METHOD, ERR_SPLIT_ZIP_FILE, ERR_UNDEFINED_COMPRESSION_METHOD, ERR_UNDEFINED_CRC32, ERR_UNDEFINED_READER, ERR_UNDEFINED_UNCOMPRESSED_SIZE, ERR_UNDETERMINED_SIZE, ERR_UNSAFE_FILENAME, ERR_UNSUPPORTED_COMPRESSION, ERR_UNSUPPORTED_CONTEXT, ERR_UNSUPPORTED_CRYPTO_API, ERR_UNSUPPORTED_ENCRYPTION, ERR_UNSUPPORTED_ENCRYPTION_PASS_THROUGH, ERR_UNSUPPORTED_ENCRYPTION_USDZ, ERR_UNSUPPORTED_FORMAT, ERR_UNSUPPORTED_SPLIT_USDZ, ERR_UNSUPPORTED_UINT64, ERR_WORKER_STARTUP_TIMEOUT, ERR_WRITER_NOT_INITIALIZED, ERR_WRITER_SIZE_NOT_WRITABLE, ERR_ZIP_CRYPTO_LAST_MOD_DATE, ERR_ZIP_NOT_EMPTY, HttpRangeReader, HttpReader, Reader, SplitDataReader, SplitDataWriter, TextReader, TextWriter, Uint8ArrayReader, Uint8ArrayWriter, VERSION, WARNING_APPENDED_DATA, WARNING_CLAMPED_LAST_MODIFICATION_DATE, WARNING_COMPRESSED_PATCHED_DATA, WARNING_COMPRESSION_UNAVAILABLE, WARNING_DUPLICATE_FILENAME, WARNING_MALFORMED_EXTRA_FIELD, WARNING_MISMATCHED_CENTRAL_DIRECTORY_OFFSET, WARNING_MISMATCHED_LOCAL_FILE_HEADER_BIT_FLAG, WARNING_MISMATCHED_LOCAL_FILE_HEADER_COMPRESSION_METHOD, WARNING_MISMATCHED_LOCAL_FILE_HEADER_CRC32_OR_SIZES, WARNING_MISMATCHED_LOCAL_FILE_HEADER_FILENAME, WARNING_MISMATCHED_ZIP64_END_OF_CENTRAL_DIRECTORY, WARNING_MISSING_ZIP64_EXTRA_FIELD, WARNING_MULTIPLE_END_OF_CENTRAL_DIRECTORY, WARNING_PREPENDED_CENTRAL_DIRECTORY, WARNING_PREPENDED_DATA, WARNING_TRAILING_CENTRAL_DIRECTORY_DATA, WARNING_UNKNOWN_VERSION, WARNING_UNKNOWN_ZIP64_EXTENSIBLE_DATA, WARNING_UNSORTED_CENTRAL_DIRECTORY, WARNING_WRAPPED_ENTRIES_COUNT, Writer, ZipReader, ZipReaderStream, ZipWriter, ZipWriterStream, configure, createBlobTempStream, createOPFSTempStream, createSyncAccessHandleTempStream, getMimeType, getRegisteredCodecs, getSupportedCompressionMethods, isZipFile, registerCodec, resetConfiguration, terminateWorkersAndModule as terminateWorkers, unregisterCodec };