@zip.js/zip.js 2.8.60 → 2.9.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/index.cjs CHANGED
@@ -489,7 +489,7 @@ function getDataView(array) {
489
489
  // Every table MUST stay a PACKED_SMI array: build with array literals (not `new Array(n)`,
490
490
  // which is HOLEY) and store the signed int32 XOR result (no `>>> 0`). An unsigned or holey
491
491
  // table becomes a V8 FixedDoubleArray whose every hot-loop lookup unboxes a double (~1.6x
492
- // slower). Signedness is irrelevant to the result — the reads mask/shift it and the final
492
+ // slower). Signedness is irrelevant to the result: the reads mask/shift it and the final
493
493
  // `~crc` normalizes it. Do NOT reintroduce `>>> 0` here or switch to `new Array(256)`.
494
494
  const T = [[], [], [], [], [], [], [], []];
495
495
  for (let n = 0; n < 256; n++) {
@@ -3477,7 +3477,7 @@ async function terminateWorkers() {
3477
3477
 
3478
3478
  /* global TextDecoder */
3479
3479
 
3480
- const CP437 = "\0☺☻♥♦♣♠•◘○◙♂♀♪♫☼►◄↕‼¶§▬↨↑↓→←∟↔▲▼ !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~⌂ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜ¢£¥₧ƒáíóúñѪº¿⌐¬½¼¡«»░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀αßΓπΣσµτΦΘΩδ∞φε∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■ ".split("");
3480
+ const CP437 = "\0\u263A\u263B\u2665\u2666\u2663\u2660\u2022\u25D8\u25CB\u25D9\u2642\u2640\u266A\u266B\u263C\u25BA\u25C4\u2195\u203C\u00B6\u00A7\u25AC\u21A8\u2191\u2193\u2192\u2190\u221F\u2194\u25B2\u25BC !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\u2302\u00C7\u00FC\u00E9\u00E2\u00E4\u00E0\u00E5\u00E7\u00EA\u00EB\u00E8\u00EF\u00EE\u00EC\u00C4\u00C5\u00C9\u00E6\u00C6\u00F4\u00F6\u00F2\u00FB\u00F9\u00FF\u00D6\u00DC\u00A2\u00A3\u00A5\u20A7\u0192\u00E1\u00ED\u00F3\u00FA\u00F1\u00D1\u00AA\u00BA\u00BF\u2310\u00AC\u00BD\u00BC\u00A1\u00AB\u00BB\u2591\u2592\u2593\u2502\u2524\u2561\u2562\u2556\u2555\u2563\u2551\u2557\u255D\u255C\u255B\u2510\u2514\u2534\u252C\u251C\u2500\u253C\u255E\u255F\u255A\u2554\u2569\u2566\u2560\u2550\u256C\u2567\u2568\u2564\u2565\u2559\u2558\u2552\u2553\u256B\u256A\u2518\u250C\u2588\u2584\u258C\u2590\u2580\u03B1\u00DF\u0393\u03C0\u03A3\u03C3\u00B5\u03C4\u03A6\u0398\u03A9\u03B4\u221E\u03C6\u03B5\u2229\u2261\u00B1\u2265\u2264\u2320\u2321\u00F7\u2248\u00B0\u2219\u00B7\u221A\u207F\u00B2\u25A0\u00A0".split("");
3481
3481
  const VALID_CP437 = CP437.length == 256;
3482
3482
 
3483
3483
  function decodeCP437(stringValue) {
@@ -4743,6 +4743,7 @@ const WARNING_UNKNOWN_ZIP64_EXTENSIBLE_DATA = "unknown zip64 extensible data";
4743
4743
  const WARNING_WRAPPED_ENTRIES_COUNT = "wrapped entries count";
4744
4744
  const WARNING_APPENDED_DATA = "appended data";
4745
4745
  const WARNING_PREPENDED_DATA = "prepended data";
4746
+ const WARNING_PREPENDED_CENTRAL_DIRECTORY = "prepended central directory";
4746
4747
  const WARNING_TRAILING_CENTRAL_DIRECTORY_DATA = "trailing central directory data";
4747
4748
  const WARNING_DUPLICATE_FILENAME = "duplicate filename";
4748
4749
  const WARNING_MISMATCHED_ZIP64_END_OF_CENTRAL_DIRECTORY = "mismatched zip64 end of central directory record";
@@ -4836,6 +4837,7 @@ class ZipReader {
4836
4837
  let diskNumber = getUint16$1(endOfDirectoryView, 6);
4837
4838
  let filesLength = getUint16$1(endOfDirectoryView, 10);
4838
4839
  let prependedDataLength = 0;
4840
+ let prependedCentralDirectory;
4839
4841
  let startOffset;
4840
4842
  let zip64EndOfDirectory;
4841
4843
  let zip64EndOfDirectoryVersion2;
@@ -4939,6 +4941,7 @@ class ZipReader {
4939
4941
  directoryDataOffset = expectedDirectoryDataOffset;
4940
4942
  if (directoryDataOffset > originalDirectoryDataOffset) {
4941
4943
  prependedDataLength += directoryDataOffset - originalDirectoryDataOffset;
4944
+ prependedCentralDirectory = storedPointsAtDirectory;
4942
4945
  }
4943
4946
  directoryArray = await readUint8Array(reader, directoryDataOffset, directoryDataLength);
4944
4947
  directoryView = getDataView(directoryArray);
@@ -5166,6 +5169,9 @@ class ZipReader {
5166
5169
  if (prependedDataLength || (filesLength && startOffset > SPLIT_ZIP_FILE_SIGNATURE_LENGTH)) {
5167
5170
  addWarning(warnings, WARNING_PREPENDED_DATA);
5168
5171
  }
5172
+ if (prependedCentralDirectory) {
5173
+ addWarning(warnings, WARNING_PREPENDED_CENTRAL_DIRECTORY);
5174
+ }
5169
5175
  if (extractPrependedData) {
5170
5176
  zipReader.prependedData = startOffset > splitZipSignatureLength ?
5171
5177
  await readUint8Array(reader, splitZipSignatureLength, startOffset - splitZipSignatureLength) :
@@ -6226,6 +6232,7 @@ var zipReader = /*#__PURE__*/Object.freeze({
6226
6232
  WARNING_MISMATCHED_LOCAL_FILE_HEADER_COMPRESSION_METHOD: WARNING_MISMATCHED_LOCAL_FILE_HEADER_COMPRESSION_METHOD,
6227
6233
  WARNING_MISMATCHED_LOCAL_FILE_HEADER_CRC32_OR_SIZES: WARNING_MISMATCHED_LOCAL_FILE_HEADER_CRC32_OR_SIZES,
6228
6234
  WARNING_MISMATCHED_ZIP64_END_OF_CENTRAL_DIRECTORY: WARNING_MISMATCHED_ZIP64_END_OF_CENTRAL_DIRECTORY,
6235
+ WARNING_PREPENDED_CENTRAL_DIRECTORY: WARNING_PREPENDED_CENTRAL_DIRECTORY,
6229
6236
  WARNING_PREPENDED_DATA: WARNING_PREPENDED_DATA,
6230
6237
  WARNING_TRAILING_CENTRAL_DIRECTORY_DATA: WARNING_TRAILING_CENTRAL_DIRECTORY_DATA,
6231
6238
  WARNING_UNKNOWN_VERSION: WARNING_UNKNOWN_VERSION,
@@ -6674,6 +6681,13 @@ async function addFile(zipWriter, name, reader, options) {
6674
6681
  const { comment } = metadataInfo;
6675
6682
  const extraField = options[PROPERTY_NAME_EXTRA_FIELD];
6676
6683
  zipWriter.fileEntries.set(name, UNDEFINED_VALUE);
6684
+ const previousFileEntry = zipWriter.lastFileEntry;
6685
+ const pendingFileEntry = {};
6686
+ let releaseLockFileEntry;
6687
+ if (metadataInfo.resolvedOptions.keepOrder) {
6688
+ pendingFileEntry.lockFileEntry = new Promise(resolve => releaseLockFileEntry = resolve);
6689
+ }
6690
+ zipWriter.lastFileEntry = pendingFileEntry;
6677
6691
  let fileEntry;
6678
6692
  try {
6679
6693
  const { resolvedOptions } = metadataInfo;
@@ -6695,10 +6709,21 @@ async function addFile(zipWriter, name, reader, options) {
6695
6709
  const headerInfo = getHeaderInfo(options);
6696
6710
  const dataDescriptorInfo = getDataDescriptorInfo(options);
6697
6711
  const metadataSize = getLength(headerInfo.localHeaderArray, dataDescriptorInfo.dataDescriptorArray);
6698
- fileEntry = await getFileEntry(zipWriter, name, reader, { headerInfo, dataDescriptorInfo, metadataSize }, options);
6712
+ fileEntry = await getFileEntry(zipWriter, name, reader, {
6713
+ headerInfo,
6714
+ dataDescriptorInfo,
6715
+ metadataSize,
6716
+ fileEntry: pendingFileEntry,
6717
+ previousFileEntry,
6718
+ releaseLockFileEntry
6719
+ }, options);
6699
6720
  } catch (error) {
6700
6721
  zipWriter.fileEntries.delete(name);
6701
6722
  throw error;
6723
+ } finally {
6724
+ if (releaseLockFileEntry) {
6725
+ releaseLockFileEntry(previousFileEntry && previousFileEntry.lockFileEntry);
6726
+ }
6702
6727
  }
6703
6728
  Object.assign(fileEntry, {
6704
6729
  name,
@@ -7086,7 +7111,6 @@ async function getEntriesSize(writerOptions, entries, writeOrderGuaranteed, comm
7086
7111
  }
7087
7112
  const usdz = writerOptions[OPTION_USDZ];
7088
7113
  const files = new Map();
7089
- let layoutDependsOnWriteOrder = Boolean(usdz);
7090
7114
  const initialOffset = writerOptions[OPTION_OFFSET] === UNDEFINED_VALUE ? 0 : writerOptions[OPTION_OFFSET];
7091
7115
  let offset = initialOffset;
7092
7116
  let minimumEntrySize = INFINITY_VALUE;
@@ -7132,9 +7156,7 @@ async function getEntriesSize(writerOptions, entries, writeOrderGuaranteed, comm
7132
7156
  minimumEntrySize = Math.min(minimumEntrySize, entrySize);
7133
7157
  offset += entrySize;
7134
7158
  }
7135
- if (files.size && offset - minimumEntrySize >= MAX_32_BITS) {
7136
- layoutDependsOnWriteOrder = true;
7137
- }
7159
+ const layoutDependsOnWriteOrder = files.size > 1 && (usdz || offset - minimumEntrySize >= MAX_32_BITS);
7138
7160
  if (layoutDependsOnWriteOrder && !writeOrderGuaranteed) {
7139
7161
  throw new Error(ERR_UNDETERMINED_SIZE);
7140
7162
  }
@@ -7162,27 +7184,23 @@ async function getFileEntry(zipWriter, name, reader, entryInfo, options) {
7162
7184
  signal
7163
7185
  } = options;
7164
7186
  const {
7165
- headerInfo
7187
+ headerInfo,
7188
+ fileEntry: pendingFileEntry,
7189
+ previousFileEntry,
7190
+ releaseLockFileEntry
7166
7191
  } = entryInfo;
7167
7192
  const usdz = zipWriter.options[OPTION_USDZ];
7168
- const previousFileEntry = zipWriter.lastFileEntry;
7169
- let fileEntry = {};
7193
+ let fileEntry = pendingFileEntry;
7170
7194
  let bufferedWrite;
7171
7195
  let releaseLockWriter;
7172
- let releaseLockCurrentFileEntry;
7173
7196
  let writingBufferedEntryData;
7174
7197
  let writingEntryData;
7175
7198
  let writerSizeBeforeEntry;
7176
7199
  let flushedBufferedSize = 0;
7177
7200
  let fileWriter;
7201
+ const lockPreviousFileEntry = keepOrder && previousFileEntry ? previousFileEntry.lockFileEntry : UNDEFINED_VALUE;
7178
7202
  fileEntries.set(name, fileEntry);
7179
- zipWriter.lastFileEntry = fileEntry;
7180
7203
  try {
7181
- let lockPreviousFileEntry;
7182
- if (keepOrder) {
7183
- lockPreviousFileEntry = previousFileEntry && previousFileEntry.lockFileEntry;
7184
- requestLockCurrentFileEntry();
7185
- }
7186
7204
  if (options.bufferedWrite || !keepOrder || zipWriter.writerLocked || zipWriter.bufferedWrites || (!dataDescriptor && !emptyEntry)) {
7187
7205
  bufferedWrite = true;
7188
7206
  zipWriter.bufferedWrites++;
@@ -7195,6 +7213,7 @@ async function getFileEntry(zipWriter, name, reader, entryInfo, options) {
7195
7213
  await initStream(writer);
7196
7214
  } else {
7197
7215
  fileWriter = writer;
7216
+ await lockPreviousFileEntry;
7198
7217
  await requestLockWriter();
7199
7218
  }
7200
7219
  await initStream(fileWriter);
@@ -7207,7 +7226,6 @@ async function getFileEntry(zipWriter, name, reader, entryInfo, options) {
7207
7226
  }
7208
7227
  const { localHeaderArray } = headerInfo;
7209
7228
  if (!bufferedWrite) {
7210
- await lockPreviousFileEntry;
7211
7229
  await skipDiskIfNeeded();
7212
7230
  }
7213
7231
  const diskNumberStart = getDiskNumber(writer);
@@ -7272,8 +7290,8 @@ async function getFileEntry(zipWriter, name, reader, entryInfo, options) {
7272
7290
  if (bufferedWrite) {
7273
7291
  zipWriter.bufferedWrites--;
7274
7292
  }
7275
- if (releaseLockCurrentFileEntry) {
7276
- releaseLockCurrentFileEntry();
7293
+ if (releaseLockFileEntry) {
7294
+ releaseLockFileEntry(lockPreviousFileEntry);
7277
7295
  }
7278
7296
  if (releaseLockWriter) {
7279
7297
  releaseLockWriter();
@@ -7287,10 +7305,6 @@ async function getFileEntry(zipWriter, name, reader, entryInfo, options) {
7287
7305
  }
7288
7306
  }
7289
7307
 
7290
- function requestLockCurrentFileEntry() {
7291
- fileEntry.lockFileEntry = new Promise(resolve => releaseLockCurrentFileEntry = resolve);
7292
- }
7293
-
7294
7308
  async function requestLockWriter() {
7295
7309
  zipWriter.writerLocked = true;
7296
7310
  const { lockWriter } = zipWriter;
@@ -8610,7 +8624,7 @@ function formatSupported(StreamClass, format) {
8610
8624
  EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
8611
8625
  */
8612
8626
 
8613
- const VERSION = "2.8.60";
8627
+ const VERSION = "2.9.0";
8614
8628
 
8615
8629
  /*
8616
8630
  Copyright (c) 2025 Gildas Lormeau. All rights reserved.
@@ -9962,12 +9976,13 @@ class ZipDirectoryEntry extends ZipEntry {
9962
9976
  if (options.bufferedWrite === UNDEFINED_VALUE) {
9963
9977
  options.bufferedWrite = true;
9964
9978
  }
9965
- const writeOrderGuaranteed = !options.bufferedWrite ||
9966
- (options.keepOrder !== false && zipEntry.children.every(child => !child.children.length));
9967
- return getEntriesSize(options, zipEntry.getChildren({ recursive: true }).filter(child => !isImplicitDirectory(child)).map(child => {
9979
+ const entries = zipEntry.getChildren({ recursive: true }).filter(child => !isImplicitDirectory(child)).map(child => {
9968
9980
  const { name, entryOptions } = getChildEntryOptions(child, zipEntry, options);
9969
9981
  return { name, size: child.directory ? 0 : getDeterminedSize(child, isPassThrough(child, options)), options: entryOptions };
9970
- }), writeOrderGuaranteed, options.globalComment);
9982
+ });
9983
+ const writeOrderGuaranteed = !options.bufferedWrite ||
9984
+ (entries.every(entry => entry.options.keepOrder !== false) && zipEntry.children.every(child => !child.children.length));
9985
+ return getEntriesSize(options, entries, writeOrderGuaranteed, options.globalComment);
9971
9986
  }
9972
9987
 
9973
9988
  getChildByName(name) {
@@ -10981,6 +10996,7 @@ exports.WARNING_MISMATCHED_LOCAL_FILE_HEADER_BIT_FLAG = WARNING_MISMATCHED_LOCAL
10981
10996
  exports.WARNING_MISMATCHED_LOCAL_FILE_HEADER_COMPRESSION_METHOD = WARNING_MISMATCHED_LOCAL_FILE_HEADER_COMPRESSION_METHOD;
10982
10997
  exports.WARNING_MISMATCHED_LOCAL_FILE_HEADER_CRC32_OR_SIZES = WARNING_MISMATCHED_LOCAL_FILE_HEADER_CRC32_OR_SIZES;
10983
10998
  exports.WARNING_MISMATCHED_ZIP64_END_OF_CENTRAL_DIRECTORY = WARNING_MISMATCHED_ZIP64_END_OF_CENTRAL_DIRECTORY;
10999
+ exports.WARNING_PREPENDED_CENTRAL_DIRECTORY = WARNING_PREPENDED_CENTRAL_DIRECTORY;
10984
11000
  exports.WARNING_PREPENDED_DATA = WARNING_PREPENDED_DATA;
10985
11001
  exports.WARNING_TRAILING_CENTRAL_DIRECTORY_DATA = WARNING_TRAILING_CENTRAL_DIRECTORY_DATA;
10986
11002
  exports.WARNING_UNKNOWN_VERSION = WARNING_UNKNOWN_VERSION;
package/index.d.cts CHANGED
@@ -1467,8 +1467,10 @@ export class ZipReader<Type> {
1467
1467
  * {@link WARNING_UNKNOWN_VERSION} (the low byte of the "version needed to extract" field exceeds the highest
1468
1468
  * known zip specification version; the high byte is ignored because some writers store a host identifier in it),
1469
1469
  * {@link WARNING_COMPRESSED_PATCHED_DATA} (bit 5 of the general purpose bit flag),
1470
- * {@link WARNING_MALFORMED_EXTRA_FIELD}, {@link WARNING_UNKNOWN_ZIP64_EXTENSIBLE_DATA} and
1471
- * {@link WARNING_WRAPPED_ENTRIES_COUNT}. The other reasons are the checks that
1470
+ * {@link WARNING_MALFORMED_EXTRA_FIELD}, {@link WARNING_UNKNOWN_ZIP64_EXTENSIBLE_DATA},
1471
+ * {@link WARNING_WRAPPED_ENTRIES_COUNT} and {@link WARNING_PREPENDED_CENTRAL_DIRECTORY} (the prepended data
1472
+ * holds a central directory of its own, i.e. another archive precedes this one and other readers may report
1473
+ * its entries instead). The other reasons are the checks that
1472
1474
  * `strictness: "strict"` rejects with {@link ERR_AMBIGUOUS_ARCHIVE}: when the effective strictness tolerates
1473
1475
  * one of them and the evidence is already in hand, the same reason string is deposited as a warning instead —
1474
1476
  * {@link WARNING_APPENDED_DATA}, {@link WARNING_PREPENDED_DATA}, {@link WARNING_TRAILING_CENTRAL_DIRECTORY_DATA},
@@ -4842,6 +4844,19 @@ export const WARNING_APPENDED_DATA: string;
4842
4844
  * {@link ERR_AMBIGUOUS_ARCHIVE} under `strictness: "strict"`
4843
4845
  */
4844
4846
  export const WARNING_PREPENDED_DATA: string;
4847
+ /**
4848
+ * Warning reason: the data prepended before the zip file holds a central directory of its own, i.e. the zip file
4849
+ * is preceded by another archive rather than by an arbitrary prefix such as a self-extracting stub
4850
+ * (see {@link ZipReader#warnings})
4851
+ *
4852
+ * @remarks
4853
+ * Readers disagree on such files: zip.js reads the last archive, as Info-ZIP `unzip` and Python's `zipfile` do,
4854
+ * whereas 7-Zip reads the first one and reports the rest as data after the end of the archive. The archive is
4855
+ * therefore ambiguous, and the entries reported here may not be the entries another tool reports. It is always
4856
+ * accompanied by {@link WARNING_PREPENDED_DATA}, which alone does not distinguish this case from a benign prefix.
4857
+ * Use `strictness: "strict"` to reject these archives instead, at the cost of also rejecting benign prefixes.
4858
+ */
4859
+ export const WARNING_PREPENDED_CENTRAL_DIRECTORY: string;
4845
4860
  /**
4846
4861
  * Warning reason: data lies between the end of the central directory records and the end of central directory
4847
4862
  * record, either inside the declared central directory length or beyond it (see {@link ZipReader#warnings});
package/index.d.ts CHANGED
@@ -1467,8 +1467,10 @@ export class ZipReader<Type> {
1467
1467
  * {@link WARNING_UNKNOWN_VERSION} (the low byte of the "version needed to extract" field exceeds the highest
1468
1468
  * known zip specification version; the high byte is ignored because some writers store a host identifier in it),
1469
1469
  * {@link WARNING_COMPRESSED_PATCHED_DATA} (bit 5 of the general purpose bit flag),
1470
- * {@link WARNING_MALFORMED_EXTRA_FIELD}, {@link WARNING_UNKNOWN_ZIP64_EXTENSIBLE_DATA} and
1471
- * {@link WARNING_WRAPPED_ENTRIES_COUNT}. The other reasons are the checks that
1470
+ * {@link WARNING_MALFORMED_EXTRA_FIELD}, {@link WARNING_UNKNOWN_ZIP64_EXTENSIBLE_DATA},
1471
+ * {@link WARNING_WRAPPED_ENTRIES_COUNT} and {@link WARNING_PREPENDED_CENTRAL_DIRECTORY} (the prepended data
1472
+ * holds a central directory of its own, i.e. another archive precedes this one and other readers may report
1473
+ * its entries instead). The other reasons are the checks that
1472
1474
  * `strictness: "strict"` rejects with {@link ERR_AMBIGUOUS_ARCHIVE}: when the effective strictness tolerates
1473
1475
  * one of them and the evidence is already in hand, the same reason string is deposited as a warning instead —
1474
1476
  * {@link WARNING_APPENDED_DATA}, {@link WARNING_PREPENDED_DATA}, {@link WARNING_TRAILING_CENTRAL_DIRECTORY_DATA},
@@ -4842,6 +4844,19 @@ export const WARNING_APPENDED_DATA: string;
4842
4844
  * {@link ERR_AMBIGUOUS_ARCHIVE} under `strictness: "strict"`
4843
4845
  */
4844
4846
  export const WARNING_PREPENDED_DATA: string;
4847
+ /**
4848
+ * Warning reason: the data prepended before the zip file holds a central directory of its own, i.e. the zip file
4849
+ * is preceded by another archive rather than by an arbitrary prefix such as a self-extracting stub
4850
+ * (see {@link ZipReader#warnings})
4851
+ *
4852
+ * @remarks
4853
+ * Readers disagree on such files: zip.js reads the last archive, as Info-ZIP `unzip` and Python's `zipfile` do,
4854
+ * whereas 7-Zip reads the first one and reports the rest as data after the end of the archive. The archive is
4855
+ * therefore ambiguous, and the entries reported here may not be the entries another tool reports. It is always
4856
+ * accompanied by {@link WARNING_PREPENDED_DATA}, which alone does not distinguish this case from a benign prefix.
4857
+ * Use `strictness: "strict"` to reject these archives instead, at the cost of also rejecting benign prefixes.
4858
+ */
4859
+ export const WARNING_PREPENDED_CENTRAL_DIRECTORY: string;
4845
4860
  /**
4846
4861
  * Warning reason: data lies between the end of the central directory records and the end of central directory
4847
4862
  * record, either inside the declared central directory length or beyond it (see {@link ZipReader#warnings});