@zip.js/zip.js 2.19.0 → 2.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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";
@@ -4765,12 +4769,9 @@
4765
4769
  const ERR_EOCDR_NOT_FOUND = "End of central directory not found";
4766
4770
  const ERR_EOCDR_LOCATOR_ZIP64_NOT_FOUND = "End of Zip64 central directory locator not found";
4767
4771
  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
4772
  const ERR_ENCRYPTED = "File contains encrypted entry";
4771
4773
  const ERR_UNSUPPORTED_ENCRYPTION = "Encryption method not supported";
4772
4774
  const ERR_SPLIT_ZIP_FILE = "Split zip file";
4773
- const ERR_OVERLAPPING_ENTRY = "Overlapping entry found";
4774
4775
  const ERR_ENTRY_DATA_OUT_OF_BOUNDS = "Entry data out of bounds";
4775
4776
  const ERR_AMBIGUOUS_ARCHIVE = "Ambiguous archive";
4776
4777
  const ERR_ENCRYPTED_CENTRAL_DIRECTORY = "Encrypted central directory is not supported";
@@ -4789,6 +4790,8 @@
4789
4790
  const WARNING_PREPENDED_DATA = "prepended data";
4790
4791
  const WARNING_PREPENDED_CENTRAL_DIRECTORY = "prepended central directory";
4791
4792
  const WARNING_TRAILING_CENTRAL_DIRECTORY_DATA = "trailing central directory data";
4793
+ const WARNING_MISMATCHED_CENTRAL_DIRECTORY_OFFSET = "mismatched central directory offset";
4794
+ const WARNING_MISSING_ZIP64_EXTRA_FIELD = "missing zip64 extra field";
4792
4795
  const WARNING_DUPLICATE_FILENAME = "duplicate filename";
4793
4796
  const WARNING_MISMATCHED_ZIP64_END_OF_CENTRAL_DIRECTORY = "mismatched zip64 end of central directory record";
4794
4797
  const WARNING_MULTIPLE_END_OF_CENTRAL_DIRECTORY = "multiple end of central directory records";
@@ -4833,7 +4836,8 @@
4833
4836
  Object.assign(this, {
4834
4837
  reader: new GenericReader(reader),
4835
4838
  options,
4836
- readRanges: { indexes: new Set(), sortedRanges: [], pendingRanges: [] }
4839
+ readRanges: { indexes: new Set(), sortedRanges: [], pendingRanges: [] },
4840
+ entriesMissingZip64ExtraField: new WeakSet()
4837
4841
  });
4838
4842
  }
4839
4843
 
@@ -4904,16 +4908,22 @@
4904
4908
  directoryDataOffset = getDiskOffset$1(reader, getUint32$1(endOfDirectoryLocatorView, 4)) + getBigUint64(endOfDirectoryLocatorView, 8);
4905
4909
  let endOfDirectoryArray = await readUint8Array(reader, directoryDataOffset, ZIP64_END_OF_CENTRAL_DIR_LENGTH);
4906
4910
  let endOfDirectoryView = getDataView(endOfDirectoryArray);
4907
- const expectedDirectoryDataOffset = endOfDirectoryInfo.offset - ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH - ZIP64_END_OF_CENTRAL_DIR_LENGTH;
4908
- if ((endOfDirectoryArray.length < ZIP64_END_OF_CENTRAL_DIR_LENGTH || getUint32$1(endOfDirectoryView, 0) != ZIP64_END_OF_CENTRAL_DIR_SIGNATURE) &&
4909
- directoryDataOffset != expectedDirectoryDataOffset && expectedDirectoryDataOffset >= 0) {
4910
- const originalDirectoryDataOffset = directoryDataOffset;
4911
- directoryDataOffset = expectedDirectoryDataOffset;
4912
- if (directoryDataOffset > originalDirectoryDataOffset) {
4913
- prependedDataLength = directoryDataOffset - originalDirectoryDataOffset;
4911
+ if (endOfDirectoryArray.length < ZIP64_END_OF_CENTRAL_DIR_LENGTH || getUint32$1(endOfDirectoryView, 0) != ZIP64_END_OF_CENTRAL_DIR_SIGNATURE) {
4912
+ const locatorOffset = endOfDirectoryInfo.offset - ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH;
4913
+ let expectedDirectoryDataOffset = locatorOffset - ZIP64_END_OF_CENTRAL_DIR_LENGTH;
4914
+ if (!await startsWithSignature(reader, expectedDirectoryDataOffset, ZIP64_END_OF_CENTRAL_DIR_SIGNATURE)) {
4915
+ expectedDirectoryDataOffset = await findZip64EndOfDirectoryOffset(reader, locatorOffset);
4916
+ }
4917
+ if (expectedDirectoryDataOffset !== UNDEFINED_VALUE && expectedDirectoryDataOffset >= 0 &&
4918
+ directoryDataOffset != expectedDirectoryDataOffset) {
4919
+ const originalDirectoryDataOffset = directoryDataOffset;
4920
+ directoryDataOffset = expectedDirectoryDataOffset;
4921
+ if (directoryDataOffset > originalDirectoryDataOffset) {
4922
+ prependedDataLength = directoryDataOffset - originalDirectoryDataOffset;
4923
+ }
4924
+ endOfDirectoryArray = await readUint8Array(reader, directoryDataOffset, ZIP64_END_OF_CENTRAL_DIR_LENGTH);
4925
+ endOfDirectoryView = getDataView(endOfDirectoryArray);
4914
4926
  }
4915
- endOfDirectoryArray = await readUint8Array(reader, directoryDataOffset, ZIP64_END_OF_CENTRAL_DIR_LENGTH);
4916
- endOfDirectoryView = getDataView(endOfDirectoryArray);
4917
4927
  }
4918
4928
  if (endOfDirectoryArray.length < ZIP64_END_OF_CENTRAL_DIR_LENGTH || getUint32$1(endOfDirectoryView, 0) != ZIP64_END_OF_CENTRAL_DIR_SIGNATURE) {
4919
4929
  throw new Error(ERR_EOCDR_LOCATOR_ZIP64_NOT_FOUND);
@@ -4951,15 +4961,13 @@
4951
4961
  reportAmbiguity(checkAmbiguity, warnings, WARNING_MISMATCHED_ZIP64_END_OF_CENTRAL_DIRECTORY);
4952
4962
  }
4953
4963
  directoryDataOffset = getDiskOffset$1(reader, diskNumber) + getBigUint64(endOfDirectoryView, 48) + prependedDataLength;
4964
+ } else if (directoryDataOffset == MAX_32_BITS || directoryDataLength == MAX_32_BITS || diskNumber == MAX_16_BITS) {
4965
+ throw new Error(ERR_EOCDR_LOCATOR_ZIP64_NOT_FOUND);
4954
4966
  }
4955
4967
  }
4956
4968
  let declaredDirectoryDataLength = directoryDataLength;
4957
4969
  const centralDirectoryEndOffset = endOfDirectoryInfo.offset -
4958
4970
  (zip64EndOfDirectory ? zip64EndOfDirectoryLength + ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH : 0);
4959
- if (directoryDataOffset >= reader.size) {
4960
- prependedDataLength = reader.size - directoryDataOffset - directoryDataLength - END_OF_CENTRAL_DIR_LENGTH;
4961
- directoryDataOffset = reader.size - directoryDataLength - END_OF_CENTRAL_DIR_LENGTH;
4962
- }
4963
4971
  if (expectedLastDiskNumber != lastDiskNumber) {
4964
4972
  throw new Error(ERR_SPLIT_ZIP_FILE);
4965
4973
  }
@@ -4967,33 +4975,64 @@
4967
4975
  throw new Error(ERR_BAD_FORMAT);
4968
4976
  }
4969
4977
  let offset = 0;
4970
- let directoryArray = await readUint8Array(reader, directoryDataOffset, directoryDataLength);
4978
+ let directoryArray = directoryDataOffset < reader.size ?
4979
+ await readUint8Array(reader, directoryDataOffset, directoryDataLength) :
4980
+ EMPTY_UINT8_ARRAY;
4971
4981
  let directoryView = getDataView(directoryArray);
4972
4982
  if (directoryDataLength) {
4973
- if (directoryArray.length < 4) {
4974
- throw new Error(ERR_BAD_FORMAT);
4975
- }
4976
- const expectedDirectoryDataOffset = centralDirectoryEndOffset - directoryDataLength;
4983
+ let expectedDirectoryDataOffset = centralDirectoryEndOffset - directoryDataLength;
4977
4984
  if (directoryDataOffset != expectedDirectoryDataOffset && diskNumber == lastDiskNumber) {
4978
- const storedPointsAtDirectory = getUint32$1(directoryView, offset) == CENTRAL_FILE_HEADER_SIGNATURE ||
4985
+ const storedPointsAtDirectory = directoryArray.length >= 4 && (
4986
+ getUint32$1(directoryView, offset) == CENTRAL_FILE_HEADER_SIGNATURE ||
4979
4987
  Boolean(directoryEncryptionInfo && directoryEncryptionInfo.compressedSize) ||
4980
- detectEncryptedCentralDirectory(directoryView);
4988
+ detectEncryptedCentralDirectory(directoryView));
4989
+ if (!storedPointsAtDirectory && expectedDirectoryDataOffset < 0) {
4990
+ throw new Error(ERR_BAD_FORMAT);
4991
+ }
4981
4992
  let reconcile = !storedPointsAtDirectory;
4982
- if (!reconcile && expectedDirectoryDataOffset >= 0 && expectedDirectoryDataOffset + 4 <= reader.size) {
4983
- const expectedSignatureArray = await readUint8Array(reader, expectedDirectoryDataOffset, 4);
4984
- reconcile = getUint32$1(getDataView(expectedSignatureArray), 0) == CENTRAL_FILE_HEADER_SIGNATURE;
4993
+ if (expectedDirectoryDataOffset >= 0 && expectedDirectoryDataOffset + 4 <= reader.size) {
4994
+ let expectedPointsAtDirectory = await pointsAtDirectory(reader, expectedDirectoryDataOffset);
4995
+ if (!expectedPointsAtDirectory) {
4996
+ const signatureRecordOffset = await findDigitalSignatureRecordOffset(reader, centralDirectoryEndOffset);
4997
+ const signedDirectoryDataOffset = signatureRecordOffset - directoryDataLength;
4998
+ if (signatureRecordOffset !== UNDEFINED_VALUE && signedDirectoryDataOffset >= 0 &&
4999
+ await pointsAtDirectory(reader, signedDirectoryDataOffset)) {
5000
+ expectedDirectoryDataOffset = signedDirectoryDataOffset;
5001
+ expectedPointsAtDirectory = true;
5002
+ }
5003
+ }
5004
+ if (storedPointsAtDirectory) {
5005
+ reconcile = expectedPointsAtDirectory;
5006
+ }
4985
5007
  }
4986
- if (reconcile) {
5008
+ if (reconcile && expectedDirectoryDataOffset != directoryDataOffset) {
4987
5009
  const originalDirectoryDataOffset = directoryDataOffset;
4988
5010
  directoryDataOffset = expectedDirectoryDataOffset;
4989
- if (directoryDataOffset > originalDirectoryDataOffset) {
4990
- prependedDataLength += directoryDataOffset - originalDirectoryDataOffset;
4991
- prependedCentralDirectory = storedPointsAtDirectory;
4992
- }
4993
5011
  directoryArray = await readUint8Array(reader, directoryDataOffset, directoryDataLength);
4994
5012
  directoryView = getDataView(directoryArray);
5013
+ const offsetDelta = directoryDataOffset - originalDirectoryDataOffset;
5014
+ const localHeaderOffset = getFirstLocalHeaderOffset(directoryArray, directoryView);
5015
+ const localHeaderFound = localHeaderOffset !== UNDEFINED_VALUE &&
5016
+ await startsWithSignature(reader, localHeaderOffset, LOCAL_FILE_HEADER_SIGNATURE);
5017
+ const shiftedLocalHeaderFound = localHeaderOffset !== UNDEFINED_VALUE &&
5018
+ await startsWithSignature(reader, localHeaderOffset + offsetDelta, LOCAL_FILE_HEADER_SIGNATURE);
5019
+ if (offsetDelta > 0 && !(localHeaderFound && !shiftedLocalHeaderFound)) {
5020
+ prependedDataLength += offsetDelta;
5021
+ prependedCentralDirectory = storedPointsAtDirectory;
5022
+ } else {
5023
+ reportAmbiguity(checkAmbiguity, warnings, WARNING_MISMATCHED_CENTRAL_DIRECTORY_OFFSET);
5024
+ if (offsetDelta < 0 && !localHeaderFound && shiftedLocalHeaderFound) {
5025
+ prependedDataLength += offsetDelta;
5026
+ }
5027
+ }
4995
5028
  }
4996
5029
  }
5030
+ if (directoryArray.length < 4) {
5031
+ throw new Error(ERR_BAD_FORMAT);
5032
+ }
5033
+ } else if (!filesLength && directoryDataOffset < centralDirectoryEndOffset && diskNumber == lastDiskNumber) {
5034
+ prependedDataLength += centralDirectoryEndOffset - directoryDataOffset;
5035
+ directoryDataOffset = centralDirectoryEndOffset;
4997
5036
  }
4998
5037
  const expectedDirectoryDataLength = centralDirectoryEndOffset - directoryDataOffset;
4999
5038
  if (directoryDataLength != expectedDirectoryDataLength && expectedDirectoryDataLength >= 0 && diskNumber == lastDiskNumber) {
@@ -5035,8 +5074,10 @@
5035
5074
  addWarning(warnings, WARNING_WRAPPED_ENTRIES_COUNT);
5036
5075
  }
5037
5076
  }
5077
+ const entryOptions = Object.assign({}, zipReader.options, options, { [OPTION_STRICTNESS]: strictness });
5078
+ delete entryOptions[OPTION_CHECK_AMBIGUITY];
5038
5079
  for (let indexFile = 0; indexFile < filesLength; indexFile++) {
5039
- const fileEntry = new ZipEntry(reader, zipReader.options);
5080
+ const fileEntry = new ZipEntry(reader, entryOptions);
5040
5081
  if (offset + CENTRAL_FILE_HEADER_LENGTH > directoryArray.length || getUint32$1(directoryView, offset) != CENTRAL_FILE_HEADER_SIGNATURE) {
5041
5082
  if (indexFile == 0 && !decryptedDirectory && (zip64EndOfDirectoryVersion2 || detectEncryptedCentralDirectory(directoryView))) {
5042
5083
  throw new Error(ERR_ENCRYPTED_CENTRAL_DIRECTORY);
@@ -5102,7 +5143,16 @@
5102
5143
  filename,
5103
5144
  comment
5104
5145
  });
5105
- const malformedExtraField = readCommonFooter(fileEntry, fileEntry, directoryView, offset + 6);
5146
+ let malformedExtraField;
5147
+ try {
5148
+ malformedExtraField = readCommonFooter(fileEntry, fileEntry, directoryView, offset + 6);
5149
+ } catch (error) {
5150
+ if (checkAmbiguity || error.message != ERR_EXTRAFIELD_ZIP64_NOT_FOUND) {
5151
+ throw error;
5152
+ }
5153
+ fileEntry.zip64ExtraFieldMissing = true;
5154
+ addWarning(warnings, WARNING_MISSING_ZIP64_EXTRA_FIELD, fileEntry.filename);
5155
+ }
5106
5156
  filename = fileEntry.filename;
5107
5157
  if (normalizeFilename) {
5108
5158
  const normalizedFilename = normalizeFilename(filename);
@@ -5118,13 +5168,17 @@
5118
5168
  if (malformedExtraField) {
5119
5169
  addWarning(warnings, WARNING_MALFORMED_EXTRA_FIELD, filename);
5120
5170
  }
5121
- fileEntry.offset += prependedDataLength;
5122
- const entryPosition = getDiskOffset$1(reader, fileEntry.diskNumberStart) + fileEntry.offset;
5123
- startOffset = Math.min(entryPosition, startOffset);
5124
- if (entryPosition < previousEntryPosition) {
5125
- addWarning(warnings, WARNING_UNSORTED_CENTRAL_DIRECTORY, filename);
5171
+ if (fileEntry.zip64ExtraFieldMissing && fileEntry.offset == MAX_32_BITS) {
5172
+ startOffset = 0;
5173
+ } else {
5174
+ fileEntry.offset += prependedDataLength;
5175
+ const entryPosition = getDiskOffset$1(reader, fileEntry.diskNumberStart) + fileEntry.offset;
5176
+ startOffset = Math.min(entryPosition, startOffset);
5177
+ if (entryPosition < previousEntryPosition) {
5178
+ addWarning(warnings, WARNING_UNSORTED_CENTRAL_DIRECTORY, filename);
5179
+ }
5180
+ previousEntryPosition = entryPosition;
5126
5181
  }
5127
- previousEntryPosition = entryPosition;
5128
5182
  if ((fileEntry.version & MAX_8_BITS) > MAX_KNOWN_VERSION) {
5129
5183
  addWarning(warnings, WARNING_UNKNOWN_VERSION, filename);
5130
5184
  }
@@ -5144,11 +5198,12 @@
5144
5198
  const sticky = Boolean(fileEntry.unixMode & FILE_ATTR_UNIX_STICKY_MASK);
5145
5199
  const unixType = fileEntry.unixMode === UNDEFINED_VALUE ? unixExternalUpper : fileEntry.unixMode;
5146
5200
  const symlink = (unixType & FILE_ATTR_UNIX_TYPE_MASK) == FILE_ATTR_UNIX_TYPE_SYMLINK;
5147
- const executable = !symlink && ((fileEntry.unixMode !== UNDEFINED_VALUE)
5148
- ? ((fileEntry.unixMode & FILE_ATTR_UNIX_EXECUTABLE_MASK) != 0)
5149
- : (unixCompatible && ((unixExternalUpper & FILE_ATTR_UNIX_EXECUTABLE_MASK) != 0)));
5150
5201
  const modeIsDir = fileEntry.unixMode !== UNDEFINED_VALUE && ((fileEntry.unixMode & FILE_ATTR_UNIX_TYPE_MASK) == FILE_ATTR_UNIX_TYPE_DIR);
5151
5202
  const upperIsDir = ((unixExternalUpper & FILE_ATTR_UNIX_TYPE_MASK) == FILE_ATTR_UNIX_TYPE_DIR);
5203
+ const directory = modeIsDir || upperIsDir || (msDosCompatible && msdosAttributes.directory) || fileEntry.filename.endsWith(DIRECTORY_SIGNATURE);
5204
+ const executable = !symlink && !directory && ((fileEntry.unixMode !== UNDEFINED_VALUE)
5205
+ ? ((fileEntry.unixMode & FILE_ATTR_UNIX_EXECUTABLE_MASK) != 0)
5206
+ : (unixCompatible && ((unixExternalUpper & FILE_ATTR_UNIX_EXECUTABLE_MASK) != 0)));
5152
5207
  Object.assign(fileEntry, {
5153
5208
  setuid,
5154
5209
  setgid,
@@ -5156,16 +5211,19 @@
5156
5211
  symlink,
5157
5212
  unixExternalUpper,
5158
5213
  executable,
5159
- directory: modeIsDir || upperIsDir || (msDosCompatible && msdosAttributes.directory) || fileEntry.filename.endsWith(DIRECTORY_SIGNATURE),
5214
+ directory,
5160
5215
  zipCrypto: fileEntry.encrypted && !fileEntry.extraFieldAES
5161
5216
  });
5162
5217
  const entry = new Entry(fileEntry);
5163
- entry.getData = (writer, options) => fileEntry.getData(writer, entry, zipReader.readRanges, options);
5218
+ if (fileEntry.zip64ExtraFieldMissing) {
5219
+ zipReader.entriesMissingZip64ExtraField.add(entry);
5220
+ }
5221
+ entry.getData = (writer, options) => fileEntry.getData(writer, entry, zipReader, options);
5164
5222
  entry.arrayBuffer = async options => {
5165
5223
  const writer = new TransformStream();
5166
5224
  const arrayBufferPromise = streamToBlob(writer.readable).then(blob => blob.arrayBuffer());
5167
5225
  arrayBufferPromise.catch(() => { });
5168
- await fileEntry.getData(writer, entry, zipReader.readRanges,
5226
+ await fileEntry.getData(writer, entry, zipReader,
5169
5227
  Object.assign({}, options, { preventClose: false }));
5170
5228
  return arrayBufferPromise;
5171
5229
  };
@@ -5212,10 +5270,10 @@
5212
5270
  const extractAppendedData = getOptionValue$1(zipReader, options, OPTION_EXTRACT_APPENDED_DATA);
5213
5271
  const splitZipSignatureLength = (checkAmbiguity || extractPrependedData) && filesLength &&
5214
5272
  startOffset == SPLIT_ZIP_FILE_SIGNATURE_LENGTH && await startsWithSplitZipMarker(reader) ? SPLIT_ZIP_FILE_SIGNATURE_LENGTH : 0;
5215
- if (checkAmbiguity && (prependedDataLength || (filesLength && startOffset > splitZipSignatureLength))) {
5273
+ if (checkAmbiguity && (prependedDataLength > 0 || (filesLength && startOffset > splitZipSignatureLength))) {
5216
5274
  throwAmbiguousArchive(WARNING_PREPENDED_DATA);
5217
5275
  }
5218
- if (prependedDataLength || (filesLength && startOffset > SPLIT_ZIP_FILE_SIGNATURE_LENGTH)) {
5276
+ if (prependedDataLength > 0 || (filesLength && startOffset > SPLIT_ZIP_FILE_SIGNATURE_LENGTH)) {
5219
5277
  addWarning(warnings, WARNING_PREPENDED_DATA);
5220
5278
  }
5221
5279
  if (prependedCentralDirectory) {
@@ -5373,8 +5431,12 @@
5373
5431
  });
5374
5432
  }
5375
5433
 
5376
- async getData(writer, fileEntry, readRanges, options = {}) {
5434
+ async getData(writer, fileEntry, zipReader, options = {}) {
5377
5435
  const zipEntry = this;
5436
+ const { readRanges, directoryOffset } = zipReader;
5437
+ if (zipEntry.zip64ExtraFieldMissing) {
5438
+ throw new Error(ERR_EXTRAFIELD_ZIP64_NOT_FOUND);
5439
+ }
5378
5440
  const config = getConfiguration();
5379
5441
  const {
5380
5442
  reader,
@@ -5445,10 +5507,10 @@
5445
5507
  }
5446
5508
  validateLocalDirectory(zipEntry, localDirectory, rawLocalFilename, checkLocalFilename, checkLocalDirectory ? UNDEFINED_VALUE : warnings);
5447
5509
  const { lastAccessDate, creationDate, uid, gid } = localDirectory;
5448
- if (lastAccessDate) {
5510
+ if (lastAccessDate && fileEntry.lastAccessDate === UNDEFINED_VALUE) {
5449
5511
  fileEntry.lastAccessDate = lastAccessDate;
5450
5512
  }
5451
- if (creationDate) {
5513
+ if (creationDate && fileEntry.creationDate === UNDEFINED_VALUE) {
5452
5514
  fileEntry.creationDate = creationDate;
5453
5515
  }
5454
5516
  if (uid !== UNDEFINED_VALUE && fileEntry.uid === UNDEFINED_VALUE) {
@@ -5477,7 +5539,7 @@
5477
5539
  throw new Error(ERR_ENCRYPTED);
5478
5540
  }
5479
5541
  }
5480
- if (dataOffset + compressedSize > reader.size) {
5542
+ if (dataOffset + compressedSize > Math.min(reader.size, directoryOffset)) {
5481
5543
  throw new Error(ERR_ENTRY_DATA_OUT_OF_BOUNDS);
5482
5544
  }
5483
5545
  const size = compressedSize;
@@ -5543,6 +5605,7 @@
5543
5605
  extraFieldZip64: extraFieldZip64 || localDirectory.extraFieldZip64,
5544
5606
  readRanges
5545
5607
  });
5608
+ validateDataDescriptor(zipEntry, localDirectory, checkLocalDirectory ? UNDEFINED_VALUE : warnings);
5546
5609
  }
5547
5610
  let writable, abortError, aborted;
5548
5611
  try {
@@ -5562,10 +5625,7 @@
5562
5625
  writer.size += writtenSize;
5563
5626
  }
5564
5627
  } catch (error) {
5565
- const { outputSize: failedOutputSize } = workerOptions;
5566
- if (failedOutputSize !== UNDEFINED_VALUE) {
5567
- writer.size += failedOutputSize;
5568
- } else if (isErrorObject(error) && error.outputSize !== UNDEFINED_VALUE) {
5628
+ if (isErrorObject(error) && error.outputSize !== UNDEFINED_VALUE) {
5569
5629
  writer.size += error.outputSize;
5570
5630
  }
5571
5631
  if (!checkPasswordOnly || !isErrorObject(error) || error.message != ERR_ABORT_CHECK_PASSWORD) {
@@ -5593,13 +5653,7 @@
5593
5653
  }
5594
5654
 
5595
5655
  function detectEncryptedCentralDirectory(directoryView) {
5596
- const maxOffset = Math.min(directoryView.byteLength, 1024) - 3;
5597
- for (let offset = 0; offset < maxOffset; offset++) {
5598
- if (getUint32$1(directoryView, offset) == ARCHIVE_EXTRA_DATA_SIGNATURE) {
5599
- return true;
5600
- }
5601
- }
5602
- return false;
5656
+ return directoryView.byteLength >= 4 && getUint32$1(directoryView, 0) == ARCHIVE_EXTRA_DATA_SIGNATURE;
5603
5657
  }
5604
5658
 
5605
5659
  function getWrappedFilesLength(directoryView, directoryArray, offset) {
@@ -5612,6 +5666,70 @@
5612
5666
  return wrappedFilesLength % (MAX_16_BITS + 1) ? 0 : wrappedFilesLength;
5613
5667
  }
5614
5668
 
5669
+ function pointsAtDirectory(reader, offset) {
5670
+ return startsWithSignature(reader, offset, CENTRAL_FILE_HEADER_SIGNATURE);
5671
+ }
5672
+
5673
+ async function startsWithSignature(reader, offset, signature) {
5674
+ if (offset < 0 || offset + 4 > reader.size) {
5675
+ return false;
5676
+ }
5677
+ const signatureArray = await readUint8Array(reader, offset, 4);
5678
+ return getUint32$1(getDataView(signatureArray), 0) == signature;
5679
+ }
5680
+
5681
+ async function findDigitalSignatureRecordOffset(reader, endOffset) {
5682
+ const startOffset = Math.max(0, endOffset - (6 + MAX_16_BITS));
5683
+ const tailArray = await readUint8Array(reader, startOffset, endOffset - startOffset);
5684
+ const tailView = getDataView(tailArray);
5685
+ for (let indexByte = tailArray.length - 6; indexByte >= 0; indexByte--) {
5686
+ if (getUint32$1(tailView, indexByte) == DIGITAL_SIGNATURE_RECORD_SIGNATURE &&
5687
+ indexByte + 6 + getUint16$1(tailView, indexByte + 4) == tailArray.length) {
5688
+ return startOffset + indexByte;
5689
+ }
5690
+ }
5691
+ }
5692
+
5693
+ async function findZip64EndOfDirectoryOffset(reader, endOffset) {
5694
+ const startOffset = Math.max(0, endOffset - (ZIP64_END_OF_CENTRAL_DIR_LENGTH + MAX_16_BITS));
5695
+ const tailArray = await readUint8Array(reader, startOffset, endOffset - startOffset);
5696
+ const tailView = getDataView(tailArray);
5697
+ for (let indexByte = tailArray.length - ZIP64_END_OF_CENTRAL_DIR_LENGTH; indexByte >= 0; indexByte--) {
5698
+ if (getUint32$1(tailView, indexByte) == ZIP64_END_OF_CENTRAL_DIR_SIGNATURE &&
5699
+ indexByte + 12 + Number(tailView.getBigUint64(indexByte + 4, true)) == tailArray.length) {
5700
+ return startOffset + indexByte;
5701
+ }
5702
+ }
5703
+ }
5704
+
5705
+ function getFirstLocalHeaderOffset(directoryArray, directoryView) {
5706
+ if (directoryArray.length < CENTRAL_FILE_HEADER_LENGTH) {
5707
+ return UNDEFINED_VALUE;
5708
+ }
5709
+ const localHeaderOffset = getUint32$1(directoryView, 42);
5710
+ if (localHeaderOffset != MAX_32_BITS) {
5711
+ return localHeaderOffset;
5712
+ }
5713
+ let offsetExtraField = CENTRAL_FILE_HEADER_LENGTH + getUint16$1(directoryView, 28);
5714
+ const endExtraField = Math.min(offsetExtraField + getUint16$1(directoryView, 30), directoryArray.length);
5715
+ while (offsetExtraField + 4 <= endExtraField) {
5716
+ const type = getUint16$1(directoryView, offsetExtraField);
5717
+ const size = getUint16$1(directoryView, offsetExtraField + 2);
5718
+ if (type == EXTRAFIELD_TYPE_ZIP64) {
5719
+ let offsetValue = offsetExtraField + 4;
5720
+ if (getUint32$1(directoryView, 24) == MAX_32_BITS) {
5721
+ offsetValue += 8;
5722
+ }
5723
+ if (getUint32$1(directoryView, 20) == MAX_32_BITS) {
5724
+ offsetValue += 8;
5725
+ }
5726
+ return offsetValue + 8 <= endExtraField ? getBigUint64(directoryView, offsetValue) : UNDEFINED_VALUE;
5727
+ }
5728
+ offsetExtraField += 4 + size;
5729
+ }
5730
+ return UNDEFINED_VALUE;
5731
+ }
5732
+
5615
5733
  function readDigitalSignature(signatureRecordArray) {
5616
5734
  if (signatureRecordArray.length >= 6) {
5617
5735
  const signatureRecordView = getDataView(signatureRecordArray);
@@ -5701,6 +5819,7 @@
5701
5819
  uncompressedSize: getUint32$1(dataView, offset + HEADER_OFFSET_UNCOMPRESSED_SIZE)
5702
5820
  });
5703
5821
  const extraFieldZip64 = extraField.get(EXTRAFIELD_TYPE_ZIP64);
5822
+ let extraFieldZip64Missing;
5704
5823
  if (extraFieldZip64) {
5705
5824
  if (!readExtraFieldZip64(extraFieldZip64, directory, localDirectory)) {
5706
5825
  malformedExtraField = true;
@@ -5710,7 +5829,7 @@
5710
5829
  if (localDirectory) {
5711
5830
  malformedExtraField = true;
5712
5831
  } else {
5713
- throw new Error(ERR_EXTRAFIELD_ZIP64_NOT_FOUND);
5832
+ extraFieldZip64Missing = true;
5714
5833
  }
5715
5834
  }
5716
5835
  const extraFieldUnicodePath = extraField.get(EXTRAFIELD_TYPE_UNICODE_PATH);
@@ -5743,6 +5862,11 @@
5743
5862
  readExtraFieldUnixDates(extraFieldUnixType1, directory);
5744
5863
  directory.extraFieldUnixType1 = extraFieldUnixType1;
5745
5864
  }
5865
+ const extraFieldExtendedTimestamp = extraField.get(EXTRAFIELD_TYPE_EXTENDED_TIMESTAMP);
5866
+ if (extraFieldExtendedTimestamp) {
5867
+ readExtraFieldExtendedTimestamp(extraFieldExtendedTimestamp, directory, localDirectory);
5868
+ directory.extraFieldExtendedTimestamp = extraFieldExtendedTimestamp;
5869
+ }
5746
5870
  const extraFieldNTFS = extraField.get(EXTRAFIELD_TYPE_NTFS);
5747
5871
  if (extraFieldNTFS) {
5748
5872
  readExtraFieldNTFS(extraFieldNTFS, directory);
@@ -5759,15 +5883,13 @@
5759
5883
  readExtraFieldUnix(extraFieldUnix, unixIdsRead ? {} : directory, false);
5760
5884
  directory.extraFieldUnix = extraFieldUnix;
5761
5885
  }
5762
- const extraFieldExtendedTimestamp = extraField.get(EXTRAFIELD_TYPE_EXTENDED_TIMESTAMP);
5763
- if (extraFieldExtendedTimestamp) {
5764
- readExtraFieldExtendedTimestamp(extraFieldExtendedTimestamp, directory, localDirectory);
5765
- directory.extraFieldExtendedTimestamp = extraFieldExtendedTimestamp;
5766
- }
5767
5886
  const extraFieldUSDZ = extraField.get(EXTRAFIELD_TYPE_USDZ);
5768
5887
  if (extraFieldUSDZ) {
5769
5888
  directory.extraFieldUSDZ = extraFieldUSDZ;
5770
5889
  }
5890
+ if (extraFieldZip64Missing) {
5891
+ throw new Error(ERR_EXTRAFIELD_ZIP64_NOT_FOUND);
5892
+ }
5771
5893
  return malformedExtraField;
5772
5894
  }
5773
5895
 
@@ -5982,13 +6104,7 @@
5982
6104
  let dataDescriptorLength = 0;
5983
6105
  if (dataDescriptor) {
5984
6106
  const zip64 = Boolean(extraFieldZip64);
5985
- const dataDescriptorArray = await readUint8Array(reader, dataOffset + compressedSize, DATA_DESCRIPTOR_RECORD_ZIP_64_LENGTH + DATA_DESCRIPTOR_RECORD_SIGNATURE_LENGTH);
5986
- const dataDescriptorView = getDataView(dataDescriptorArray);
5987
- const candidates = [[zip64, true], [zip64, false], [!zip64, true], [!zip64, false]]
5988
- .map(([zip64Layout, signature]) => readDataDescriptor(dataDescriptorView, zip64Layout, signature))
5989
- .filter(candidate => candidate && candidate.compressedSize == compressedSize && candidate.uncompressedSize == uncompressedSize);
5990
- const localDataDescriptor = candidates.find(candidate => candidate.crc32 == crc32) || candidates[0] ||
5991
- readDataDescriptor(dataDescriptorView, zip64, true) || readDataDescriptor(dataDescriptorView, zip64, false);
6107
+ const localDataDescriptor = await readLocalDataDescriptor(reader, dataOffset + compressedSize, { crc32, compressedSize, uncompressedSize, zip64 });
5992
6108
  if (localDataDescriptor) {
5993
6109
  fileEntry.localDirectory.dataDescriptor = localDataDescriptor;
5994
6110
  dataDescriptorLength = getDataDescriptorLength(localDataDescriptor.zip64, localDataDescriptor.signature);
@@ -6058,6 +6174,25 @@
6058
6174
  return mergedRanges;
6059
6175
  }
6060
6176
 
6177
+ async function readLocalDataDescriptor(reader, offset, { crc32, compressedSize, uncompressedSize, zip64 }) {
6178
+ const maxLength = DATA_DESCRIPTOR_RECORD_ZIP_64_LENGTH + DATA_DESCRIPTOR_RECORD_SIGNATURE_LENGTH;
6179
+ const length = Math.min(maxLength, Math.max(0, reader.size - offset));
6180
+ const dataDescriptorArray = length ? await readUint8Array(reader, offset, length) : EMPTY_UINT8_ARRAY;
6181
+ const dataDescriptorView = getDataView(dataDescriptorArray);
6182
+ const candidates = [[zip64, true], [zip64, false], [!zip64, true], [!zip64, false]]
6183
+ .map(([zip64Layout, signature]) => readDataDescriptor(dataDescriptorView, zip64Layout, signature))
6184
+ .filter(candidate => candidate && candidate.compressedSize == compressedSize && candidate.uncompressedSize == uncompressedSize);
6185
+ return candidates.find(candidate => candidate.crc32 == crc32) || candidates[0] ||
6186
+ readDataDescriptor(dataDescriptorView, zip64, true) || readDataDescriptor(dataDescriptorView, zip64, false);
6187
+ }
6188
+
6189
+ async function getEntryDataDescriptorLength(reader, offset, { crc32, compressedSize, uncompressedSize, extraFieldZip64 }) {
6190
+ const dataDescriptor = await readLocalDataDescriptor(reader, offset, { crc32, compressedSize, uncompressedSize, zip64: Boolean(extraFieldZip64) });
6191
+ if (dataDescriptor && dataDescriptor.compressedSize == compressedSize && dataDescriptor.uncompressedSize == uncompressedSize) {
6192
+ return getDataDescriptorLength(dataDescriptor.zip64, dataDescriptor.signature);
6193
+ }
6194
+ }
6195
+
6061
6196
  function readDataDescriptor(dataDescriptorView, zip64, signature) {
6062
6197
  const offset = signature ? DATA_DESCRIPTOR_RECORD_SIGNATURE_LENGTH : 0;
6063
6198
  if (dataDescriptorView.byteLength < getDataDescriptorLength(zip64, signature) ||
@@ -6317,6 +6452,18 @@
6317
6452
  }
6318
6453
  }
6319
6454
 
6455
+ function validateDataDescriptor(zipEntry, localDirectory, warnings) {
6456
+ const { dataDescriptor } = localDirectory;
6457
+ const maskedLocalDirectory = zipEntry.decryptedDirectory &&
6458
+ (localDirectory.rawBitFlag & BITFLAG_MASKED_LOCAL_HEADERS) == BITFLAG_MASKED_LOCAL_HEADERS;
6459
+ if (dataDescriptor && !maskedLocalDirectory &&
6460
+ ((zipEntry.crc32 !== UNDEFINED_VALUE && dataDescriptor.crc32 != zipEntry.crc32) ||
6461
+ dataDescriptor.compressedSize != zipEntry.compressedSize ||
6462
+ dataDescriptor.uncompressedSize != zipEntry.uncompressedSize)) {
6463
+ reportAmbiguity(!warnings, warnings, WARNING_MISMATCHED_LOCAL_FILE_HEADER_CRC32_OR_SIZES);
6464
+ }
6465
+ }
6466
+
6320
6467
  function reportAmbiguity(reject, warnings, reason) {
6321
6468
  if (reject) {
6322
6469
  throwAmbiguousArchive(reason);
@@ -6402,11 +6549,13 @@
6402
6549
  WARNING_COMPRESSED_PATCHED_DATA: WARNING_COMPRESSED_PATCHED_DATA,
6403
6550
  WARNING_DUPLICATE_FILENAME: WARNING_DUPLICATE_FILENAME,
6404
6551
  WARNING_MALFORMED_EXTRA_FIELD: WARNING_MALFORMED_EXTRA_FIELD,
6552
+ WARNING_MISMATCHED_CENTRAL_DIRECTORY_OFFSET: WARNING_MISMATCHED_CENTRAL_DIRECTORY_OFFSET,
6405
6553
  WARNING_MISMATCHED_LOCAL_FILE_HEADER_BIT_FLAG: WARNING_MISMATCHED_LOCAL_FILE_HEADER_BIT_FLAG,
6406
6554
  WARNING_MISMATCHED_LOCAL_FILE_HEADER_COMPRESSION_METHOD: WARNING_MISMATCHED_LOCAL_FILE_HEADER_COMPRESSION_METHOD,
6407
6555
  WARNING_MISMATCHED_LOCAL_FILE_HEADER_CRC32_OR_SIZES: WARNING_MISMATCHED_LOCAL_FILE_HEADER_CRC32_OR_SIZES,
6408
6556
  WARNING_MISMATCHED_LOCAL_FILE_HEADER_FILENAME: WARNING_MISMATCHED_LOCAL_FILE_HEADER_FILENAME,
6409
6557
  WARNING_MISMATCHED_ZIP64_END_OF_CENTRAL_DIRECTORY: WARNING_MISMATCHED_ZIP64_END_OF_CENTRAL_DIRECTORY,
6558
+ WARNING_MISSING_ZIP64_EXTRA_FIELD: WARNING_MISSING_ZIP64_EXTRA_FIELD,
6410
6559
  WARNING_MULTIPLE_END_OF_CENTRAL_DIRECTORY: WARNING_MULTIPLE_END_OF_CENTRAL_DIRECTORY,
6411
6560
  WARNING_PREPENDED_CENTRAL_DIRECTORY: WARNING_PREPENDED_CENTRAL_DIRECTORY,
6412
6561
  WARNING_PREPENDED_DATA: WARNING_PREPENDED_DATA,
@@ -6417,6 +6566,7 @@
6417
6566
  WARNING_WRAPPED_ENTRIES_COUNT: WARNING_WRAPPED_ENTRIES_COUNT,
6418
6567
  ZipReader: ZipReader,
6419
6568
  ZipReaderStream: ZipReaderStream,
6569
+ getEntryDataDescriptorLength: getEntryDataDescriptorLength,
6420
6570
  isZipFile: isZipFile
6421
6571
  });
6422
6572
 
@@ -6539,130 +6689,8 @@
6539
6689
  return watchPromiseError(this, prependZipEntries(this, reader));
6540
6690
  }
6541
6691
 
6542
- appendZip(reader) {
6543
- return watchPromiseError(this, this.appendZipEntries(reader));
6544
- }
6545
-
6546
- async appendZipEntries(reader) {
6547
- const zipWriter = this;
6548
- const { pendingAddFileCalls, filenames, fileEntries } = zipWriter;
6549
- while (pendingAddFileCalls.size) {
6550
- await Promise.allSettled(Array.from(pendingAddFileCalls));
6551
- }
6552
- let resolveAppendZip;
6553
- const promiseAppendZip = new Promise(resolve => resolveAppendZip = resolve);
6554
- pendingAddFileCalls.add(promiseAppendZip);
6555
- const appendedFilenames = [];
6556
- let releaseLockWriter;
6557
- try {
6558
- reader = new GenericReader(reader);
6559
- await initStream(reader);
6560
- if (reader.size === UNDEFINED_VALUE || !reader.readUint8Array) {
6561
- reader = new BlobReader(await streamToBlob(reader.readable));
6562
- await initStream(reader);
6563
- }
6564
- const { ZipReader } = await Promise.resolve().then(function () { return zipReader; });
6565
- const zipReader$1 = new ZipReader(reader);
6566
- const entries = await zipReader$1.getEntries();
6567
- await zipReader$1.close();
6568
- await initStream(zipWriter.writer);
6569
- const { directoryOffset } = zipReader$1;
6570
- entries.forEach(({ filename }) => {
6571
- if (filenames.has(filename)) {
6572
- throw new Error(ERR_DUPLICATED_NAME);
6573
- }
6574
- filenames.add(filename);
6575
- appendedFilenames.push(filename);
6576
- });
6577
- zipWriter.writerLocked = true;
6578
- const { lockWriter } = zipWriter;
6579
- zipWriter.lockWriter = new Promise(resolve => releaseLockWriter = () => {
6580
- zipWriter.writerLocked = false;
6581
- resolve();
6582
- });
6583
- await lockWriter;
6584
- if (zipWriter.addSplitZipSignature) {
6585
- delete zipWriter.addSplitZipSignature;
6586
- if (!await startsWithSplitZipSignature(reader)) {
6587
- await writeData(zipWriter.writer, getSplitZipSignatureArray());
6588
- zipWriter.offset += SPLIT_ZIP_FILE_SIGNATURE_LENGTH;
6589
- }
6590
- }
6591
- const entryPositions = await copyZipData(zipWriter, reader, entries, directoryOffset);
6592
- entries.forEach(entry => {
6593
- const {
6594
- version,
6595
- rawLastModDate,
6596
- rawFilename,
6597
- bitFlag,
6598
- encrypted,
6599
- uncompressedSize,
6600
- compressedSize,
6601
- extraFieldZip64
6602
- } = entry;
6603
- let {
6604
- compressionMethod,
6605
- rawExtraField,
6606
- } = entry;
6607
- const { level, languageEncodingFlag, dataDescriptor } = bitFlag;
6608
- rawExtraField = removeExtraFieldZip64(rawExtraField || EMPTY_UINT8_ARRAY);
6609
- if (entry.extraFieldAES) {
6610
- compressionMethod = COMPRESSION_METHOD_AES;
6611
- }
6612
- const extraFieldLength = getLength(rawExtraField);
6613
- const zip64UncompressedSize = Boolean(extraFieldZip64) && extraFieldZip64.uncompressedSize !== UNDEFINED_VALUE;
6614
- const zip64CompressedSize = Boolean(extraFieldZip64) && extraFieldZip64.compressedSize !== UNDEFINED_VALUE;
6615
- const bitFlagValue = (getBitFlag(level, languageEncodingFlag, dataDescriptor, encrypted, compressionMethod) & ~BITFLAG_LEVEL) | (level << 1);
6616
- const {
6617
- headerArray,
6618
- headerView
6619
- } = getHeaderArrayData({
6620
- version,
6621
- bitFlag: bitFlagValue,
6622
- compressionMethod,
6623
- uncompressedSize,
6624
- compressedSize,
6625
- rawLastModDate,
6626
- rawFilename,
6627
- zip64CompressedSize,
6628
- zip64UncompressedSize,
6629
- extraFieldLength
6630
- });
6631
- const { crc32 } = entry;
6632
- if (crc32 !== UNDEFINED_VALUE) {
6633
- setUint32(headerView, HEADER_OFFSET_SIGNATURE, crc32);
6634
- }
6635
- const { offset, diskNumberStart } = entryPositions.get(entry);
6636
- Object.assign(entry, {
6637
- zip64Enabled: true,
6638
- zip64UncompressedSize,
6639
- zip64CompressedSize,
6640
- offset,
6641
- diskNumberStart,
6642
- zip64DiskNumberStart: false,
6643
- rawExtraFieldZip64: EMPTY_UINT8_ARRAY,
6644
- rawExtraFieldAES: EMPTY_UINT8_ARRAY,
6645
- rawExtraFieldExtendedTimestamp: EMPTY_UINT8_ARRAY,
6646
- rawExtraFieldNTFS: EMPTY_UINT8_ARRAY,
6647
- rawExtraFieldUnix: EMPTY_UINT8_ARRAY,
6648
- rawCentralExtraFieldUnix: EMPTY_UINT8_ARRAY,
6649
- rawExtraField,
6650
- rawCentralExtraField: EMPTY_UINT8_ARRAY,
6651
- headerArray,
6652
- headerView
6653
- });
6654
- fileEntries.set(entry.filename, entry);
6655
- });
6656
- } catch (error) {
6657
- appendedFilenames.forEach(filename => filenames.delete(filename));
6658
- throw error;
6659
- } finally {
6660
- resolveAppendZip();
6661
- pendingAddFileCalls.delete(promiseAppendZip);
6662
- if (releaseLockWriter) {
6663
- releaseLockWriter();
6664
- }
6665
- }
6692
+ appendZip(reader, options = {}) {
6693
+ return watchPromiseError(this, appendZipEntries(this, reader, options));
6666
6694
  }
6667
6695
 
6668
6696
  add(name = "", reader, options = {}) {
@@ -6824,11 +6852,140 @@
6824
6852
  return watchedPromise;
6825
6853
  }
6826
6854
 
6855
+ async function appendZipEntries(zipWriter, reader, options = {}) {
6856
+ const { pendingAddFileCalls, filenames, fileEntries } = zipWriter;
6857
+ const filter = checkFunctionOption(options.filter);
6858
+ while (pendingAddFileCalls.size) {
6859
+ await Promise.allSettled(Array.from(pendingAddFileCalls));
6860
+ }
6861
+ let resolveAppendZip;
6862
+ const promiseAppendZip = new Promise(resolve => resolveAppendZip = resolve);
6863
+ pendingAddFileCalls.add(promiseAppendZip);
6864
+ const appendedFilenames = [];
6865
+ let releaseLockWriter;
6866
+ try {
6867
+ reader = new GenericReader(reader);
6868
+ await initStream(reader);
6869
+ if (reader.size === UNDEFINED_VALUE || !reader.readUint8Array) {
6870
+ reader = new BlobReader(await streamToBlob(reader.readable));
6871
+ await initStream(reader);
6872
+ }
6873
+ const { ZipReader, getEntryDataDescriptorLength } = await Promise.resolve().then(function () { return zipReader; });
6874
+ const zipReader$1 = new ZipReader(reader);
6875
+ const entries = await zipReader$1.getEntries();
6876
+ const keptEntries = [];
6877
+ for (const entry of entries) {
6878
+ if (!filter || await filter(entry)) {
6879
+ keptEntries.push(entry);
6880
+ }
6881
+ }
6882
+ await zipReader$1.close();
6883
+ await initStream(zipWriter.writer);
6884
+ const { directoryOffset, entriesMissingZip64ExtraField } = zipReader$1;
6885
+ keptEntries.forEach(entry => {
6886
+ const { filename } = entry;
6887
+ if (entriesMissingZip64ExtraField.has(entry)) {
6888
+ throw new Error(ERR_EXTRAFIELD_ZIP64_NOT_FOUND);
6889
+ }
6890
+ if (filenames.has(filename)) {
6891
+ throw new Error(ERR_DUPLICATED_NAME);
6892
+ }
6893
+ filenames.add(filename);
6894
+ appendedFilenames.push(filename);
6895
+ });
6896
+ zipWriter.writerLocked = true;
6897
+ const { lockWriter } = zipWriter;
6898
+ zipWriter.lockWriter = new Promise(resolve => releaseLockWriter = () => {
6899
+ zipWriter.writerLocked = false;
6900
+ resolve();
6901
+ });
6902
+ await lockWriter;
6903
+ if (zipWriter.addSplitZipSignature) {
6904
+ delete zipWriter.addSplitZipSignature;
6905
+ if (filter || !await startsWithSplitZipSignature(reader)) {
6906
+ await writeData(zipWriter.writer, getSplitZipSignatureArray());
6907
+ zipWriter.offset += SPLIT_ZIP_FILE_SIGNATURE_LENGTH;
6908
+ }
6909
+ }
6910
+ const entryPositions = await copyZipData(zipWriter, reader, entries, keptEntries, directoryOffset, Boolean(filter), getEntryDataDescriptorLength);
6911
+ keptEntries.forEach(entry => {
6912
+ const {
6913
+ version,
6914
+ rawLastModDate,
6915
+ rawFilename,
6916
+ rawBitFlag,
6917
+ uncompressedSize,
6918
+ compressedSize,
6919
+ extraFieldZip64
6920
+ } = entry;
6921
+ let {
6922
+ compressionMethod,
6923
+ rawExtraField,
6924
+ } = entry;
6925
+ rawExtraField = removeExtraFieldZip64(rawExtraField || EMPTY_UINT8_ARRAY);
6926
+ if (entry.extraFieldAES) {
6927
+ compressionMethod = COMPRESSION_METHOD_AES;
6928
+ }
6929
+ const extraFieldLength = getLength(rawExtraField);
6930
+ const zip64UncompressedSize = Boolean(extraFieldZip64) && extraFieldZip64.uncompressedSize !== UNDEFINED_VALUE;
6931
+ const zip64CompressedSize = Boolean(extraFieldZip64) && extraFieldZip64.compressedSize !== UNDEFINED_VALUE;
6932
+ const {
6933
+ headerArray,
6934
+ headerView
6935
+ } = getHeaderArrayData({
6936
+ version,
6937
+ bitFlag: rawBitFlag,
6938
+ compressionMethod,
6939
+ uncompressedSize,
6940
+ compressedSize,
6941
+ rawLastModDate,
6942
+ rawFilename,
6943
+ zip64CompressedSize,
6944
+ zip64UncompressedSize,
6945
+ extraFieldLength
6946
+ });
6947
+ const { crc32 } = entry;
6948
+ if (crc32 !== UNDEFINED_VALUE) {
6949
+ setUint32(headerView, HEADER_OFFSET_SIGNATURE, crc32);
6950
+ }
6951
+ const { offset, diskNumberStart } = entryPositions.get(entry);
6952
+ Object.assign(entry, {
6953
+ zip64Enabled: true,
6954
+ zip64UncompressedSize,
6955
+ zip64CompressedSize,
6956
+ offset,
6957
+ diskNumberStart,
6958
+ zip64DiskNumberStart: false,
6959
+ rawExtraFieldZip64: EMPTY_UINT8_ARRAY,
6960
+ rawExtraFieldAES: EMPTY_UINT8_ARRAY,
6961
+ rawExtraFieldExtendedTimestamp: EMPTY_UINT8_ARRAY,
6962
+ rawExtraFieldNTFS: EMPTY_UINT8_ARRAY,
6963
+ rawExtraFieldUnix: EMPTY_UINT8_ARRAY,
6964
+ rawCentralExtraFieldUnix: EMPTY_UINT8_ARRAY,
6965
+ rawExtraField,
6966
+ rawCentralExtraField: EMPTY_UINT8_ARRAY,
6967
+ headerArray,
6968
+ headerView
6969
+ });
6970
+ fileEntries.set(entry.filename, entry);
6971
+ });
6972
+ } catch (error) {
6973
+ appendedFilenames.forEach(filename => filenames.delete(filename));
6974
+ throw error;
6975
+ } finally {
6976
+ resolveAppendZip();
6977
+ pendingAddFileCalls.delete(promiseAppendZip);
6978
+ if (releaseLockWriter) {
6979
+ releaseLockWriter();
6980
+ }
6981
+ }
6982
+ }
6983
+
6827
6984
  async function prependZipEntries(zipWriter, reader) {
6828
6985
  if (zipWriter.filenames.size) {
6829
6986
  throw new Error(ERR_ZIP_NOT_EMPTY);
6830
6987
  }
6831
- await zipWriter.appendZipEntries(reader);
6988
+ await appendZipEntries(zipWriter, reader);
6832
6989
  }
6833
6990
 
6834
6991
  async function addFileEntry(zipWriter, name, reader, options) {
@@ -8502,26 +8659,63 @@
8502
8659
  return rawExtraField;
8503
8660
  }
8504
8661
 
8505
- async function copyZipData(zipWriter, reader, entries, directoryOffset) {
8662
+ async function copyZipData(zipWriter, reader, entries, keptEntries, directoryOffset, compact, getEntryDataDescriptorLength) {
8506
8663
  const { writer } = zipWriter;
8507
8664
  const entryPositions = new Map();
8508
- if (writer.closeDisk) {
8665
+ if (writer.closeDisk || compact) {
8509
8666
  const sortedEntries = Array.from(entries).sort((firstEntry, secondEntry) =>
8510
8667
  getSourceOffset(reader, firstEntry) - getSourceOffset(reader, secondEntry));
8511
- let copiedLength = 0;
8512
- for (const entry of sortedEntries) {
8513
- const sourceOffset = getSourceOffset(reader, entry);
8514
- await copyData(zipWriter, reader, copiedLength, sourceOffset - copiedLength);
8515
- if (exceedsAvailableSize(writer, await getLocalHeaderLength(reader, sourceOffset))) {
8516
- await writer.closeDisk();
8517
- }
8518
- entryPositions.set(entry, {
8519
- offset: getSegmentOffset(zipWriter, writer),
8520
- diskNumberStart: getDiskNumber(writer)
8521
- });
8522
- copiedLength = sourceOffset;
8668
+ const regionEnds = getRegionEnds(reader, sortedEntries, directoryOffset);
8669
+ const keptEntrySet = new Set(keptEntries);
8670
+ const localHeaderLengths = new Map();
8671
+ for (let indexEntry = 0; indexEntry < sortedEntries.length; indexEntry++) {
8672
+ const entry = sortedEntries[indexEntry];
8673
+ if (keptEntrySet.has(entry)) {
8674
+ const sourceOffset = getSourceOffset(reader, entry);
8675
+ const localHeaderLength = await getLocalHeaderLength(reader, sourceOffset);
8676
+ if (localHeaderLength === UNDEFINED_VALUE) {
8677
+ throw new Error(ERR_LOCAL_FILE_HEADER_NOT_FOUND);
8678
+ }
8679
+ let entryEnd = sourceOffset + localHeaderLength + entry.compressedSize;
8680
+ if (entry.bitFlag.dataDescriptor) {
8681
+ const dataDescriptorLength = await getEntryDataDescriptorLength(reader, entryEnd, entry);
8682
+ entryEnd = dataDescriptorLength === UNDEFINED_VALUE ? Math.max(entryEnd, regionEnds[indexEntry]) : entryEnd + dataDescriptorLength;
8683
+ }
8684
+ if (entryEnd > regionEnds[indexEntry]) {
8685
+ throw new Error(ERR_OVERLAPPING_ENTRY);
8686
+ }
8687
+ regionEnds[indexEntry] = entryEnd;
8688
+ localHeaderLengths.set(entry, localHeaderLength);
8689
+ }
8690
+ }
8691
+ let copiedOffset = 0;
8692
+ let lastPosition;
8693
+ for (let indexEntry = 0; indexEntry < sortedEntries.length; indexEntry++) {
8694
+ const entry = sortedEntries[indexEntry];
8695
+ if (keptEntrySet.has(entry)) {
8696
+ const sourceOffset = getSourceOffset(reader, entry);
8697
+ if (sourceOffset < copiedOffset) {
8698
+ entryPositions.set(entry, lastPosition);
8699
+ } else {
8700
+ if (!compact) {
8701
+ await copyData(zipWriter, reader, copiedOffset, sourceOffset - copiedOffset);
8702
+ }
8703
+ if (writer.closeDisk && exceedsAvailableSize(writer, localHeaderLengths.get(entry))) {
8704
+ await writer.closeDisk();
8705
+ }
8706
+ lastPosition = {
8707
+ offset: getSegmentOffset(zipWriter, writer),
8708
+ diskNumberStart: getDiskNumber(writer)
8709
+ };
8710
+ entryPositions.set(entry, lastPosition);
8711
+ await copyData(zipWriter, reader, sourceOffset, regionEnds[indexEntry] - sourceOffset);
8712
+ copiedOffset = regionEnds[indexEntry];
8713
+ }
8714
+ }
8715
+ }
8716
+ if (!compact) {
8717
+ await copyData(zipWriter, reader, copiedOffset, directoryOffset - copiedOffset);
8523
8718
  }
8524
- await copyData(zipWriter, reader, copiedLength, directoryOffset - copiedLength);
8525
8719
  } else {
8526
8720
  const baseOffset = zipWriter.offset;
8527
8721
  await copyData(zipWriter, reader, 0, directoryOffset);
@@ -8533,6 +8727,20 @@
8533
8727
  return entryPositions;
8534
8728
  }
8535
8729
 
8730
+ function getRegionEnds(reader, sortedEntries, directoryOffset) {
8731
+ const regionEnds = new Array(sortedEntries.length);
8732
+ let regionEnd = directoryOffset;
8733
+ for (let indexEntry = sortedEntries.length - 1; indexEntry >= 0; indexEntry--) {
8734
+ const sourceOffset = getSourceOffset(reader, sortedEntries[indexEntry]);
8735
+ const nextEntry = sortedEntries[indexEntry + 1];
8736
+ if (nextEntry && getSourceOffset(reader, nextEntry) > sourceOffset) {
8737
+ regionEnd = Math.min(getSourceOffset(reader, nextEntry), directoryOffset);
8738
+ }
8739
+ regionEnds[indexEntry] = regionEnd;
8740
+ }
8741
+ return regionEnds;
8742
+ }
8743
+
8536
8744
  async function copyData(zipWriter, reader, offset, size) {
8537
8745
  if (size > 0) {
8538
8746
  const { writer } = zipWriter;
@@ -8540,11 +8748,13 @@
8540
8748
  try {
8541
8749
  await flushBufferedData(createReadable(reader, { offset, size }), writer, UNDEFINED_VALUE, chunkLength => copiedLength += chunkLength);
8542
8750
  } catch (error) {
8543
- zipWriter.hasCorruptedEntries = true;
8544
- try {
8545
- error.corruptedEntry = true;
8546
- } catch {
8547
- // ignored
8751
+ if (copiedLength) {
8752
+ zipWriter.hasCorruptedEntries = true;
8753
+ try {
8754
+ error.corruptedEntry = true;
8755
+ } catch {
8756
+ // ignored
8757
+ }
8548
8758
  }
8549
8759
  throw error;
8550
8760
  } finally {
@@ -8555,11 +8765,16 @@
8555
8765
  }
8556
8766
 
8557
8767
  async function getLocalHeaderLength(reader, offset) {
8558
- const headerArray = await readUint8Array(reader, offset, HEADER_SIZE);
8768
+ const headerArray = offset >= 0 && offset + HEADER_SIZE <= reader.size ?
8769
+ await readUint8Array(reader, offset, HEADER_SIZE) :
8770
+ EMPTY_UINT8_ARRAY;
8559
8771
  if (getLength(headerArray) < HEADER_SIZE) {
8560
- return HEADER_SIZE;
8772
+ return UNDEFINED_VALUE;
8561
8773
  }
8562
8774
  const headerView = getDataView(headerArray);
8775
+ if (getUint32(headerView, 0) != LOCAL_FILE_HEADER_SIGNATURE) {
8776
+ return UNDEFINED_VALUE;
8777
+ }
8563
8778
  return HEADER_SIZE +
8564
8779
  getUint16(headerView, HEADER_OFFSET_FILENAME_LENGTH + LOCAL_HEADER_COMMON_OFFSET) +
8565
8780
  getUint16(headerView, HEADER_OFFSET_EXTRAFIELD_LENGTH + LOCAL_HEADER_COMMON_OFFSET);
@@ -8910,7 +9125,7 @@
8910
9125
  EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
8911
9126
  */
8912
9127
 
8913
- const VERSION = "2.19.0";
9128
+ const VERSION = "2.21.0";
8914
9129
 
8915
9130
  /*
8916
9131
  Copyright (c) 2025 Gildas Lormeau. All rights reserved.
@@ -10074,11 +10289,13 @@
10074
10289
  exports.WARNING_COMPRESSION_UNAVAILABLE = WARNING_COMPRESSION_UNAVAILABLE;
10075
10290
  exports.WARNING_DUPLICATE_FILENAME = WARNING_DUPLICATE_FILENAME;
10076
10291
  exports.WARNING_MALFORMED_EXTRA_FIELD = WARNING_MALFORMED_EXTRA_FIELD;
10292
+ exports.WARNING_MISMATCHED_CENTRAL_DIRECTORY_OFFSET = WARNING_MISMATCHED_CENTRAL_DIRECTORY_OFFSET;
10077
10293
  exports.WARNING_MISMATCHED_LOCAL_FILE_HEADER_BIT_FLAG = WARNING_MISMATCHED_LOCAL_FILE_HEADER_BIT_FLAG;
10078
10294
  exports.WARNING_MISMATCHED_LOCAL_FILE_HEADER_COMPRESSION_METHOD = WARNING_MISMATCHED_LOCAL_FILE_HEADER_COMPRESSION_METHOD;
10079
10295
  exports.WARNING_MISMATCHED_LOCAL_FILE_HEADER_CRC32_OR_SIZES = WARNING_MISMATCHED_LOCAL_FILE_HEADER_CRC32_OR_SIZES;
10080
10296
  exports.WARNING_MISMATCHED_LOCAL_FILE_HEADER_FILENAME = WARNING_MISMATCHED_LOCAL_FILE_HEADER_FILENAME;
10081
10297
  exports.WARNING_MISMATCHED_ZIP64_END_OF_CENTRAL_DIRECTORY = WARNING_MISMATCHED_ZIP64_END_OF_CENTRAL_DIRECTORY;
10298
+ exports.WARNING_MISSING_ZIP64_EXTRA_FIELD = WARNING_MISSING_ZIP64_EXTRA_FIELD;
10082
10299
  exports.WARNING_MULTIPLE_END_OF_CENTRAL_DIRECTORY = WARNING_MULTIPLE_END_OF_CENTRAL_DIRECTORY;
10083
10300
  exports.WARNING_PREPENDED_CENTRAL_DIRECTORY = WARNING_PREPENDED_CENTRAL_DIRECTORY;
10084
10301
  exports.WARNING_PREPENDED_DATA = WARNING_PREPENDED_DATA;