@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-fs.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";
@@ -4785,12 +4789,9 @@
4785
4789
  const ERR_EOCDR_NOT_FOUND = "End of central directory not found";
4786
4790
  const ERR_EOCDR_LOCATOR_ZIP64_NOT_FOUND = "End of Zip64 central directory locator not found";
4787
4791
  const ERR_CENTRAL_DIRECTORY_NOT_FOUND = "Central directory header not found";
4788
- const ERR_LOCAL_FILE_HEADER_NOT_FOUND = "Local file header not found";
4789
- const ERR_EXTRAFIELD_ZIP64_NOT_FOUND = "Zip64 extra field not found";
4790
4792
  const ERR_ENCRYPTED = "File contains encrypted entry";
4791
4793
  const ERR_UNSUPPORTED_ENCRYPTION = "Encryption method not supported";
4792
4794
  const ERR_SPLIT_ZIP_FILE = "Split zip file";
4793
- const ERR_OVERLAPPING_ENTRY = "Overlapping entry found";
4794
4795
  const ERR_ENTRY_DATA_OUT_OF_BOUNDS = "Entry data out of bounds";
4795
4796
  const ERR_AMBIGUOUS_ARCHIVE = "Ambiguous archive";
4796
4797
  const ERR_ENCRYPTED_CENTRAL_DIRECTORY = "Encrypted central directory is not supported";
@@ -4809,6 +4810,8 @@
4809
4810
  const WARNING_PREPENDED_DATA = "prepended data";
4810
4811
  const WARNING_PREPENDED_CENTRAL_DIRECTORY = "prepended central directory";
4811
4812
  const WARNING_TRAILING_CENTRAL_DIRECTORY_DATA = "trailing central directory data";
4813
+ const WARNING_MISMATCHED_CENTRAL_DIRECTORY_OFFSET = "mismatched central directory offset";
4814
+ const WARNING_MISSING_ZIP64_EXTRA_FIELD = "missing zip64 extra field";
4812
4815
  const WARNING_DUPLICATE_FILENAME = "duplicate filename";
4813
4816
  const WARNING_MISMATCHED_ZIP64_END_OF_CENTRAL_DIRECTORY = "mismatched zip64 end of central directory record";
4814
4817
  const WARNING_MULTIPLE_END_OF_CENTRAL_DIRECTORY = "multiple end of central directory records";
@@ -4853,7 +4856,8 @@
4853
4856
  Object.assign(this, {
4854
4857
  reader: new GenericReader(reader),
4855
4858
  options,
4856
- readRanges: { indexes: new Set(), sortedRanges: [], pendingRanges: [] }
4859
+ readRanges: { indexes: new Set(), sortedRanges: [], pendingRanges: [] },
4860
+ entriesMissingZip64ExtraField: new WeakSet()
4857
4861
  });
4858
4862
  }
4859
4863
 
@@ -4924,16 +4928,22 @@
4924
4928
  directoryDataOffset = getDiskOffset$1(reader, getUint32$1(endOfDirectoryLocatorView, 4)) + getBigUint64(endOfDirectoryLocatorView, 8);
4925
4929
  let endOfDirectoryArray = await readUint8Array(reader, directoryDataOffset, ZIP64_END_OF_CENTRAL_DIR_LENGTH);
4926
4930
  let endOfDirectoryView = getDataView(endOfDirectoryArray);
4927
- const expectedDirectoryDataOffset = endOfDirectoryInfo.offset - ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH - ZIP64_END_OF_CENTRAL_DIR_LENGTH;
4928
- if ((endOfDirectoryArray.length < ZIP64_END_OF_CENTRAL_DIR_LENGTH || getUint32$1(endOfDirectoryView, 0) != ZIP64_END_OF_CENTRAL_DIR_SIGNATURE) &&
4929
- directoryDataOffset != expectedDirectoryDataOffset && expectedDirectoryDataOffset >= 0) {
4930
- const originalDirectoryDataOffset = directoryDataOffset;
4931
- directoryDataOffset = expectedDirectoryDataOffset;
4932
- if (directoryDataOffset > originalDirectoryDataOffset) {
4933
- prependedDataLength = directoryDataOffset - originalDirectoryDataOffset;
4931
+ if (endOfDirectoryArray.length < ZIP64_END_OF_CENTRAL_DIR_LENGTH || getUint32$1(endOfDirectoryView, 0) != ZIP64_END_OF_CENTRAL_DIR_SIGNATURE) {
4932
+ const locatorOffset = endOfDirectoryInfo.offset - ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH;
4933
+ let expectedDirectoryDataOffset = locatorOffset - ZIP64_END_OF_CENTRAL_DIR_LENGTH;
4934
+ if (!await startsWithSignature(reader, expectedDirectoryDataOffset, ZIP64_END_OF_CENTRAL_DIR_SIGNATURE)) {
4935
+ expectedDirectoryDataOffset = await findZip64EndOfDirectoryOffset(reader, locatorOffset);
4936
+ }
4937
+ if (expectedDirectoryDataOffset !== UNDEFINED_VALUE && expectedDirectoryDataOffset >= 0 &&
4938
+ directoryDataOffset != expectedDirectoryDataOffset) {
4939
+ const originalDirectoryDataOffset = directoryDataOffset;
4940
+ directoryDataOffset = expectedDirectoryDataOffset;
4941
+ if (directoryDataOffset > originalDirectoryDataOffset) {
4942
+ prependedDataLength = directoryDataOffset - originalDirectoryDataOffset;
4943
+ }
4944
+ endOfDirectoryArray = await readUint8Array(reader, directoryDataOffset, ZIP64_END_OF_CENTRAL_DIR_LENGTH);
4945
+ endOfDirectoryView = getDataView(endOfDirectoryArray);
4934
4946
  }
4935
- endOfDirectoryArray = await readUint8Array(reader, directoryDataOffset, ZIP64_END_OF_CENTRAL_DIR_LENGTH);
4936
- endOfDirectoryView = getDataView(endOfDirectoryArray);
4937
4947
  }
4938
4948
  if (endOfDirectoryArray.length < ZIP64_END_OF_CENTRAL_DIR_LENGTH || getUint32$1(endOfDirectoryView, 0) != ZIP64_END_OF_CENTRAL_DIR_SIGNATURE) {
4939
4949
  throw new Error(ERR_EOCDR_LOCATOR_ZIP64_NOT_FOUND);
@@ -4971,15 +4981,13 @@
4971
4981
  reportAmbiguity(checkAmbiguity, warnings, WARNING_MISMATCHED_ZIP64_END_OF_CENTRAL_DIRECTORY);
4972
4982
  }
4973
4983
  directoryDataOffset = getDiskOffset$1(reader, diskNumber) + getBigUint64(endOfDirectoryView, 48) + prependedDataLength;
4984
+ } else if (directoryDataOffset == MAX_32_BITS || directoryDataLength == MAX_32_BITS || diskNumber == MAX_16_BITS) {
4985
+ throw new Error(ERR_EOCDR_LOCATOR_ZIP64_NOT_FOUND);
4974
4986
  }
4975
4987
  }
4976
4988
  let declaredDirectoryDataLength = directoryDataLength;
4977
4989
  const centralDirectoryEndOffset = endOfDirectoryInfo.offset -
4978
4990
  (zip64EndOfDirectory ? zip64EndOfDirectoryLength + ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH : 0);
4979
- if (directoryDataOffset >= reader.size) {
4980
- prependedDataLength = reader.size - directoryDataOffset - directoryDataLength - END_OF_CENTRAL_DIR_LENGTH;
4981
- directoryDataOffset = reader.size - directoryDataLength - END_OF_CENTRAL_DIR_LENGTH;
4982
- }
4983
4991
  if (expectedLastDiskNumber != lastDiskNumber) {
4984
4992
  throw new Error(ERR_SPLIT_ZIP_FILE);
4985
4993
  }
@@ -4987,33 +4995,64 @@
4987
4995
  throw new Error(ERR_BAD_FORMAT);
4988
4996
  }
4989
4997
  let offset = 0;
4990
- let directoryArray = await readUint8Array(reader, directoryDataOffset, directoryDataLength);
4998
+ let directoryArray = directoryDataOffset < reader.size ?
4999
+ await readUint8Array(reader, directoryDataOffset, directoryDataLength) :
5000
+ EMPTY_UINT8_ARRAY;
4991
5001
  let directoryView = getDataView(directoryArray);
4992
5002
  if (directoryDataLength) {
4993
- if (directoryArray.length < 4) {
4994
- throw new Error(ERR_BAD_FORMAT);
4995
- }
4996
- const expectedDirectoryDataOffset = centralDirectoryEndOffset - directoryDataLength;
5003
+ let expectedDirectoryDataOffset = centralDirectoryEndOffset - directoryDataLength;
4997
5004
  if (directoryDataOffset != expectedDirectoryDataOffset && diskNumber == lastDiskNumber) {
4998
- const storedPointsAtDirectory = getUint32$1(directoryView, offset) == CENTRAL_FILE_HEADER_SIGNATURE ||
5005
+ const storedPointsAtDirectory = directoryArray.length >= 4 && (
5006
+ getUint32$1(directoryView, offset) == CENTRAL_FILE_HEADER_SIGNATURE ||
4999
5007
  Boolean(directoryEncryptionInfo && directoryEncryptionInfo.compressedSize) ||
5000
- detectEncryptedCentralDirectory(directoryView);
5008
+ detectEncryptedCentralDirectory(directoryView));
5009
+ if (!storedPointsAtDirectory && expectedDirectoryDataOffset < 0) {
5010
+ throw new Error(ERR_BAD_FORMAT);
5011
+ }
5001
5012
  let reconcile = !storedPointsAtDirectory;
5002
- if (!reconcile && expectedDirectoryDataOffset >= 0 && expectedDirectoryDataOffset + 4 <= reader.size) {
5003
- const expectedSignatureArray = await readUint8Array(reader, expectedDirectoryDataOffset, 4);
5004
- reconcile = getUint32$1(getDataView(expectedSignatureArray), 0) == CENTRAL_FILE_HEADER_SIGNATURE;
5013
+ if (expectedDirectoryDataOffset >= 0 && expectedDirectoryDataOffset + 4 <= reader.size) {
5014
+ let expectedPointsAtDirectory = await pointsAtDirectory(reader, expectedDirectoryDataOffset);
5015
+ if (!expectedPointsAtDirectory) {
5016
+ const signatureRecordOffset = await findDigitalSignatureRecordOffset(reader, centralDirectoryEndOffset);
5017
+ const signedDirectoryDataOffset = signatureRecordOffset - directoryDataLength;
5018
+ if (signatureRecordOffset !== UNDEFINED_VALUE && signedDirectoryDataOffset >= 0 &&
5019
+ await pointsAtDirectory(reader, signedDirectoryDataOffset)) {
5020
+ expectedDirectoryDataOffset = signedDirectoryDataOffset;
5021
+ expectedPointsAtDirectory = true;
5022
+ }
5023
+ }
5024
+ if (storedPointsAtDirectory) {
5025
+ reconcile = expectedPointsAtDirectory;
5026
+ }
5005
5027
  }
5006
- if (reconcile) {
5028
+ if (reconcile && expectedDirectoryDataOffset != directoryDataOffset) {
5007
5029
  const originalDirectoryDataOffset = directoryDataOffset;
5008
5030
  directoryDataOffset = expectedDirectoryDataOffset;
5009
- if (directoryDataOffset > originalDirectoryDataOffset) {
5010
- prependedDataLength += directoryDataOffset - originalDirectoryDataOffset;
5011
- prependedCentralDirectory = storedPointsAtDirectory;
5012
- }
5013
5031
  directoryArray = await readUint8Array(reader, directoryDataOffset, directoryDataLength);
5014
5032
  directoryView = getDataView(directoryArray);
5033
+ const offsetDelta = directoryDataOffset - originalDirectoryDataOffset;
5034
+ const localHeaderOffset = getFirstLocalHeaderOffset(directoryArray, directoryView);
5035
+ const localHeaderFound = localHeaderOffset !== UNDEFINED_VALUE &&
5036
+ await startsWithSignature(reader, localHeaderOffset, LOCAL_FILE_HEADER_SIGNATURE);
5037
+ const shiftedLocalHeaderFound = localHeaderOffset !== UNDEFINED_VALUE &&
5038
+ await startsWithSignature(reader, localHeaderOffset + offsetDelta, LOCAL_FILE_HEADER_SIGNATURE);
5039
+ if (offsetDelta > 0 && !(localHeaderFound && !shiftedLocalHeaderFound)) {
5040
+ prependedDataLength += offsetDelta;
5041
+ prependedCentralDirectory = storedPointsAtDirectory;
5042
+ } else {
5043
+ reportAmbiguity(checkAmbiguity, warnings, WARNING_MISMATCHED_CENTRAL_DIRECTORY_OFFSET);
5044
+ if (offsetDelta < 0 && !localHeaderFound && shiftedLocalHeaderFound) {
5045
+ prependedDataLength += offsetDelta;
5046
+ }
5047
+ }
5015
5048
  }
5016
5049
  }
5050
+ if (directoryArray.length < 4) {
5051
+ throw new Error(ERR_BAD_FORMAT);
5052
+ }
5053
+ } else if (!filesLength && directoryDataOffset < centralDirectoryEndOffset && diskNumber == lastDiskNumber) {
5054
+ prependedDataLength += centralDirectoryEndOffset - directoryDataOffset;
5055
+ directoryDataOffset = centralDirectoryEndOffset;
5017
5056
  }
5018
5057
  const expectedDirectoryDataLength = centralDirectoryEndOffset - directoryDataOffset;
5019
5058
  if (directoryDataLength != expectedDirectoryDataLength && expectedDirectoryDataLength >= 0 && diskNumber == lastDiskNumber) {
@@ -5055,8 +5094,10 @@
5055
5094
  addWarning(warnings, WARNING_WRAPPED_ENTRIES_COUNT);
5056
5095
  }
5057
5096
  }
5097
+ const entryOptions = Object.assign({}, zipReader.options, options, { [OPTION_STRICTNESS]: strictness });
5098
+ delete entryOptions[OPTION_CHECK_AMBIGUITY];
5058
5099
  for (let indexFile = 0; indexFile < filesLength; indexFile++) {
5059
- const fileEntry = new ZipEntry$1(reader, zipReader.options);
5100
+ const fileEntry = new ZipEntry$1(reader, entryOptions);
5060
5101
  if (offset + CENTRAL_FILE_HEADER_LENGTH > directoryArray.length || getUint32$1(directoryView, offset) != CENTRAL_FILE_HEADER_SIGNATURE) {
5061
5102
  if (indexFile == 0 && !decryptedDirectory && (zip64EndOfDirectoryVersion2 || detectEncryptedCentralDirectory(directoryView))) {
5062
5103
  throw new Error(ERR_ENCRYPTED_CENTRAL_DIRECTORY);
@@ -5122,7 +5163,16 @@
5122
5163
  filename,
5123
5164
  comment
5124
5165
  });
5125
- const malformedExtraField = readCommonFooter(fileEntry, fileEntry, directoryView, offset + 6);
5166
+ let malformedExtraField;
5167
+ try {
5168
+ malformedExtraField = readCommonFooter(fileEntry, fileEntry, directoryView, offset + 6);
5169
+ } catch (error) {
5170
+ if (checkAmbiguity || error.message != ERR_EXTRAFIELD_ZIP64_NOT_FOUND) {
5171
+ throw error;
5172
+ }
5173
+ fileEntry.zip64ExtraFieldMissing = true;
5174
+ addWarning(warnings, WARNING_MISSING_ZIP64_EXTRA_FIELD, fileEntry.filename);
5175
+ }
5126
5176
  filename = fileEntry.filename;
5127
5177
  if (normalizeFilename) {
5128
5178
  const normalizedFilename = normalizeFilename(filename);
@@ -5138,13 +5188,17 @@
5138
5188
  if (malformedExtraField) {
5139
5189
  addWarning(warnings, WARNING_MALFORMED_EXTRA_FIELD, filename);
5140
5190
  }
5141
- fileEntry.offset += prependedDataLength;
5142
- const entryPosition = getDiskOffset$1(reader, fileEntry.diskNumberStart) + fileEntry.offset;
5143
- startOffset = Math.min(entryPosition, startOffset);
5144
- if (entryPosition < previousEntryPosition) {
5145
- addWarning(warnings, WARNING_UNSORTED_CENTRAL_DIRECTORY, filename);
5191
+ if (fileEntry.zip64ExtraFieldMissing && fileEntry.offset == MAX_32_BITS) {
5192
+ startOffset = 0;
5193
+ } else {
5194
+ fileEntry.offset += prependedDataLength;
5195
+ const entryPosition = getDiskOffset$1(reader, fileEntry.diskNumberStart) + fileEntry.offset;
5196
+ startOffset = Math.min(entryPosition, startOffset);
5197
+ if (entryPosition < previousEntryPosition) {
5198
+ addWarning(warnings, WARNING_UNSORTED_CENTRAL_DIRECTORY, filename);
5199
+ }
5200
+ previousEntryPosition = entryPosition;
5146
5201
  }
5147
- previousEntryPosition = entryPosition;
5148
5202
  if ((fileEntry.version & MAX_8_BITS) > MAX_KNOWN_VERSION) {
5149
5203
  addWarning(warnings, WARNING_UNKNOWN_VERSION, filename);
5150
5204
  }
@@ -5164,11 +5218,12 @@
5164
5218
  const sticky = Boolean(fileEntry.unixMode & FILE_ATTR_UNIX_STICKY_MASK);
5165
5219
  const unixType = fileEntry.unixMode === UNDEFINED_VALUE ? unixExternalUpper : fileEntry.unixMode;
5166
5220
  const symlink = (unixType & FILE_ATTR_UNIX_TYPE_MASK) == FILE_ATTR_UNIX_TYPE_SYMLINK;
5167
- const executable = !symlink && ((fileEntry.unixMode !== UNDEFINED_VALUE)
5168
- ? ((fileEntry.unixMode & FILE_ATTR_UNIX_EXECUTABLE_MASK) != 0)
5169
- : (unixCompatible && ((unixExternalUpper & FILE_ATTR_UNIX_EXECUTABLE_MASK) != 0)));
5170
5221
  const modeIsDir = fileEntry.unixMode !== UNDEFINED_VALUE && ((fileEntry.unixMode & FILE_ATTR_UNIX_TYPE_MASK) == FILE_ATTR_UNIX_TYPE_DIR);
5171
5222
  const upperIsDir = ((unixExternalUpper & FILE_ATTR_UNIX_TYPE_MASK) == FILE_ATTR_UNIX_TYPE_DIR);
5223
+ const directory = modeIsDir || upperIsDir || (msDosCompatible && msdosAttributes.directory) || fileEntry.filename.endsWith(DIRECTORY_SIGNATURE);
5224
+ const executable = !symlink && !directory && ((fileEntry.unixMode !== UNDEFINED_VALUE)
5225
+ ? ((fileEntry.unixMode & FILE_ATTR_UNIX_EXECUTABLE_MASK) != 0)
5226
+ : (unixCompatible && ((unixExternalUpper & FILE_ATTR_UNIX_EXECUTABLE_MASK) != 0)));
5172
5227
  Object.assign(fileEntry, {
5173
5228
  setuid,
5174
5229
  setgid,
@@ -5176,16 +5231,19 @@
5176
5231
  symlink,
5177
5232
  unixExternalUpper,
5178
5233
  executable,
5179
- directory: modeIsDir || upperIsDir || (msDosCompatible && msdosAttributes.directory) || fileEntry.filename.endsWith(DIRECTORY_SIGNATURE),
5234
+ directory,
5180
5235
  zipCrypto: fileEntry.encrypted && !fileEntry.extraFieldAES
5181
5236
  });
5182
5237
  const entry = new Entry(fileEntry);
5183
- entry.getData = (writer, options) => fileEntry.getData(writer, entry, zipReader.readRanges, options);
5238
+ if (fileEntry.zip64ExtraFieldMissing) {
5239
+ zipReader.entriesMissingZip64ExtraField.add(entry);
5240
+ }
5241
+ entry.getData = (writer, options) => fileEntry.getData(writer, entry, zipReader, options);
5184
5242
  entry.arrayBuffer = async options => {
5185
5243
  const writer = new TransformStream();
5186
5244
  const arrayBufferPromise = streamToBlob(writer.readable).then(blob => blob.arrayBuffer());
5187
5245
  arrayBufferPromise.catch(() => { });
5188
- await fileEntry.getData(writer, entry, zipReader.readRanges,
5246
+ await fileEntry.getData(writer, entry, zipReader,
5189
5247
  Object.assign({}, options, { preventClose: false }));
5190
5248
  return arrayBufferPromise;
5191
5249
  };
@@ -5232,10 +5290,10 @@
5232
5290
  const extractAppendedData = getOptionValue$1(zipReader, options, OPTION_EXTRACT_APPENDED_DATA);
5233
5291
  const splitZipSignatureLength = (checkAmbiguity || extractPrependedData) && filesLength &&
5234
5292
  startOffset == SPLIT_ZIP_FILE_SIGNATURE_LENGTH && await startsWithSplitZipMarker(reader) ? SPLIT_ZIP_FILE_SIGNATURE_LENGTH : 0;
5235
- if (checkAmbiguity && (prependedDataLength || (filesLength && startOffset > splitZipSignatureLength))) {
5293
+ if (checkAmbiguity && (prependedDataLength > 0 || (filesLength && startOffset > splitZipSignatureLength))) {
5236
5294
  throwAmbiguousArchive(WARNING_PREPENDED_DATA);
5237
5295
  }
5238
- if (prependedDataLength || (filesLength && startOffset > SPLIT_ZIP_FILE_SIGNATURE_LENGTH)) {
5296
+ if (prependedDataLength > 0 || (filesLength && startOffset > SPLIT_ZIP_FILE_SIGNATURE_LENGTH)) {
5239
5297
  addWarning(warnings, WARNING_PREPENDED_DATA);
5240
5298
  }
5241
5299
  if (prependedCentralDirectory) {
@@ -5393,8 +5451,12 @@
5393
5451
  });
5394
5452
  }
5395
5453
 
5396
- async getData(writer, fileEntry, readRanges, options = {}) {
5454
+ async getData(writer, fileEntry, zipReader, options = {}) {
5397
5455
  const zipEntry = this;
5456
+ const { readRanges, directoryOffset } = zipReader;
5457
+ if (zipEntry.zip64ExtraFieldMissing) {
5458
+ throw new Error(ERR_EXTRAFIELD_ZIP64_NOT_FOUND);
5459
+ }
5398
5460
  const config = getConfiguration();
5399
5461
  const {
5400
5462
  reader,
@@ -5465,10 +5527,10 @@
5465
5527
  }
5466
5528
  validateLocalDirectory(zipEntry, localDirectory, rawLocalFilename, checkLocalFilename, checkLocalDirectory ? UNDEFINED_VALUE : warnings);
5467
5529
  const { lastAccessDate, creationDate, uid, gid } = localDirectory;
5468
- if (lastAccessDate) {
5530
+ if (lastAccessDate && fileEntry.lastAccessDate === UNDEFINED_VALUE) {
5469
5531
  fileEntry.lastAccessDate = lastAccessDate;
5470
5532
  }
5471
- if (creationDate) {
5533
+ if (creationDate && fileEntry.creationDate === UNDEFINED_VALUE) {
5472
5534
  fileEntry.creationDate = creationDate;
5473
5535
  }
5474
5536
  if (uid !== UNDEFINED_VALUE && fileEntry.uid === UNDEFINED_VALUE) {
@@ -5497,7 +5559,7 @@
5497
5559
  throw new Error(ERR_ENCRYPTED);
5498
5560
  }
5499
5561
  }
5500
- if (dataOffset + compressedSize > reader.size) {
5562
+ if (dataOffset + compressedSize > Math.min(reader.size, directoryOffset)) {
5501
5563
  throw new Error(ERR_ENTRY_DATA_OUT_OF_BOUNDS);
5502
5564
  }
5503
5565
  const size = compressedSize;
@@ -5563,6 +5625,7 @@
5563
5625
  extraFieldZip64: extraFieldZip64 || localDirectory.extraFieldZip64,
5564
5626
  readRanges
5565
5627
  });
5628
+ validateDataDescriptor(zipEntry, localDirectory, checkLocalDirectory ? UNDEFINED_VALUE : warnings);
5566
5629
  }
5567
5630
  let writable, abortError, aborted;
5568
5631
  try {
@@ -5582,10 +5645,7 @@
5582
5645
  writer.size += writtenSize;
5583
5646
  }
5584
5647
  } catch (error) {
5585
- const { outputSize: failedOutputSize } = workerOptions;
5586
- if (failedOutputSize !== UNDEFINED_VALUE) {
5587
- writer.size += failedOutputSize;
5588
- } else if (isErrorObject(error) && error.outputSize !== UNDEFINED_VALUE) {
5648
+ if (isErrorObject(error) && error.outputSize !== UNDEFINED_VALUE) {
5589
5649
  writer.size += error.outputSize;
5590
5650
  }
5591
5651
  if (!checkPasswordOnly || !isErrorObject(error) || error.message != ERR_ABORT_CHECK_PASSWORD) {
@@ -5613,13 +5673,7 @@
5613
5673
  };
5614
5674
 
5615
5675
  function detectEncryptedCentralDirectory(directoryView) {
5616
- const maxOffset = Math.min(directoryView.byteLength, 1024) - 3;
5617
- for (let offset = 0; offset < maxOffset; offset++) {
5618
- if (getUint32$1(directoryView, offset) == ARCHIVE_EXTRA_DATA_SIGNATURE) {
5619
- return true;
5620
- }
5621
- }
5622
- return false;
5676
+ return directoryView.byteLength >= 4 && getUint32$1(directoryView, 0) == ARCHIVE_EXTRA_DATA_SIGNATURE;
5623
5677
  }
5624
5678
 
5625
5679
  function getWrappedFilesLength(directoryView, directoryArray, offset) {
@@ -5632,6 +5686,70 @@
5632
5686
  return wrappedFilesLength % (MAX_16_BITS + 1) ? 0 : wrappedFilesLength;
5633
5687
  }
5634
5688
 
5689
+ function pointsAtDirectory(reader, offset) {
5690
+ return startsWithSignature(reader, offset, CENTRAL_FILE_HEADER_SIGNATURE);
5691
+ }
5692
+
5693
+ async function startsWithSignature(reader, offset, signature) {
5694
+ if (offset < 0 || offset + 4 > reader.size) {
5695
+ return false;
5696
+ }
5697
+ const signatureArray = await readUint8Array(reader, offset, 4);
5698
+ return getUint32$1(getDataView(signatureArray), 0) == signature;
5699
+ }
5700
+
5701
+ async function findDigitalSignatureRecordOffset(reader, endOffset) {
5702
+ const startOffset = Math.max(0, endOffset - (6 + MAX_16_BITS));
5703
+ const tailArray = await readUint8Array(reader, startOffset, endOffset - startOffset);
5704
+ const tailView = getDataView(tailArray);
5705
+ for (let indexByte = tailArray.length - 6; indexByte >= 0; indexByte--) {
5706
+ if (getUint32$1(tailView, indexByte) == DIGITAL_SIGNATURE_RECORD_SIGNATURE &&
5707
+ indexByte + 6 + getUint16$1(tailView, indexByte + 4) == tailArray.length) {
5708
+ return startOffset + indexByte;
5709
+ }
5710
+ }
5711
+ }
5712
+
5713
+ async function findZip64EndOfDirectoryOffset(reader, endOffset) {
5714
+ const startOffset = Math.max(0, endOffset - (ZIP64_END_OF_CENTRAL_DIR_LENGTH + MAX_16_BITS));
5715
+ const tailArray = await readUint8Array(reader, startOffset, endOffset - startOffset);
5716
+ const tailView = getDataView(tailArray);
5717
+ for (let indexByte = tailArray.length - ZIP64_END_OF_CENTRAL_DIR_LENGTH; indexByte >= 0; indexByte--) {
5718
+ if (getUint32$1(tailView, indexByte) == ZIP64_END_OF_CENTRAL_DIR_SIGNATURE &&
5719
+ indexByte + 12 + Number(tailView.getBigUint64(indexByte + 4, true)) == tailArray.length) {
5720
+ return startOffset + indexByte;
5721
+ }
5722
+ }
5723
+ }
5724
+
5725
+ function getFirstLocalHeaderOffset(directoryArray, directoryView) {
5726
+ if (directoryArray.length < CENTRAL_FILE_HEADER_LENGTH) {
5727
+ return UNDEFINED_VALUE;
5728
+ }
5729
+ const localHeaderOffset = getUint32$1(directoryView, 42);
5730
+ if (localHeaderOffset != MAX_32_BITS) {
5731
+ return localHeaderOffset;
5732
+ }
5733
+ let offsetExtraField = CENTRAL_FILE_HEADER_LENGTH + getUint16$1(directoryView, 28);
5734
+ const endExtraField = Math.min(offsetExtraField + getUint16$1(directoryView, 30), directoryArray.length);
5735
+ while (offsetExtraField + 4 <= endExtraField) {
5736
+ const type = getUint16$1(directoryView, offsetExtraField);
5737
+ const size = getUint16$1(directoryView, offsetExtraField + 2);
5738
+ if (type == EXTRAFIELD_TYPE_ZIP64) {
5739
+ let offsetValue = offsetExtraField + 4;
5740
+ if (getUint32$1(directoryView, 24) == MAX_32_BITS) {
5741
+ offsetValue += 8;
5742
+ }
5743
+ if (getUint32$1(directoryView, 20) == MAX_32_BITS) {
5744
+ offsetValue += 8;
5745
+ }
5746
+ return offsetValue + 8 <= endExtraField ? getBigUint64(directoryView, offsetValue) : UNDEFINED_VALUE;
5747
+ }
5748
+ offsetExtraField += 4 + size;
5749
+ }
5750
+ return UNDEFINED_VALUE;
5751
+ }
5752
+
5635
5753
  function readDigitalSignature(signatureRecordArray) {
5636
5754
  if (signatureRecordArray.length >= 6) {
5637
5755
  const signatureRecordView = getDataView(signatureRecordArray);
@@ -5721,6 +5839,7 @@
5721
5839
  uncompressedSize: getUint32$1(dataView, offset + HEADER_OFFSET_UNCOMPRESSED_SIZE)
5722
5840
  });
5723
5841
  const extraFieldZip64 = extraField.get(EXTRAFIELD_TYPE_ZIP64);
5842
+ let extraFieldZip64Missing;
5724
5843
  if (extraFieldZip64) {
5725
5844
  if (!readExtraFieldZip64(extraFieldZip64, directory, localDirectory)) {
5726
5845
  malformedExtraField = true;
@@ -5730,7 +5849,7 @@
5730
5849
  if (localDirectory) {
5731
5850
  malformedExtraField = true;
5732
5851
  } else {
5733
- throw new Error(ERR_EXTRAFIELD_ZIP64_NOT_FOUND);
5852
+ extraFieldZip64Missing = true;
5734
5853
  }
5735
5854
  }
5736
5855
  const extraFieldUnicodePath = extraField.get(EXTRAFIELD_TYPE_UNICODE_PATH);
@@ -5763,6 +5882,11 @@
5763
5882
  readExtraFieldUnixDates(extraFieldUnixType1, directory);
5764
5883
  directory.extraFieldUnixType1 = extraFieldUnixType1;
5765
5884
  }
5885
+ const extraFieldExtendedTimestamp = extraField.get(EXTRAFIELD_TYPE_EXTENDED_TIMESTAMP);
5886
+ if (extraFieldExtendedTimestamp) {
5887
+ readExtraFieldExtendedTimestamp(extraFieldExtendedTimestamp, directory, localDirectory);
5888
+ directory.extraFieldExtendedTimestamp = extraFieldExtendedTimestamp;
5889
+ }
5766
5890
  const extraFieldNTFS = extraField.get(EXTRAFIELD_TYPE_NTFS);
5767
5891
  if (extraFieldNTFS) {
5768
5892
  readExtraFieldNTFS(extraFieldNTFS, directory);
@@ -5779,15 +5903,13 @@
5779
5903
  readExtraFieldUnix(extraFieldUnix, unixIdsRead ? {} : directory, false);
5780
5904
  directory.extraFieldUnix = extraFieldUnix;
5781
5905
  }
5782
- const extraFieldExtendedTimestamp = extraField.get(EXTRAFIELD_TYPE_EXTENDED_TIMESTAMP);
5783
- if (extraFieldExtendedTimestamp) {
5784
- readExtraFieldExtendedTimestamp(extraFieldExtendedTimestamp, directory, localDirectory);
5785
- directory.extraFieldExtendedTimestamp = extraFieldExtendedTimestamp;
5786
- }
5787
5906
  const extraFieldUSDZ = extraField.get(EXTRAFIELD_TYPE_USDZ);
5788
5907
  if (extraFieldUSDZ) {
5789
5908
  directory.extraFieldUSDZ = extraFieldUSDZ;
5790
5909
  }
5910
+ if (extraFieldZip64Missing) {
5911
+ throw new Error(ERR_EXTRAFIELD_ZIP64_NOT_FOUND);
5912
+ }
5791
5913
  return malformedExtraField;
5792
5914
  }
5793
5915
 
@@ -6002,13 +6124,7 @@
6002
6124
  let dataDescriptorLength = 0;
6003
6125
  if (dataDescriptor) {
6004
6126
  const zip64 = Boolean(extraFieldZip64);
6005
- const dataDescriptorArray = await readUint8Array(reader, dataOffset + compressedSize, DATA_DESCRIPTOR_RECORD_ZIP_64_LENGTH + DATA_DESCRIPTOR_RECORD_SIGNATURE_LENGTH);
6006
- const dataDescriptorView = getDataView(dataDescriptorArray);
6007
- const candidates = [[zip64, true], [zip64, false], [!zip64, true], [!zip64, false]]
6008
- .map(([zip64Layout, signature]) => readDataDescriptor(dataDescriptorView, zip64Layout, signature))
6009
- .filter(candidate => candidate && candidate.compressedSize == compressedSize && candidate.uncompressedSize == uncompressedSize);
6010
- const localDataDescriptor = candidates.find(candidate => candidate.crc32 == crc32) || candidates[0] ||
6011
- readDataDescriptor(dataDescriptorView, zip64, true) || readDataDescriptor(dataDescriptorView, zip64, false);
6127
+ const localDataDescriptor = await readLocalDataDescriptor(reader, dataOffset + compressedSize, { crc32, compressedSize, uncompressedSize, zip64 });
6012
6128
  if (localDataDescriptor) {
6013
6129
  fileEntry.localDirectory.dataDescriptor = localDataDescriptor;
6014
6130
  dataDescriptorLength = getDataDescriptorLength(localDataDescriptor.zip64, localDataDescriptor.signature);
@@ -6078,6 +6194,25 @@
6078
6194
  return mergedRanges;
6079
6195
  }
6080
6196
 
6197
+ async function readLocalDataDescriptor(reader, offset, { crc32, compressedSize, uncompressedSize, zip64 }) {
6198
+ const maxLength = DATA_DESCRIPTOR_RECORD_ZIP_64_LENGTH + DATA_DESCRIPTOR_RECORD_SIGNATURE_LENGTH;
6199
+ const length = Math.min(maxLength, Math.max(0, reader.size - offset));
6200
+ const dataDescriptorArray = length ? await readUint8Array(reader, offset, length) : EMPTY_UINT8_ARRAY;
6201
+ const dataDescriptorView = getDataView(dataDescriptorArray);
6202
+ const candidates = [[zip64, true], [zip64, false], [!zip64, true], [!zip64, false]]
6203
+ .map(([zip64Layout, signature]) => readDataDescriptor(dataDescriptorView, zip64Layout, signature))
6204
+ .filter(candidate => candidate && candidate.compressedSize == compressedSize && candidate.uncompressedSize == uncompressedSize);
6205
+ return candidates.find(candidate => candidate.crc32 == crc32) || candidates[0] ||
6206
+ readDataDescriptor(dataDescriptorView, zip64, true) || readDataDescriptor(dataDescriptorView, zip64, false);
6207
+ }
6208
+
6209
+ async function getEntryDataDescriptorLength(reader, offset, { crc32, compressedSize, uncompressedSize, extraFieldZip64 }) {
6210
+ const dataDescriptor = await readLocalDataDescriptor(reader, offset, { crc32, compressedSize, uncompressedSize, zip64: Boolean(extraFieldZip64) });
6211
+ if (dataDescriptor && dataDescriptor.compressedSize == compressedSize && dataDescriptor.uncompressedSize == uncompressedSize) {
6212
+ return getDataDescriptorLength(dataDescriptor.zip64, dataDescriptor.signature);
6213
+ }
6214
+ }
6215
+
6081
6216
  function readDataDescriptor(dataDescriptorView, zip64, signature) {
6082
6217
  const offset = signature ? DATA_DESCRIPTOR_RECORD_SIGNATURE_LENGTH : 0;
6083
6218
  if (dataDescriptorView.byteLength < getDataDescriptorLength(zip64, signature) ||
@@ -6337,6 +6472,18 @@
6337
6472
  }
6338
6473
  }
6339
6474
 
6475
+ function validateDataDescriptor(zipEntry, localDirectory, warnings) {
6476
+ const { dataDescriptor } = localDirectory;
6477
+ const maskedLocalDirectory = zipEntry.decryptedDirectory &&
6478
+ (localDirectory.rawBitFlag & BITFLAG_MASKED_LOCAL_HEADERS) == BITFLAG_MASKED_LOCAL_HEADERS;
6479
+ if (dataDescriptor && !maskedLocalDirectory &&
6480
+ ((zipEntry.crc32 !== UNDEFINED_VALUE && dataDescriptor.crc32 != zipEntry.crc32) ||
6481
+ dataDescriptor.compressedSize != zipEntry.compressedSize ||
6482
+ dataDescriptor.uncompressedSize != zipEntry.uncompressedSize)) {
6483
+ reportAmbiguity(!warnings, warnings, WARNING_MISMATCHED_LOCAL_FILE_HEADER_CRC32_OR_SIZES);
6484
+ }
6485
+ }
6486
+
6340
6487
  function reportAmbiguity(reject, warnings, reason) {
6341
6488
  if (reject) {
6342
6489
  throwAmbiguousArchive(reason);
@@ -6422,11 +6569,13 @@
6422
6569
  WARNING_COMPRESSED_PATCHED_DATA: WARNING_COMPRESSED_PATCHED_DATA,
6423
6570
  WARNING_DUPLICATE_FILENAME: WARNING_DUPLICATE_FILENAME,
6424
6571
  WARNING_MALFORMED_EXTRA_FIELD: WARNING_MALFORMED_EXTRA_FIELD,
6572
+ WARNING_MISMATCHED_CENTRAL_DIRECTORY_OFFSET: WARNING_MISMATCHED_CENTRAL_DIRECTORY_OFFSET,
6425
6573
  WARNING_MISMATCHED_LOCAL_FILE_HEADER_BIT_FLAG: WARNING_MISMATCHED_LOCAL_FILE_HEADER_BIT_FLAG,
6426
6574
  WARNING_MISMATCHED_LOCAL_FILE_HEADER_COMPRESSION_METHOD: WARNING_MISMATCHED_LOCAL_FILE_HEADER_COMPRESSION_METHOD,
6427
6575
  WARNING_MISMATCHED_LOCAL_FILE_HEADER_CRC32_OR_SIZES: WARNING_MISMATCHED_LOCAL_FILE_HEADER_CRC32_OR_SIZES,
6428
6576
  WARNING_MISMATCHED_LOCAL_FILE_HEADER_FILENAME: WARNING_MISMATCHED_LOCAL_FILE_HEADER_FILENAME,
6429
6577
  WARNING_MISMATCHED_ZIP64_END_OF_CENTRAL_DIRECTORY: WARNING_MISMATCHED_ZIP64_END_OF_CENTRAL_DIRECTORY,
6578
+ WARNING_MISSING_ZIP64_EXTRA_FIELD: WARNING_MISSING_ZIP64_EXTRA_FIELD,
6430
6579
  WARNING_MULTIPLE_END_OF_CENTRAL_DIRECTORY: WARNING_MULTIPLE_END_OF_CENTRAL_DIRECTORY,
6431
6580
  WARNING_PREPENDED_CENTRAL_DIRECTORY: WARNING_PREPENDED_CENTRAL_DIRECTORY,
6432
6581
  WARNING_PREPENDED_DATA: WARNING_PREPENDED_DATA,
@@ -6437,6 +6586,7 @@
6437
6586
  WARNING_WRAPPED_ENTRIES_COUNT: WARNING_WRAPPED_ENTRIES_COUNT,
6438
6587
  ZipReader: ZipReader,
6439
6588
  ZipReaderStream: ZipReaderStream,
6589
+ getEntryDataDescriptorLength: getEntryDataDescriptorLength,
6440
6590
  isZipFile: isZipFile
6441
6591
  });
6442
6592
 
@@ -6559,130 +6709,8 @@
6559
6709
  return watchPromiseError(this, prependZipEntries(this, reader));
6560
6710
  }
6561
6711
 
6562
- appendZip(reader) {
6563
- return watchPromiseError(this, this.appendZipEntries(reader));
6564
- }
6565
-
6566
- async appendZipEntries(reader) {
6567
- const zipWriter = this;
6568
- const { pendingAddFileCalls, filenames, fileEntries } = zipWriter;
6569
- while (pendingAddFileCalls.size) {
6570
- await Promise.allSettled(Array.from(pendingAddFileCalls));
6571
- }
6572
- let resolveAppendZip;
6573
- const promiseAppendZip = new Promise(resolve => resolveAppendZip = resolve);
6574
- pendingAddFileCalls.add(promiseAppendZip);
6575
- const appendedFilenames = [];
6576
- let releaseLockWriter;
6577
- try {
6578
- reader = new GenericReader(reader);
6579
- await initStream(reader);
6580
- if (reader.size === UNDEFINED_VALUE || !reader.readUint8Array) {
6581
- reader = new BlobReader(await streamToBlob(reader.readable));
6582
- await initStream(reader);
6583
- }
6584
- const { ZipReader } = await Promise.resolve().then(function () { return zipReader; });
6585
- const zipReader$1 = new ZipReader(reader);
6586
- const entries = await zipReader$1.getEntries();
6587
- await zipReader$1.close();
6588
- await initStream(zipWriter.writer);
6589
- const { directoryOffset } = zipReader$1;
6590
- entries.forEach(({ filename }) => {
6591
- if (filenames.has(filename)) {
6592
- throw new Error(ERR_DUPLICATED_NAME);
6593
- }
6594
- filenames.add(filename);
6595
- appendedFilenames.push(filename);
6596
- });
6597
- zipWriter.writerLocked = true;
6598
- const { lockWriter } = zipWriter;
6599
- zipWriter.lockWriter = new Promise(resolve => releaseLockWriter = () => {
6600
- zipWriter.writerLocked = false;
6601
- resolve();
6602
- });
6603
- await lockWriter;
6604
- if (zipWriter.addSplitZipSignature) {
6605
- delete zipWriter.addSplitZipSignature;
6606
- if (!await startsWithSplitZipSignature(reader)) {
6607
- await writeData(zipWriter.writer, getSplitZipSignatureArray());
6608
- zipWriter.offset += SPLIT_ZIP_FILE_SIGNATURE_LENGTH;
6609
- }
6610
- }
6611
- const entryPositions = await copyZipData(zipWriter, reader, entries, directoryOffset);
6612
- entries.forEach(entry => {
6613
- const {
6614
- version,
6615
- rawLastModDate,
6616
- rawFilename,
6617
- bitFlag,
6618
- encrypted,
6619
- uncompressedSize,
6620
- compressedSize,
6621
- extraFieldZip64
6622
- } = entry;
6623
- let {
6624
- compressionMethod,
6625
- rawExtraField,
6626
- } = entry;
6627
- const { level, languageEncodingFlag, dataDescriptor } = bitFlag;
6628
- rawExtraField = removeExtraFieldZip64(rawExtraField || EMPTY_UINT8_ARRAY);
6629
- if (entry.extraFieldAES) {
6630
- compressionMethod = COMPRESSION_METHOD_AES;
6631
- }
6632
- const extraFieldLength = getLength(rawExtraField);
6633
- const zip64UncompressedSize = Boolean(extraFieldZip64) && extraFieldZip64.uncompressedSize !== UNDEFINED_VALUE;
6634
- const zip64CompressedSize = Boolean(extraFieldZip64) && extraFieldZip64.compressedSize !== UNDEFINED_VALUE;
6635
- const bitFlagValue = (getBitFlag(level, languageEncodingFlag, dataDescriptor, encrypted, compressionMethod) & ~BITFLAG_LEVEL) | (level << 1);
6636
- const {
6637
- headerArray,
6638
- headerView
6639
- } = getHeaderArrayData({
6640
- version,
6641
- bitFlag: bitFlagValue,
6642
- compressionMethod,
6643
- uncompressedSize,
6644
- compressedSize,
6645
- rawLastModDate,
6646
- rawFilename,
6647
- zip64CompressedSize,
6648
- zip64UncompressedSize,
6649
- extraFieldLength
6650
- });
6651
- const { crc32 } = entry;
6652
- if (crc32 !== UNDEFINED_VALUE) {
6653
- setUint32(headerView, HEADER_OFFSET_SIGNATURE, crc32);
6654
- }
6655
- const { offset, diskNumberStart } = entryPositions.get(entry);
6656
- Object.assign(entry, {
6657
- zip64Enabled: true,
6658
- zip64UncompressedSize,
6659
- zip64CompressedSize,
6660
- offset,
6661
- diskNumberStart,
6662
- zip64DiskNumberStart: false,
6663
- rawExtraFieldZip64: EMPTY_UINT8_ARRAY,
6664
- rawExtraFieldAES: EMPTY_UINT8_ARRAY,
6665
- rawExtraFieldExtendedTimestamp: EMPTY_UINT8_ARRAY,
6666
- rawExtraFieldNTFS: EMPTY_UINT8_ARRAY,
6667
- rawExtraFieldUnix: EMPTY_UINT8_ARRAY,
6668
- rawCentralExtraFieldUnix: EMPTY_UINT8_ARRAY,
6669
- rawExtraField,
6670
- rawCentralExtraField: EMPTY_UINT8_ARRAY,
6671
- headerArray,
6672
- headerView
6673
- });
6674
- fileEntries.set(entry.filename, entry);
6675
- });
6676
- } catch (error) {
6677
- appendedFilenames.forEach(filename => filenames.delete(filename));
6678
- throw error;
6679
- } finally {
6680
- resolveAppendZip();
6681
- pendingAddFileCalls.delete(promiseAppendZip);
6682
- if (releaseLockWriter) {
6683
- releaseLockWriter();
6684
- }
6685
- }
6712
+ appendZip(reader, options = {}) {
6713
+ return watchPromiseError(this, appendZipEntries(this, reader, options));
6686
6714
  }
6687
6715
 
6688
6716
  add(name = "", reader, options = {}) {
@@ -6844,11 +6872,140 @@
6844
6872
  return watchedPromise;
6845
6873
  }
6846
6874
 
6875
+ async function appendZipEntries(zipWriter, reader, options = {}) {
6876
+ const { pendingAddFileCalls, filenames, fileEntries } = zipWriter;
6877
+ const filter = checkFunctionOption(options.filter);
6878
+ while (pendingAddFileCalls.size) {
6879
+ await Promise.allSettled(Array.from(pendingAddFileCalls));
6880
+ }
6881
+ let resolveAppendZip;
6882
+ const promiseAppendZip = new Promise(resolve => resolveAppendZip = resolve);
6883
+ pendingAddFileCalls.add(promiseAppendZip);
6884
+ const appendedFilenames = [];
6885
+ let releaseLockWriter;
6886
+ try {
6887
+ reader = new GenericReader(reader);
6888
+ await initStream(reader);
6889
+ if (reader.size === UNDEFINED_VALUE || !reader.readUint8Array) {
6890
+ reader = new BlobReader(await streamToBlob(reader.readable));
6891
+ await initStream(reader);
6892
+ }
6893
+ const { ZipReader, getEntryDataDescriptorLength } = await Promise.resolve().then(function () { return zipReader; });
6894
+ const zipReader$1 = new ZipReader(reader);
6895
+ const entries = await zipReader$1.getEntries();
6896
+ const keptEntries = [];
6897
+ for (const entry of entries) {
6898
+ if (!filter || await filter(entry)) {
6899
+ keptEntries.push(entry);
6900
+ }
6901
+ }
6902
+ await zipReader$1.close();
6903
+ await initStream(zipWriter.writer);
6904
+ const { directoryOffset, entriesMissingZip64ExtraField } = zipReader$1;
6905
+ keptEntries.forEach(entry => {
6906
+ const { filename } = entry;
6907
+ if (entriesMissingZip64ExtraField.has(entry)) {
6908
+ throw new Error(ERR_EXTRAFIELD_ZIP64_NOT_FOUND);
6909
+ }
6910
+ if (filenames.has(filename)) {
6911
+ throw new Error(ERR_DUPLICATED_NAME);
6912
+ }
6913
+ filenames.add(filename);
6914
+ appendedFilenames.push(filename);
6915
+ });
6916
+ zipWriter.writerLocked = true;
6917
+ const { lockWriter } = zipWriter;
6918
+ zipWriter.lockWriter = new Promise(resolve => releaseLockWriter = () => {
6919
+ zipWriter.writerLocked = false;
6920
+ resolve();
6921
+ });
6922
+ await lockWriter;
6923
+ if (zipWriter.addSplitZipSignature) {
6924
+ delete zipWriter.addSplitZipSignature;
6925
+ if (filter || !await startsWithSplitZipSignature(reader)) {
6926
+ await writeData(zipWriter.writer, getSplitZipSignatureArray());
6927
+ zipWriter.offset += SPLIT_ZIP_FILE_SIGNATURE_LENGTH;
6928
+ }
6929
+ }
6930
+ const entryPositions = await copyZipData(zipWriter, reader, entries, keptEntries, directoryOffset, Boolean(filter), getEntryDataDescriptorLength);
6931
+ keptEntries.forEach(entry => {
6932
+ const {
6933
+ version,
6934
+ rawLastModDate,
6935
+ rawFilename,
6936
+ rawBitFlag,
6937
+ uncompressedSize,
6938
+ compressedSize,
6939
+ extraFieldZip64
6940
+ } = entry;
6941
+ let {
6942
+ compressionMethod,
6943
+ rawExtraField,
6944
+ } = entry;
6945
+ rawExtraField = removeExtraFieldZip64(rawExtraField || EMPTY_UINT8_ARRAY);
6946
+ if (entry.extraFieldAES) {
6947
+ compressionMethod = COMPRESSION_METHOD_AES;
6948
+ }
6949
+ const extraFieldLength = getLength(rawExtraField);
6950
+ const zip64UncompressedSize = Boolean(extraFieldZip64) && extraFieldZip64.uncompressedSize !== UNDEFINED_VALUE;
6951
+ const zip64CompressedSize = Boolean(extraFieldZip64) && extraFieldZip64.compressedSize !== UNDEFINED_VALUE;
6952
+ const {
6953
+ headerArray,
6954
+ headerView
6955
+ } = getHeaderArrayData({
6956
+ version,
6957
+ bitFlag: rawBitFlag,
6958
+ compressionMethod,
6959
+ uncompressedSize,
6960
+ compressedSize,
6961
+ rawLastModDate,
6962
+ rawFilename,
6963
+ zip64CompressedSize,
6964
+ zip64UncompressedSize,
6965
+ extraFieldLength
6966
+ });
6967
+ const { crc32 } = entry;
6968
+ if (crc32 !== UNDEFINED_VALUE) {
6969
+ setUint32(headerView, HEADER_OFFSET_SIGNATURE, crc32);
6970
+ }
6971
+ const { offset, diskNumberStart } = entryPositions.get(entry);
6972
+ Object.assign(entry, {
6973
+ zip64Enabled: true,
6974
+ zip64UncompressedSize,
6975
+ zip64CompressedSize,
6976
+ offset,
6977
+ diskNumberStart,
6978
+ zip64DiskNumberStart: false,
6979
+ rawExtraFieldZip64: EMPTY_UINT8_ARRAY,
6980
+ rawExtraFieldAES: EMPTY_UINT8_ARRAY,
6981
+ rawExtraFieldExtendedTimestamp: EMPTY_UINT8_ARRAY,
6982
+ rawExtraFieldNTFS: EMPTY_UINT8_ARRAY,
6983
+ rawExtraFieldUnix: EMPTY_UINT8_ARRAY,
6984
+ rawCentralExtraFieldUnix: EMPTY_UINT8_ARRAY,
6985
+ rawExtraField,
6986
+ rawCentralExtraField: EMPTY_UINT8_ARRAY,
6987
+ headerArray,
6988
+ headerView
6989
+ });
6990
+ fileEntries.set(entry.filename, entry);
6991
+ });
6992
+ } catch (error) {
6993
+ appendedFilenames.forEach(filename => filenames.delete(filename));
6994
+ throw error;
6995
+ } finally {
6996
+ resolveAppendZip();
6997
+ pendingAddFileCalls.delete(promiseAppendZip);
6998
+ if (releaseLockWriter) {
6999
+ releaseLockWriter();
7000
+ }
7001
+ }
7002
+ }
7003
+
6847
7004
  async function prependZipEntries(zipWriter, reader) {
6848
7005
  if (zipWriter.filenames.size) {
6849
7006
  throw new Error(ERR_ZIP_NOT_EMPTY);
6850
7007
  }
6851
- await zipWriter.appendZipEntries(reader);
7008
+ await appendZipEntries(zipWriter, reader);
6852
7009
  }
6853
7010
 
6854
7011
  async function addFileEntry(zipWriter, name, reader, options) {
@@ -8620,26 +8777,63 @@
8620
8777
  return rawExtraField;
8621
8778
  }
8622
8779
 
8623
- async function copyZipData(zipWriter, reader, entries, directoryOffset) {
8780
+ async function copyZipData(zipWriter, reader, entries, keptEntries, directoryOffset, compact, getEntryDataDescriptorLength) {
8624
8781
  const { writer } = zipWriter;
8625
8782
  const entryPositions = new Map();
8626
- if (writer.closeDisk) {
8783
+ if (writer.closeDisk || compact) {
8627
8784
  const sortedEntries = Array.from(entries).sort((firstEntry, secondEntry) =>
8628
8785
  getSourceOffset(reader, firstEntry) - getSourceOffset(reader, secondEntry));
8629
- let copiedLength = 0;
8630
- for (const entry of sortedEntries) {
8631
- const sourceOffset = getSourceOffset(reader, entry);
8632
- await copyData(zipWriter, reader, copiedLength, sourceOffset - copiedLength);
8633
- if (exceedsAvailableSize(writer, await getLocalHeaderLength(reader, sourceOffset))) {
8634
- await writer.closeDisk();
8635
- }
8636
- entryPositions.set(entry, {
8637
- offset: getSegmentOffset(zipWriter, writer),
8638
- diskNumberStart: getDiskNumber(writer)
8639
- });
8640
- copiedLength = sourceOffset;
8786
+ const regionEnds = getRegionEnds(reader, sortedEntries, directoryOffset);
8787
+ const keptEntrySet = new Set(keptEntries);
8788
+ const localHeaderLengths = new Map();
8789
+ for (let indexEntry = 0; indexEntry < sortedEntries.length; indexEntry++) {
8790
+ const entry = sortedEntries[indexEntry];
8791
+ if (keptEntrySet.has(entry)) {
8792
+ const sourceOffset = getSourceOffset(reader, entry);
8793
+ const localHeaderLength = await getLocalHeaderLength(reader, sourceOffset);
8794
+ if (localHeaderLength === UNDEFINED_VALUE) {
8795
+ throw new Error(ERR_LOCAL_FILE_HEADER_NOT_FOUND);
8796
+ }
8797
+ let entryEnd = sourceOffset + localHeaderLength + entry.compressedSize;
8798
+ if (entry.bitFlag.dataDescriptor) {
8799
+ const dataDescriptorLength = await getEntryDataDescriptorLength(reader, entryEnd, entry);
8800
+ entryEnd = dataDescriptorLength === UNDEFINED_VALUE ? Math.max(entryEnd, regionEnds[indexEntry]) : entryEnd + dataDescriptorLength;
8801
+ }
8802
+ if (entryEnd > regionEnds[indexEntry]) {
8803
+ throw new Error(ERR_OVERLAPPING_ENTRY);
8804
+ }
8805
+ regionEnds[indexEntry] = entryEnd;
8806
+ localHeaderLengths.set(entry, localHeaderLength);
8807
+ }
8808
+ }
8809
+ let copiedOffset = 0;
8810
+ let lastPosition;
8811
+ for (let indexEntry = 0; indexEntry < sortedEntries.length; indexEntry++) {
8812
+ const entry = sortedEntries[indexEntry];
8813
+ if (keptEntrySet.has(entry)) {
8814
+ const sourceOffset = getSourceOffset(reader, entry);
8815
+ if (sourceOffset < copiedOffset) {
8816
+ entryPositions.set(entry, lastPosition);
8817
+ } else {
8818
+ if (!compact) {
8819
+ await copyData(zipWriter, reader, copiedOffset, sourceOffset - copiedOffset);
8820
+ }
8821
+ if (writer.closeDisk && exceedsAvailableSize(writer, localHeaderLengths.get(entry))) {
8822
+ await writer.closeDisk();
8823
+ }
8824
+ lastPosition = {
8825
+ offset: getSegmentOffset(zipWriter, writer),
8826
+ diskNumberStart: getDiskNumber(writer)
8827
+ };
8828
+ entryPositions.set(entry, lastPosition);
8829
+ await copyData(zipWriter, reader, sourceOffset, regionEnds[indexEntry] - sourceOffset);
8830
+ copiedOffset = regionEnds[indexEntry];
8831
+ }
8832
+ }
8833
+ }
8834
+ if (!compact) {
8835
+ await copyData(zipWriter, reader, copiedOffset, directoryOffset - copiedOffset);
8641
8836
  }
8642
- await copyData(zipWriter, reader, copiedLength, directoryOffset - copiedLength);
8643
8837
  } else {
8644
8838
  const baseOffset = zipWriter.offset;
8645
8839
  await copyData(zipWriter, reader, 0, directoryOffset);
@@ -8651,6 +8845,20 @@
8651
8845
  return entryPositions;
8652
8846
  }
8653
8847
 
8848
+ function getRegionEnds(reader, sortedEntries, directoryOffset) {
8849
+ const regionEnds = new Array(sortedEntries.length);
8850
+ let regionEnd = directoryOffset;
8851
+ for (let indexEntry = sortedEntries.length - 1; indexEntry >= 0; indexEntry--) {
8852
+ const sourceOffset = getSourceOffset(reader, sortedEntries[indexEntry]);
8853
+ const nextEntry = sortedEntries[indexEntry + 1];
8854
+ if (nextEntry && getSourceOffset(reader, nextEntry) > sourceOffset) {
8855
+ regionEnd = Math.min(getSourceOffset(reader, nextEntry), directoryOffset);
8856
+ }
8857
+ regionEnds[indexEntry] = regionEnd;
8858
+ }
8859
+ return regionEnds;
8860
+ }
8861
+
8654
8862
  async function copyData(zipWriter, reader, offset, size) {
8655
8863
  if (size > 0) {
8656
8864
  const { writer } = zipWriter;
@@ -8658,11 +8866,13 @@
8658
8866
  try {
8659
8867
  await flushBufferedData(createReadable(reader, { offset, size }), writer, UNDEFINED_VALUE, chunkLength => copiedLength += chunkLength);
8660
8868
  } catch (error) {
8661
- zipWriter.hasCorruptedEntries = true;
8662
- try {
8663
- error.corruptedEntry = true;
8664
- } catch {
8665
- // ignored
8869
+ if (copiedLength) {
8870
+ zipWriter.hasCorruptedEntries = true;
8871
+ try {
8872
+ error.corruptedEntry = true;
8873
+ } catch {
8874
+ // ignored
8875
+ }
8666
8876
  }
8667
8877
  throw error;
8668
8878
  } finally {
@@ -8673,11 +8883,16 @@
8673
8883
  }
8674
8884
 
8675
8885
  async function getLocalHeaderLength(reader, offset) {
8676
- const headerArray = await readUint8Array(reader, offset, HEADER_SIZE);
8886
+ const headerArray = offset >= 0 && offset + HEADER_SIZE <= reader.size ?
8887
+ await readUint8Array(reader, offset, HEADER_SIZE) :
8888
+ EMPTY_UINT8_ARRAY;
8677
8889
  if (getLength(headerArray) < HEADER_SIZE) {
8678
- return HEADER_SIZE;
8890
+ return UNDEFINED_VALUE;
8679
8891
  }
8680
8892
  const headerView = getDataView(headerArray);
8893
+ if (getUint32(headerView, 0) != LOCAL_FILE_HEADER_SIGNATURE) {
8894
+ return UNDEFINED_VALUE;
8895
+ }
8681
8896
  return HEADER_SIZE +
8682
8897
  getUint16(headerView, HEADER_OFFSET_FILENAME_LENGTH + LOCAL_HEADER_COMMON_OFFSET) +
8683
8898
  getUint16(headerView, HEADER_OFFSET_EXTRAFIELD_LENGTH + LOCAL_HEADER_COMMON_OFFSET);
@@ -9028,7 +9243,7 @@
9028
9243
  EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
9029
9244
  */
9030
9245
 
9031
- const VERSION = "2.19.0";
9246
+ const VERSION = "2.21.0";
9032
9247
 
9033
9248
  /*
9034
9249
  Copyright (c) 2025 Gildas Lormeau. All rights reserved.
@@ -11768,11 +11983,13 @@
11768
11983
  exports.WARNING_COMPRESSION_UNAVAILABLE = WARNING_COMPRESSION_UNAVAILABLE;
11769
11984
  exports.WARNING_DUPLICATE_FILENAME = WARNING_DUPLICATE_FILENAME;
11770
11985
  exports.WARNING_MALFORMED_EXTRA_FIELD = WARNING_MALFORMED_EXTRA_FIELD;
11986
+ exports.WARNING_MISMATCHED_CENTRAL_DIRECTORY_OFFSET = WARNING_MISMATCHED_CENTRAL_DIRECTORY_OFFSET;
11771
11987
  exports.WARNING_MISMATCHED_LOCAL_FILE_HEADER_BIT_FLAG = WARNING_MISMATCHED_LOCAL_FILE_HEADER_BIT_FLAG;
11772
11988
  exports.WARNING_MISMATCHED_LOCAL_FILE_HEADER_COMPRESSION_METHOD = WARNING_MISMATCHED_LOCAL_FILE_HEADER_COMPRESSION_METHOD;
11773
11989
  exports.WARNING_MISMATCHED_LOCAL_FILE_HEADER_CRC32_OR_SIZES = WARNING_MISMATCHED_LOCAL_FILE_HEADER_CRC32_OR_SIZES;
11774
11990
  exports.WARNING_MISMATCHED_LOCAL_FILE_HEADER_FILENAME = WARNING_MISMATCHED_LOCAL_FILE_HEADER_FILENAME;
11775
11991
  exports.WARNING_MISMATCHED_ZIP64_END_OF_CENTRAL_DIRECTORY = WARNING_MISMATCHED_ZIP64_END_OF_CENTRAL_DIRECTORY;
11992
+ exports.WARNING_MISSING_ZIP64_EXTRA_FIELD = WARNING_MISSING_ZIP64_EXTRA_FIELD;
11776
11993
  exports.WARNING_MULTIPLE_END_OF_CENTRAL_DIRECTORY = WARNING_MULTIPLE_END_OF_CENTRAL_DIRECTORY;
11777
11994
  exports.WARNING_PREPENDED_CENTRAL_DIRECTORY = WARNING_PREPENDED_CENTRAL_DIRECTORY;
11778
11995
  exports.WARNING_PREPENDED_DATA = WARNING_PREPENDED_DATA;