@zip.js/zip.js 2.18.2 → 2.20.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.
Files changed (45) hide show
  1. package/BENCHMARKS.md +172 -144
  2. package/deno.json +1 -1
  3. package/dist/zip-core-external.js +192 -120
  4. package/dist/zip-core-external.min.js +1 -1
  5. package/dist/zip-core.js +193 -119
  6. package/dist/zip-core.min.js +1 -1
  7. package/dist/zip-fs-core-external.js +192 -120
  8. package/dist/zip-fs-core-external.min.js +1 -1
  9. package/dist/zip-fs-core.js +193 -119
  10. package/dist/zip-fs-core.min.js +1 -1
  11. package/dist/zip-fs-external.js +192 -120
  12. package/dist/zip-fs-external.min.js +1 -1
  13. package/dist/zip-fs-native.js +195 -121
  14. package/dist/zip-fs-native.min.js +1 -1
  15. package/dist/zip-fs.js +194 -120
  16. package/dist/zip-fs.min.js +1 -1
  17. package/dist/zip-legacy.js +195 -121
  18. package/dist/zip-legacy.min.js +1 -1
  19. package/dist/zip-native.js +195 -121
  20. package/dist/zip-native.min.js +1 -1
  21. package/dist/zip-web-worker-native.js +1 -1
  22. package/dist/zip-web-worker.js +1 -1
  23. package/dist/zip.js +194 -120
  24. package/dist/zip.min.js +1 -1
  25. package/index-native.cjs +195 -121
  26. package/index-native.min.js +1 -1
  27. package/index.cjs +194 -120
  28. package/index.d.cts +95 -26
  29. package/index.d.ts +95 -26
  30. package/index.min.js +1 -1
  31. package/lib/core/codec-pool.js +1 -2
  32. package/lib/core/codec-worker-web.js +11 -39
  33. package/lib/core/codec-worker.js +1 -2
  34. package/lib/core/configuration.js +1 -1
  35. package/lib/core/options.js +0 -2
  36. package/lib/core/streams/codec-stream.js +1 -1
  37. package/lib/core/version.js +1 -1
  38. package/lib/core/web-worker-base.js +2 -3
  39. package/lib/core/web-worker-inline-native.js +1 -1
  40. package/lib/core/web-worker-inline-wasm.js +1 -1
  41. package/lib/core/zip-reader.js +100 -40
  42. package/lib/core/zip-writer.js +75 -34
  43. package/lib/zip-core-reader.js +2 -0
  44. package/package.json +1 -1
  45. package/worker-message-property-names.js +1 -1
@@ -185,7 +185,6 @@
185
185
  const OPTION_CHECK_AUTHENTICATION_CODE = "checkAuthenticationCode";
186
186
  const OPTION_USE_WEB_WORKERS = "useWebWorkers";
187
187
  const OPTION_USE_COMPRESSION_STREAM = "useCompressionStream";
188
- const OPTION_TRANSFER_STREAMS = "transferStreams";
189
188
  const OPTION_PREVENT_CLOSE = "preventClose";
190
189
  const OPTION_ENCRYPTION_STRENGTH = "encryptionStrength";
191
190
  const OPTION_EXTENDED_TIMESTAMP = "extendedTimestamp";
@@ -303,7 +302,7 @@
303
302
  */
304
303
 
305
304
 
306
- const DEFAULT_CHUNK_SIZE$1 = 64 * 1024;
305
+ const DEFAULT_CHUNK_SIZE$1 = 256 * 1024;
307
306
  const MINIMUM_CHUNK_SIZE = 64;
308
307
  const MINIMUM_PROPERTY_VALUE = 1;
309
308
  const ERR_INVALID_MAX_WORKERS = "Invalid maxWorkers (must be an integer greater than 0)";
@@ -2392,7 +2391,7 @@
2392
2391
  */
2393
2392
 
2394
2393
 
2395
- const DEFAULT_CHUNK_SIZE = 64 * 1024;
2394
+ const DEFAULT_CHUNK_SIZE = 256 * 1024;
2396
2395
  const MESSAGE_EVENT_TYPE = "message";
2397
2396
  const MESSAGE_START = "start";
2398
2397
  const MESSAGE_PULL = "pull";
@@ -2598,7 +2597,7 @@
2598
2597
  class CodecWorker {
2599
2598
 
2600
2599
  constructor(workerData, { readable, writable }, workerOptions, onTaskFinished) {
2601
- const { options, config, streamOptions, useWebWorkers, transferStreams, workerURI } = workerOptions;
2600
+ const { options, config, streamOptions, useWebWorkers, workerURI } = workerOptions;
2602
2601
  let { createWorker } = workerOptions;
2603
2602
  const { signal } = streamOptions;
2604
2603
  if (createWorkerFailed) {
@@ -2615,7 +2614,6 @@
2615
2614
  workerOptions,
2616
2615
  workerURI,
2617
2616
  createWorker,
2618
- transferStreams,
2619
2617
  terminate() {
2620
2618
  return new Promise(resolve => {
2621
2619
  const { worker, busy } = workerData;
@@ -2793,12 +2791,6 @@
2793
2791
  const ABORT_EVENT_TYPE = "abort";
2794
2792
 
2795
2793
  let webWorkerSource, webWorkerURI, webWorkerOptions;
2796
- let transferStreamsSupported = true;
2797
- try {
2798
- transferStreamsSupported = typeof structuredClone == FUNCTION_TYPE && structuredClone(new DOMException("", "AbortError")).code !== UNDEFINED_VALUE;
2799
- } catch {
2800
- // ignored
2801
- }
2802
2794
 
2803
2795
  setWebWorkerBackend(createWebWorkerInterface);
2804
2796
 
@@ -2885,14 +2877,11 @@
2885
2877
  });
2886
2878
  const { readable, options } = workerData;
2887
2879
  const { writable, closed, abortPipe } = watchClosedStream(workerData.writable, workerData);
2888
- let streamsTransferred;
2889
2880
  try {
2890
- streamsTransferred = sendMessage({
2881
+ sendMessage({
2891
2882
  type: MESSAGE_START,
2892
2883
  options,
2893
- config,
2894
- readable,
2895
- writable
2884
+ config
2896
2885
  }, workerData);
2897
2886
  } catch (error) {
2898
2887
  abortPipe();
@@ -2904,12 +2893,10 @@
2904
2893
  workerData.onTaskFinished();
2905
2894
  throw error;
2906
2895
  }
2907
- if (!streamsTransferred) {
2908
- Object.assign(workerData, {
2909
- reader: readable.getReader(),
2910
- writer: writable.getWriter()
2911
- });
2912
- }
2896
+ Object.assign(workerData, {
2897
+ reader: readable.getReader(),
2898
+ writer: writable.getWriter()
2899
+ });
2913
2900
  const { workerStartupTimeout } = config;
2914
2901
  if (!workerData.workerAlive && Number.isFinite(workerStartupTimeout) && workerStartupTimeout >= 0) {
2915
2902
  workerData.startupTimeout = setTimeout(() => onStartupTimeout(workerData), workerStartupTimeout);
@@ -2942,7 +2929,7 @@
2942
2929
  }
2943
2930
 
2944
2931
  async function closeWritable() {
2945
- if (!streamsTransferred && !writable.locked) {
2932
+ if (!writable.locked) {
2946
2933
  try {
2947
2934
  await writable.getWriter().close();
2948
2935
  } catch {
@@ -3133,31 +3120,14 @@
3133
3120
  }
3134
3121
  }
3135
3122
 
3136
- function sendMessage(message, { worker, writer, transferStreams, workerAlive }) {
3123
+ function sendMessage(message, { worker, writer }) {
3137
3124
  try {
3138
- const { value, readable, writable } = message;
3139
- const transferables = [];
3125
+ const { value } = message;
3140
3126
  if (value) {
3141
3127
  message.value = toExactUint8Array(value);
3142
- transferables.push(message.value.buffer);
3143
- }
3144
- if (transferStreams && transferStreamsSupported && workerAlive) {
3145
- if (readable) {
3146
- transferables.push(readable);
3147
- }
3148
- if (writable) {
3149
- transferables.push(writable);
3150
- }
3151
- } else {
3152
- message.readable = message.writable = null;
3153
- }
3154
- if (transferables.length) {
3155
3128
  try {
3156
- worker.postMessage(message, transferables);
3157
- return true;
3129
+ worker.postMessage(message, [message.value.buffer]);
3158
3130
  } catch {
3159
- transferStreamsSupported = false;
3160
- message.readable = message.writable = null;
3161
3131
  worker.postMessage(message);
3162
3132
  }
3163
3133
  } else {
@@ -3306,7 +3276,7 @@
3306
3276
 
3307
3277
  async function runWorker(stream, workerOptions) {
3308
3278
  const { options, config } = workerOptions;
3309
- const { transferStreams, useWebWorkers, useCompressionStream, compressed, checkCrc32, computeCrc32, encrypted, format, codecURI } = options;
3279
+ const { useWebWorkers, useCompressionStream, compressed, checkCrc32, computeCrc32, encrypted, format, codecURI } = options;
3310
3280
  const { workerURI, createWorker, maxWorkers } = config;
3311
3281
  if (format) {
3312
3282
  if (codecURI) {
@@ -3314,7 +3284,6 @@
3314
3284
  }
3315
3285
  await ensureCodecStreams(format, options.codecURI);
3316
3286
  }
3317
- workerOptions.transferStreams = !format && (transferStreams || (transferStreams === UNDEFINED_VALUE && config.transferStreams));
3318
3287
  const streamCopy = !compressed && !checkCrc32 && !computeCrc32 && !encrypted;
3319
3288
  const workerSupported = format === UNDEFINED_VALUE || Boolean(options.codecURI);
3320
3289
  workerOptions.useWebWorkers = !streamCopy && workerSupported && (useWebWorkers || (useWebWorkers === UNDEFINED_VALUE && config.useWebWorkers));
@@ -4830,6 +4799,8 @@
4830
4799
  const WARNING_PREPENDED_DATA = "prepended data";
4831
4800
  const WARNING_PREPENDED_CENTRAL_DIRECTORY = "prepended central directory";
4832
4801
  const WARNING_TRAILING_CENTRAL_DIRECTORY_DATA = "trailing central directory data";
4802
+ const WARNING_MISMATCHED_CENTRAL_DIRECTORY_OFFSET = "mismatched central directory offset";
4803
+ const WARNING_MISSING_ZIP64_EXTRA_FIELD = "missing zip64 extra field";
4833
4804
  const WARNING_DUPLICATE_FILENAME = "duplicate filename";
4834
4805
  const WARNING_MISMATCHED_ZIP64_END_OF_CENTRAL_DIRECTORY = "mismatched zip64 end of central directory record";
4835
4806
  const WARNING_MULTIPLE_END_OF_CENTRAL_DIRECTORY = "multiple end of central directory records";
@@ -4992,6 +4963,8 @@
4992
4963
  reportAmbiguity(checkAmbiguity, warnings, WARNING_MISMATCHED_ZIP64_END_OF_CENTRAL_DIRECTORY);
4993
4964
  }
4994
4965
  directoryDataOffset = getDiskOffset$1(reader, diskNumber) + getBigUint64(endOfDirectoryView, 48) + prependedDataLength;
4966
+ } else if (directoryDataOffset == MAX_32_BITS || directoryDataLength == MAX_32_BITS || diskNumber == MAX_16_BITS) {
4967
+ throw new Error(ERR_EOCDR_LOCATOR_ZIP64_NOT_FOUND);
4995
4968
  }
4996
4969
  }
4997
4970
  let declaredDirectoryDataLength = directoryDataLength;
@@ -5014,25 +4987,44 @@
5014
4987
  if (directoryArray.length < 4) {
5015
4988
  throw new Error(ERR_BAD_FORMAT);
5016
4989
  }
5017
- const expectedDirectoryDataOffset = centralDirectoryEndOffset - directoryDataLength;
4990
+ let expectedDirectoryDataOffset = centralDirectoryEndOffset - directoryDataLength;
5018
4991
  if (directoryDataOffset != expectedDirectoryDataOffset && diskNumber == lastDiskNumber) {
5019
4992
  const storedPointsAtDirectory = getUint32$1(directoryView, offset) == CENTRAL_FILE_HEADER_SIGNATURE ||
5020
4993
  Boolean(directoryEncryptionInfo && directoryEncryptionInfo.compressedSize) ||
5021
4994
  detectEncryptedCentralDirectory(directoryView);
5022
4995
  let reconcile = !storedPointsAtDirectory;
5023
- if (!reconcile && expectedDirectoryDataOffset >= 0 && expectedDirectoryDataOffset + 4 <= reader.size) {
5024
- const expectedSignatureArray = await readUint8Array(reader, expectedDirectoryDataOffset, 4);
5025
- reconcile = getUint32$1(getDataView(expectedSignatureArray), 0) == CENTRAL_FILE_HEADER_SIGNATURE;
4996
+ if (expectedDirectoryDataOffset >= 0 && expectedDirectoryDataOffset + 4 <= reader.size) {
4997
+ const expectedPointsAtDirectory = await pointsAtDirectory(reader, expectedDirectoryDataOffset);
4998
+ if (storedPointsAtDirectory) {
4999
+ reconcile = expectedPointsAtDirectory;
5000
+ } else if (!expectedPointsAtDirectory) {
5001
+ const signatureRecordOffset = await findDigitalSignatureRecordOffset(reader, centralDirectoryEndOffset);
5002
+ const signedDirectoryDataOffset = signatureRecordOffset - directoryDataLength;
5003
+ if (signatureRecordOffset !== UNDEFINED_VALUE && signedDirectoryDataOffset >= 0 &&
5004
+ await pointsAtDirectory(reader, signedDirectoryDataOffset)) {
5005
+ expectedDirectoryDataOffset = signedDirectoryDataOffset;
5006
+ }
5007
+ }
5026
5008
  }
5027
5009
  if (reconcile) {
5028
5010
  const originalDirectoryDataOffset = directoryDataOffset;
5029
5011
  directoryDataOffset = expectedDirectoryDataOffset;
5012
+ directoryArray = await readUint8Array(reader, directoryDataOffset, directoryDataLength);
5013
+ directoryView = getDataView(directoryArray);
5030
5014
  if (directoryDataOffset > originalDirectoryDataOffset) {
5031
5015
  prependedDataLength += directoryDataOffset - originalDirectoryDataOffset;
5032
5016
  prependedCentralDirectory = storedPointsAtDirectory;
5017
+ } else {
5018
+ reportAmbiguity(checkAmbiguity, warnings, WARNING_MISMATCHED_CENTRAL_DIRECTORY_OFFSET);
5019
+ const offsetDelta = directoryDataOffset - originalDirectoryDataOffset;
5020
+ if (directoryArray.length >= CENTRAL_FILE_HEADER_LENGTH) {
5021
+ const localHeaderOffset = getUint32$1(directoryView, 42);
5022
+ if (!await startsWithSignature(reader, localHeaderOffset, LOCAL_FILE_HEADER_SIGNATURE) &&
5023
+ await startsWithSignature(reader, localHeaderOffset + offsetDelta, LOCAL_FILE_HEADER_SIGNATURE)) {
5024
+ prependedDataLength += offsetDelta;
5025
+ }
5026
+ }
5033
5027
  }
5034
- directoryArray = await readUint8Array(reader, directoryDataOffset, directoryDataLength);
5035
- directoryView = getDataView(directoryArray);
5036
5028
  }
5037
5029
  }
5038
5030
  }
@@ -5116,17 +5108,6 @@
5116
5108
  if (filename === UNDEFINED_VALUE) {
5117
5109
  filename = decodeText(rawFilename, rawFilenameEncoding);
5118
5110
  }
5119
- if (normalizeFilename) {
5120
- const normalizedFilename = normalizeFilename(filename);
5121
- if (normalizedFilename !== UNDEFINED_VALUE) {
5122
- filename = normalizedFilename;
5123
- }
5124
- }
5125
- if (isUnsafeFilename(filename, filenameValidation)) {
5126
- const error = new Error(ERR_UNSAFE_FILENAME);
5127
- error.filename = filename;
5128
- throw error;
5129
- }
5130
5111
  let comment = decode(rawComment, rawCommentEncoding, TEXT_TYPE_COMMENT);
5131
5112
  if (comment === UNDEFINED_VALUE) {
5132
5113
  comment = decodeText(rawComment, rawCommentEncoding);
@@ -5154,7 +5135,29 @@
5154
5135
  filename,
5155
5136
  comment
5156
5137
  });
5157
- if (readCommonFooter(fileEntry, fileEntry, directoryView, offset + 6)) {
5138
+ let malformedExtraField;
5139
+ try {
5140
+ malformedExtraField = readCommonFooter(fileEntry, fileEntry, directoryView, offset + 6);
5141
+ } catch (error) {
5142
+ if (checkAmbiguity || error.message != ERR_EXTRAFIELD_ZIP64_NOT_FOUND) {
5143
+ throw error;
5144
+ }
5145
+ fileEntry.zip64ExtraFieldMissing = true;
5146
+ addWarning(warnings, WARNING_MISSING_ZIP64_EXTRA_FIELD, fileEntry.filename);
5147
+ }
5148
+ filename = fileEntry.filename;
5149
+ if (normalizeFilename) {
5150
+ const normalizedFilename = normalizeFilename(filename);
5151
+ if (normalizedFilename !== UNDEFINED_VALUE) {
5152
+ filename = fileEntry.filename = normalizedFilename;
5153
+ }
5154
+ }
5155
+ if (isUnsafeFilename(filename, filenameValidation)) {
5156
+ const error = new Error(ERR_UNSAFE_FILENAME);
5157
+ error.filename = filename;
5158
+ throw error;
5159
+ }
5160
+ if (malformedExtraField) {
5158
5161
  addWarning(warnings, WARNING_MALFORMED_EXTRA_FIELD, filename);
5159
5162
  }
5160
5163
  fileEntry.offset += prependedDataLength;
@@ -5183,11 +5186,12 @@
5183
5186
  const sticky = Boolean(fileEntry.unixMode & FILE_ATTR_UNIX_STICKY_MASK);
5184
5187
  const unixType = fileEntry.unixMode === UNDEFINED_VALUE ? unixExternalUpper : fileEntry.unixMode;
5185
5188
  const symlink = (unixType & FILE_ATTR_UNIX_TYPE_MASK) == FILE_ATTR_UNIX_TYPE_SYMLINK;
5186
- const executable = !symlink && ((fileEntry.unixMode !== UNDEFINED_VALUE)
5187
- ? ((fileEntry.unixMode & FILE_ATTR_UNIX_EXECUTABLE_MASK) != 0)
5188
- : (unixCompatible && ((unixExternalUpper & FILE_ATTR_UNIX_EXECUTABLE_MASK) != 0)));
5189
5189
  const modeIsDir = fileEntry.unixMode !== UNDEFINED_VALUE && ((fileEntry.unixMode & FILE_ATTR_UNIX_TYPE_MASK) == FILE_ATTR_UNIX_TYPE_DIR);
5190
5190
  const upperIsDir = ((unixExternalUpper & FILE_ATTR_UNIX_TYPE_MASK) == FILE_ATTR_UNIX_TYPE_DIR);
5191
+ const directory = modeIsDir || upperIsDir || (msDosCompatible && msdosAttributes.directory) || fileEntry.filename.endsWith(DIRECTORY_SIGNATURE);
5192
+ const executable = !symlink && !directory && ((fileEntry.unixMode !== UNDEFINED_VALUE)
5193
+ ? ((fileEntry.unixMode & FILE_ATTR_UNIX_EXECUTABLE_MASK) != 0)
5194
+ : (unixCompatible && ((unixExternalUpper & FILE_ATTR_UNIX_EXECUTABLE_MASK) != 0)));
5191
5195
  Object.assign(fileEntry, {
5192
5196
  setuid,
5193
5197
  setgid,
@@ -5195,7 +5199,7 @@
5195
5199
  symlink,
5196
5200
  unixExternalUpper,
5197
5201
  executable,
5198
- directory: modeIsDir || upperIsDir || (msDosCompatible && msdosAttributes.directory) || fileEntry.filename.endsWith(DIRECTORY_SIGNATURE),
5202
+ directory,
5199
5203
  zipCrypto: fileEntry.encrypted && !fileEntry.extraFieldAES
5200
5204
  });
5201
5205
  const entry = new Entry(fileEntry);
@@ -5251,10 +5255,10 @@
5251
5255
  const extractAppendedData = getOptionValue$1(zipReader, options, OPTION_EXTRACT_APPENDED_DATA);
5252
5256
  const splitZipSignatureLength = (checkAmbiguity || extractPrependedData) && filesLength &&
5253
5257
  startOffset == SPLIT_ZIP_FILE_SIGNATURE_LENGTH && await startsWithSplitZipMarker(reader) ? SPLIT_ZIP_FILE_SIGNATURE_LENGTH : 0;
5254
- if (checkAmbiguity && (prependedDataLength || (filesLength && startOffset > splitZipSignatureLength))) {
5258
+ if (checkAmbiguity && (prependedDataLength > 0 || (filesLength && startOffset > splitZipSignatureLength))) {
5255
5259
  throwAmbiguousArchive(WARNING_PREPENDED_DATA);
5256
5260
  }
5257
- if (prependedDataLength || (filesLength && startOffset > SPLIT_ZIP_FILE_SIGNATURE_LENGTH)) {
5261
+ if (prependedDataLength > 0 || (filesLength && startOffset > SPLIT_ZIP_FILE_SIGNATURE_LENGTH)) {
5258
5262
  addWarning(warnings, WARNING_PREPENDED_DATA);
5259
5263
  }
5260
5264
  if (prependedCentralDirectory) {
@@ -5414,6 +5418,9 @@
5414
5418
 
5415
5419
  async getData(writer, fileEntry, readRanges, options = {}) {
5416
5420
  const zipEntry = this;
5421
+ if (zipEntry.zip64ExtraFieldMissing) {
5422
+ throw new Error(ERR_EXTRAFIELD_ZIP64_NOT_FOUND);
5423
+ }
5417
5424
  const config = getConfiguration();
5418
5425
  const {
5419
5426
  reader,
@@ -5558,7 +5565,6 @@
5558
5565
  encrypted,
5559
5566
  useWebWorkers: getOptionValue$1(zipEntry, options, OPTION_USE_WEB_WORKERS),
5560
5567
  useCompressionStream,
5561
- transferStreams: getOptionValue$1(zipEntry, options, OPTION_TRANSFER_STREAMS),
5562
5568
  deflate64,
5563
5569
  format: registeredCodec ? registeredCodec.format : UNDEFINED_VALUE,
5564
5570
  codecURI: registeredCodec ? registeredCodec.codecURI : UNDEFINED_VALUE,
@@ -5652,6 +5658,30 @@
5652
5658
  return wrappedFilesLength % (MAX_16_BITS + 1) ? 0 : wrappedFilesLength;
5653
5659
  }
5654
5660
 
5661
+ function pointsAtDirectory(reader, offset) {
5662
+ return startsWithSignature(reader, offset, CENTRAL_FILE_HEADER_SIGNATURE);
5663
+ }
5664
+
5665
+ async function startsWithSignature(reader, offset, signature) {
5666
+ if (offset < 0 || offset + 4 > reader.size) {
5667
+ return false;
5668
+ }
5669
+ const signatureArray = await readUint8Array(reader, offset, 4);
5670
+ return getUint32$1(getDataView(signatureArray), 0) == signature;
5671
+ }
5672
+
5673
+ async function findDigitalSignatureRecordOffset(reader, endOffset) {
5674
+ const startOffset = Math.max(0, endOffset - (6 + MAX_16_BITS));
5675
+ const tailArray = await readUint8Array(reader, startOffset, endOffset - startOffset);
5676
+ const tailView = getDataView(tailArray);
5677
+ for (let indexByte = tailArray.length - 6; indexByte >= 0; indexByte--) {
5678
+ if (getUint32$1(tailView, indexByte) == DIGITAL_SIGNATURE_RECORD_SIGNATURE &&
5679
+ indexByte + 6 + getUint16$1(tailView, indexByte + 4) == tailArray.length) {
5680
+ return startOffset + indexByte;
5681
+ }
5682
+ }
5683
+ }
5684
+
5655
5685
  function readDigitalSignature(signatureRecordArray) {
5656
5686
  if (signatureRecordArray.length >= 6) {
5657
5687
  const signatureRecordView = getDataView(signatureRecordArray);
@@ -5783,29 +5813,27 @@
5783
5813
  readExtraFieldUnixDates(extraFieldUnixType1, directory);
5784
5814
  directory.extraFieldUnixType1 = extraFieldUnixType1;
5785
5815
  }
5816
+ const extraFieldExtendedTimestamp = extraField.get(EXTRAFIELD_TYPE_EXTENDED_TIMESTAMP);
5817
+ if (extraFieldExtendedTimestamp) {
5818
+ readExtraFieldExtendedTimestamp(extraFieldExtendedTimestamp, directory, localDirectory);
5819
+ directory.extraFieldExtendedTimestamp = extraFieldExtendedTimestamp;
5820
+ }
5786
5821
  const extraFieldNTFS = extraField.get(EXTRAFIELD_TYPE_NTFS);
5787
5822
  if (extraFieldNTFS) {
5788
5823
  readExtraFieldNTFS(extraFieldNTFS, directory);
5789
5824
  directory.extraFieldNTFS = extraFieldNTFS;
5790
5825
  }
5791
- const extraFieldUnix = extraField.get(EXTRAFIELD_TYPE_UNIX);
5826
+ const extraFieldInfoZip = extraField.get(EXTRAFIELD_TYPE_INFOZIP);
5792
5827
  let unixIdsRead;
5828
+ if (extraFieldInfoZip) {
5829
+ unixIdsRead = readExtraFieldUnix(extraFieldInfoZip, directory, true);
5830
+ directory.extraFieldInfoZip = extraFieldInfoZip;
5831
+ }
5832
+ const extraFieldUnix = extraField.get(EXTRAFIELD_TYPE_UNIX);
5793
5833
  if (extraFieldUnix) {
5794
- unixIdsRead = readExtraFieldUnix(extraFieldUnix, directory, false);
5834
+ readExtraFieldUnix(extraFieldUnix, unixIdsRead ? {} : directory, false);
5795
5835
  directory.extraFieldUnix = extraFieldUnix;
5796
5836
  }
5797
- if (!unixIdsRead) {
5798
- const extraFieldInfoZip = extraField.get(EXTRAFIELD_TYPE_INFOZIP);
5799
- if (extraFieldInfoZip) {
5800
- readExtraFieldUnix(extraFieldInfoZip, directory, true);
5801
- directory.extraFieldInfoZip = extraFieldInfoZip;
5802
- }
5803
- }
5804
- const extraFieldExtendedTimestamp = extraField.get(EXTRAFIELD_TYPE_EXTENDED_TIMESTAMP);
5805
- if (extraFieldExtendedTimestamp) {
5806
- readExtraFieldExtendedTimestamp(extraFieldExtendedTimestamp, directory, localDirectory);
5807
- directory.extraFieldExtendedTimestamp = extraFieldExtendedTimestamp;
5808
- }
5809
5837
  const extraFieldUSDZ = extraField.get(EXTRAFIELD_TYPE_USDZ);
5810
5838
  if (extraFieldUSDZ) {
5811
5839
  directory.extraFieldUSDZ = extraFieldUSDZ;
@@ -6444,11 +6472,13 @@
6444
6472
  WARNING_COMPRESSED_PATCHED_DATA: WARNING_COMPRESSED_PATCHED_DATA,
6445
6473
  WARNING_DUPLICATE_FILENAME: WARNING_DUPLICATE_FILENAME,
6446
6474
  WARNING_MALFORMED_EXTRA_FIELD: WARNING_MALFORMED_EXTRA_FIELD,
6475
+ WARNING_MISMATCHED_CENTRAL_DIRECTORY_OFFSET: WARNING_MISMATCHED_CENTRAL_DIRECTORY_OFFSET,
6447
6476
  WARNING_MISMATCHED_LOCAL_FILE_HEADER_BIT_FLAG: WARNING_MISMATCHED_LOCAL_FILE_HEADER_BIT_FLAG,
6448
6477
  WARNING_MISMATCHED_LOCAL_FILE_HEADER_COMPRESSION_METHOD: WARNING_MISMATCHED_LOCAL_FILE_HEADER_COMPRESSION_METHOD,
6449
6478
  WARNING_MISMATCHED_LOCAL_FILE_HEADER_CRC32_OR_SIZES: WARNING_MISMATCHED_LOCAL_FILE_HEADER_CRC32_OR_SIZES,
6450
6479
  WARNING_MISMATCHED_LOCAL_FILE_HEADER_FILENAME: WARNING_MISMATCHED_LOCAL_FILE_HEADER_FILENAME,
6451
6480
  WARNING_MISMATCHED_ZIP64_END_OF_CENTRAL_DIRECTORY: WARNING_MISMATCHED_ZIP64_END_OF_CENTRAL_DIRECTORY,
6481
+ WARNING_MISSING_ZIP64_EXTRA_FIELD: WARNING_MISSING_ZIP64_EXTRA_FIELD,
6452
6482
  WARNING_MULTIPLE_END_OF_CENTRAL_DIRECTORY: WARNING_MULTIPLE_END_OF_CENTRAL_DIRECTORY,
6453
6483
  WARNING_PREPENDED_CENTRAL_DIRECTORY: WARNING_PREPENDED_CENTRAL_DIRECTORY,
6454
6484
  WARNING_PREPENDED_DATA: WARNING_PREPENDED_DATA,
@@ -6581,13 +6611,14 @@
6581
6611
  return watchPromiseError(this, prependZipEntries(this, reader));
6582
6612
  }
6583
6613
 
6584
- appendZip(reader) {
6585
- return watchPromiseError(this, this.appendZipEntries(reader));
6614
+ appendZip(reader, options = {}) {
6615
+ return watchPromiseError(this, this.appendZipEntries(reader, options));
6586
6616
  }
6587
6617
 
6588
- async appendZipEntries(reader) {
6618
+ async appendZipEntries(reader, options = {}) {
6589
6619
  const zipWriter = this;
6590
6620
  const { pendingAddFileCalls, filenames, fileEntries } = zipWriter;
6621
+ const filter = checkFunctionOption(options.filter);
6591
6622
  while (pendingAddFileCalls.size) {
6592
6623
  await Promise.allSettled(Array.from(pendingAddFileCalls));
6593
6624
  }
@@ -6606,10 +6637,16 @@
6606
6637
  const { ZipReader } = await Promise.resolve().then(function () { return zipReader; });
6607
6638
  const zipReader$1 = new ZipReader(reader);
6608
6639
  const entries = await zipReader$1.getEntries();
6640
+ const keptEntries = [];
6641
+ for (const entry of entries) {
6642
+ if (!filter || await filter(entry)) {
6643
+ keptEntries.push(entry);
6644
+ }
6645
+ }
6609
6646
  await zipReader$1.close();
6610
6647
  await initStream(zipWriter.writer);
6611
6648
  const { directoryOffset } = zipReader$1;
6612
- entries.forEach(({ filename }) => {
6649
+ keptEntries.forEach(({ filename }) => {
6613
6650
  if (filenames.has(filename)) {
6614
6651
  throw new Error(ERR_DUPLICATED_NAME);
6615
6652
  }
@@ -6630,8 +6667,8 @@
6630
6667
  zipWriter.offset += SPLIT_ZIP_FILE_SIGNATURE_LENGTH;
6631
6668
  }
6632
6669
  }
6633
- const entryPositions = await copyZipData(zipWriter, reader, entries, directoryOffset);
6634
- entries.forEach(entry => {
6670
+ const entryPositions = await copyZipData(zipWriter, reader, entries, keptEntries, directoryOffset, Boolean(filter));
6671
+ keptEntries.forEach(entry => {
6635
6672
  const {
6636
6673
  version,
6637
6674
  rawLastModDate,
@@ -6687,6 +6724,7 @@
6687
6724
  rawExtraFieldExtendedTimestamp: EMPTY_UINT8_ARRAY,
6688
6725
  rawExtraFieldNTFS: EMPTY_UINT8_ARRAY,
6689
6726
  rawExtraFieldUnix: EMPTY_UINT8_ARRAY,
6727
+ rawCentralExtraFieldUnix: EMPTY_UINT8_ARRAY,
6690
6728
  rawExtraField,
6691
6729
  rawCentralExtraField: EMPTY_UINT8_ARRAY,
6692
6730
  headerArray,
@@ -7255,7 +7293,6 @@
7255
7293
  const ntfsTimestamp = getOptionValue(zipWriter, options, OPTION_NTFS_TIMESTAMP);
7256
7294
  const keepOrder = getOptionValue(zipWriter, options, OPTION_KEEP_ORDER, true);
7257
7295
  const useWebWorkers = getOptionValue(zipWriter, options, OPTION_USE_WEB_WORKERS);
7258
- const transferStreams = getOptionValue(zipWriter, options, OPTION_TRANSFER_STREAMS);
7259
7296
  const bufferedWrite = getOptionValue(zipWriter, options, OPTION_BUFFERED_WRITE);
7260
7297
  const createTempStream = getFunctionOptionValue(zipWriter, options, OPTION_CREATE_TEMP_STREAM);
7261
7298
  const dataDescriptorSignature = getOptionValue(zipWriter, options, OPTION_DATA_DESCRIPTOR_SIGNATURE, true);
@@ -7321,7 +7358,6 @@
7321
7358
  ntfsTimestamp,
7322
7359
  keepOrder,
7323
7360
  useWebWorkers,
7324
- transferStreams,
7325
7361
  bufferedWrite,
7326
7362
  createTempStream,
7327
7363
  dataDescriptorSignature,
@@ -7380,7 +7416,7 @@
7380
7416
  if (reader) {
7381
7417
  reader = new GenericReader(reader);
7382
7418
  await initStream(reader);
7383
- if (!reader.readable && !reader.readUint8Array) {
7419
+ if (!reader.readUint8Array && !reader.readable) {
7384
7420
  throw new Error(ERR_INVALID_READER);
7385
7421
  }
7386
7422
  ({ size: contentSize } = reader);
@@ -7741,6 +7777,7 @@
7741
7777
  extraFieldExtendedTimestampTime,
7742
7778
  rawExtraFieldNTFS,
7743
7779
  rawExtraFieldUnix,
7780
+ rawCentralExtraFieldUnix,
7744
7781
  rawExtraFieldAES,
7745
7782
  } = headerInfo;
7746
7783
  const { dataDescriptorArray } = dataDescriptorInfo;
@@ -7765,7 +7802,6 @@
7765
7802
  rawExtraField,
7766
7803
  rawCentralExtraField,
7767
7804
  useWebWorkers,
7768
- transferStreams,
7769
7805
  onstart,
7770
7806
  onprogress,
7771
7807
  onend,
@@ -7807,6 +7843,7 @@
7807
7843
  rawExtraFieldExtendedTimestamp,
7808
7844
  rawExtraFieldNTFS,
7809
7845
  rawExtraFieldUnix,
7846
+ rawCentralExtraFieldUnix,
7810
7847
  rawExtraFieldAES,
7811
7848
  rawExtraField,
7812
7849
  rawCentralExtraField,
@@ -7853,7 +7890,6 @@
7853
7890
  encrypted: encrypted && !passThroughEncryption,
7854
7891
  useWebWorkers,
7855
7892
  useCompressionStream,
7856
- transferStreams,
7857
7893
  format,
7858
7894
  codecURI,
7859
7895
  compressionMethod
@@ -8031,6 +8067,7 @@
8031
8067
  rawExtraFieldNTFS = rawExtraFieldExtendedTimestamp = EMPTY_UINT8_ARRAY;
8032
8068
  }
8033
8069
  let rawExtraFieldUnix;
8070
+ let rawCentralExtraFieldUnix;
8034
8071
  try {
8035
8072
  const { uid, gid, unixExtraFieldType } = options;
8036
8073
  if (unixExtraFieldType == INFOZIP_EXTRA_FIELD_TYPE && (uid !== UNDEFINED_VALUE || gid !== UNDEFINED_VALUE)) {
@@ -8045,7 +8082,7 @@
8045
8082
  extraFieldUnix.writeBytes(uidBytes);
8046
8083
  extraFieldUnix.writeUint8(gidBytes.length);
8047
8084
  extraFieldUnix.writeBytes(gidBytes);
8048
- rawExtraFieldUnix = extraFieldUnix.array;
8085
+ rawExtraFieldUnix = rawCentralExtraFieldUnix = extraFieldUnix.array;
8049
8086
  } else if (unixExtraFieldType == UNIX_EXTRA_FIELD_TYPE && (uid !== UNDEFINED_VALUE || gid !== UNDEFINED_VALUE)) {
8050
8087
  const extraFieldUnix = createRecordWriter(8);
8051
8088
  extraFieldUnix.writeUint16(EXTRAFIELD_TYPE_UNIX);
@@ -8053,11 +8090,15 @@
8053
8090
  extraFieldUnix.writeUint16((uid === UNDEFINED_VALUE ? 0 : uid) & MAX_16_BITS);
8054
8091
  extraFieldUnix.writeUint16((gid === UNDEFINED_VALUE ? 0 : gid) & MAX_16_BITS);
8055
8092
  rawExtraFieldUnix = extraFieldUnix.array;
8093
+ const centralExtraFieldUnix = createRecordWriter(4);
8094
+ centralExtraFieldUnix.writeUint16(EXTRAFIELD_TYPE_UNIX);
8095
+ centralExtraFieldUnix.writeUint16(0);
8096
+ rawCentralExtraFieldUnix = centralExtraFieldUnix.array;
8056
8097
  } else {
8057
- rawExtraFieldUnix = EMPTY_UINT8_ARRAY;
8098
+ rawExtraFieldUnix = rawCentralExtraFieldUnix = EMPTY_UINT8_ARRAY;
8058
8099
  }
8059
8100
  } catch {
8060
- rawExtraFieldUnix = EMPTY_UINT8_ARRAY;
8101
+ rawExtraFieldUnix = rawCentralExtraFieldUnix = EMPTY_UINT8_ARRAY;
8061
8102
  }
8062
8103
  if (compressionMethod === UNDEFINED_VALUE) {
8063
8104
  compressionMethod = compressed ? COMPRESSION_METHOD_DEFLATE : COMPRESSION_METHOD_STORE;
@@ -8149,6 +8190,7 @@
8149
8190
  rawExtraFieldExtendedTimestamp,
8150
8191
  rawExtraFieldNTFS,
8151
8192
  rawExtraFieldUnix,
8193
+ rawCentralExtraFieldUnix,
8152
8194
  rawExtraFieldAES,
8153
8195
  extraFieldLength
8154
8196
  };
@@ -8324,7 +8366,7 @@
8324
8366
  rawExtraFieldAES,
8325
8367
  rawComment,
8326
8368
  rawExtraFieldNTFS,
8327
- rawExtraFieldUnix,
8369
+ rawCentralExtraFieldUnix,
8328
8370
  rawExtraField,
8329
8371
  rawCentralExtraField,
8330
8372
  extraFieldExtendedTimestampFlag,
@@ -8386,7 +8428,7 @@
8386
8428
  rawExtraFieldZip64,
8387
8429
  rawExtraFieldAES,
8388
8430
  rawExtraFieldNTFS,
8389
- rawExtraFieldUnix,
8431
+ rawCentralExtraFieldUnix,
8390
8432
  rawExtraFieldTimestamp,
8391
8433
  rawExtraField,
8392
8434
  rawCentralExtraField);
@@ -8415,7 +8457,7 @@
8415
8457
  rawExtraFieldAES,
8416
8458
  rawExtraFieldExtendedTimestamp,
8417
8459
  rawExtraFieldNTFS,
8418
- rawExtraFieldUnix,
8460
+ rawCentralExtraFieldUnix,
8419
8461
  rawExtraField,
8420
8462
  rawCentralExtraField,
8421
8463
  rawComment,
@@ -8432,7 +8474,7 @@
8432
8474
  uncompressedSize,
8433
8475
  compressedSize
8434
8476
  } = fileEntry;
8435
- const extraFieldLength = getLength(rawExtraFieldZip64, rawExtraFieldAES, rawExtraFieldExtendedTimestamp, rawExtraFieldNTFS, rawExtraFieldUnix, rawExtraField, rawCentralExtraField);
8477
+ const extraFieldLength = getLength(rawExtraFieldZip64, rawExtraFieldAES, rawExtraFieldExtendedTimestamp, rawExtraFieldNTFS, rawCentralExtraFieldUnix, rawExtraField, rawCentralExtraField);
8436
8478
  const directoryRecordLength = CENTRAL_FILE_HEADER_LENGTH + getLength(rawFilename, rawComment) + extraFieldLength;
8437
8479
  if (exceedsAvailableSize(writer, offset + directoryRecordLength - directoryDiskOffset)) {
8438
8480
  await writeData(writer, directoryArray.slice(directoryDiskOffset, offset));
@@ -8468,7 +8510,7 @@
8468
8510
  directoryRecord.writeBytes(rawExtraFieldAES);
8469
8511
  directoryRecord.writeBytes(rawExtraFieldExtendedTimestamp);
8470
8512
  directoryRecord.writeBytes(rawExtraFieldNTFS);
8471
- directoryRecord.writeBytes(rawExtraFieldUnix);
8513
+ directoryRecord.writeBytes(rawCentralExtraFieldUnix);
8472
8514
  directoryRecord.writeBytes(rawExtraField);
8473
8515
  directoryRecord.writeBytes(rawCentralExtraField);
8474
8516
  directoryRecord.writeBytes(rawComment);
@@ -8637,26 +8679,42 @@
8637
8679
  return rawExtraField;
8638
8680
  }
8639
8681
 
8640
- async function copyZipData(zipWriter, reader, entries, directoryOffset) {
8682
+ async function copyZipData(zipWriter, reader, entries, keptEntries, directoryOffset, compact) {
8641
8683
  const { writer } = zipWriter;
8642
8684
  const entryPositions = new Map();
8643
- if (writer.closeDisk) {
8685
+ if (writer.closeDisk || compact) {
8644
8686
  const sortedEntries = Array.from(entries).sort((firstEntry, secondEntry) =>
8645
8687
  getSourceOffset(reader, firstEntry) - getSourceOffset(reader, secondEntry));
8646
- let copiedLength = 0;
8647
- for (const entry of sortedEntries) {
8648
- const sourceOffset = getSourceOffset(reader, entry);
8649
- await copyData(zipWriter, reader, copiedLength, sourceOffset - copiedLength);
8650
- if (exceedsAvailableSize(writer, await getLocalHeaderLength(reader, sourceOffset))) {
8651
- await writer.closeDisk();
8652
- }
8653
- entryPositions.set(entry, {
8654
- offset: getSegmentOffset(zipWriter, writer),
8655
- diskNumberStart: getDiskNumber(writer)
8656
- });
8657
- copiedLength = sourceOffset;
8688
+ const regionEnds = getRegionEnds(reader, sortedEntries, directoryOffset);
8689
+ const keptEntrySet = new Set(keptEntries);
8690
+ let copiedOffset = 0;
8691
+ let lastPosition;
8692
+ for (let indexEntry = 0; indexEntry < sortedEntries.length; indexEntry++) {
8693
+ const entry = sortedEntries[indexEntry];
8694
+ if (keptEntrySet.has(entry)) {
8695
+ const sourceOffset = getSourceOffset(reader, entry);
8696
+ if (sourceOffset < copiedOffset) {
8697
+ entryPositions.set(entry, lastPosition);
8698
+ } else {
8699
+ if (!compact) {
8700
+ await copyData(zipWriter, reader, copiedOffset, sourceOffset - copiedOffset);
8701
+ }
8702
+ if (writer.closeDisk && exceedsAvailableSize(writer, await getLocalHeaderLength(reader, sourceOffset))) {
8703
+ await writer.closeDisk();
8704
+ }
8705
+ lastPosition = {
8706
+ offset: getSegmentOffset(zipWriter, writer),
8707
+ diskNumberStart: getDiskNumber(writer)
8708
+ };
8709
+ entryPositions.set(entry, lastPosition);
8710
+ await copyData(zipWriter, reader, sourceOffset, regionEnds[indexEntry] - sourceOffset);
8711
+ copiedOffset = regionEnds[indexEntry];
8712
+ }
8713
+ }
8714
+ }
8715
+ if (!compact) {
8716
+ await copyData(zipWriter, reader, copiedOffset, directoryOffset - copiedOffset);
8658
8717
  }
8659
- await copyData(zipWriter, reader, copiedLength, directoryOffset - copiedLength);
8660
8718
  } else {
8661
8719
  const baseOffset = zipWriter.offset;
8662
8720
  await copyData(zipWriter, reader, 0, directoryOffset);
@@ -8668,6 +8726,20 @@
8668
8726
  return entryPositions;
8669
8727
  }
8670
8728
 
8729
+ function getRegionEnds(reader, sortedEntries, directoryOffset) {
8730
+ const regionEnds = new Array(sortedEntries.length);
8731
+ let regionEnd = directoryOffset;
8732
+ for (let indexEntry = sortedEntries.length - 1; indexEntry >= 0; indexEntry--) {
8733
+ const sourceOffset = getSourceOffset(reader, sortedEntries[indexEntry]);
8734
+ const nextEntry = sortedEntries[indexEntry + 1];
8735
+ if (nextEntry && getSourceOffset(reader, nextEntry) > sourceOffset) {
8736
+ regionEnd = getSourceOffset(reader, nextEntry);
8737
+ }
8738
+ regionEnds[indexEntry] = regionEnd;
8739
+ }
8740
+ return regionEnds;
8741
+ }
8742
+
8671
8743
  async function copyData(zipWriter, reader, offset, size) {
8672
8744
  if (size > 0) {
8673
8745
  const { writer } = zipWriter;
@@ -9045,7 +9117,7 @@
9045
9117
  EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
9046
9118
  */
9047
9119
 
9048
- const VERSION = "2.18.2";
9120
+ const VERSION = "2.20.0";
9049
9121
 
9050
9122
  /*
9051
9123
  Copyright (c) 2025 Gildas Lormeau. All rights reserved.
@@ -11106,11 +11178,13 @@
11106
11178
  exports.WARNING_COMPRESSION_UNAVAILABLE = WARNING_COMPRESSION_UNAVAILABLE;
11107
11179
  exports.WARNING_DUPLICATE_FILENAME = WARNING_DUPLICATE_FILENAME;
11108
11180
  exports.WARNING_MALFORMED_EXTRA_FIELD = WARNING_MALFORMED_EXTRA_FIELD;
11181
+ exports.WARNING_MISMATCHED_CENTRAL_DIRECTORY_OFFSET = WARNING_MISMATCHED_CENTRAL_DIRECTORY_OFFSET;
11109
11182
  exports.WARNING_MISMATCHED_LOCAL_FILE_HEADER_BIT_FLAG = WARNING_MISMATCHED_LOCAL_FILE_HEADER_BIT_FLAG;
11110
11183
  exports.WARNING_MISMATCHED_LOCAL_FILE_HEADER_COMPRESSION_METHOD = WARNING_MISMATCHED_LOCAL_FILE_HEADER_COMPRESSION_METHOD;
11111
11184
  exports.WARNING_MISMATCHED_LOCAL_FILE_HEADER_CRC32_OR_SIZES = WARNING_MISMATCHED_LOCAL_FILE_HEADER_CRC32_OR_SIZES;
11112
11185
  exports.WARNING_MISMATCHED_LOCAL_FILE_HEADER_FILENAME = WARNING_MISMATCHED_LOCAL_FILE_HEADER_FILENAME;
11113
11186
  exports.WARNING_MISMATCHED_ZIP64_END_OF_CENTRAL_DIRECTORY = WARNING_MISMATCHED_ZIP64_END_OF_CENTRAL_DIRECTORY;
11187
+ exports.WARNING_MISSING_ZIP64_EXTRA_FIELD = WARNING_MISSING_ZIP64_EXTRA_FIELD;
11114
11188
  exports.WARNING_MULTIPLE_END_OF_CENTRAL_DIRECTORY = WARNING_MULTIPLE_END_OF_CENTRAL_DIRECTORY;
11115
11189
  exports.WARNING_PREPENDED_CENTRAL_DIRECTORY = WARNING_PREPENDED_CENTRAL_DIRECTORY;
11116
11190
  exports.WARNING_PREPENDED_DATA = WARNING_PREPENDED_DATA;