@zip.js/zip.js 2.8.56 → 2.8.58

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.
@@ -92,6 +92,7 @@ const FILE_ATTR_UNIX_SETUID_MASK = 0o4000;
92
92
  const FILE_ATTR_UNIX_SETGID_MASK = 0o2000;
93
93
  const FILE_ATTR_UNIX_STICKY_MASK = 0o1000;
94
94
 
95
+ const VERSION_STORE = 0x0A;
95
96
  const VERSION_DEFLATE = 0x14;
96
97
  const VERSION_ZIP64 = 0x2D;
97
98
  const VERSION_AES = 0x33;
@@ -4758,6 +4759,7 @@ const ERR_UNSAFE_FILENAME = "Unsafe filename";
4758
4759
  const ERR_INVALID_STRICTNESS = "Invalid strictness (must be 'strict', 'balanced' or 'tolerant')";
4759
4760
  const ERR_INVALID_FILENAME_VALIDATION = "Invalid filenameValidation (must be 'strict', 'balanced' or 'tolerant')";
4760
4761
  const ERR_INVALID_MAX_APPENDED_DATA_SIZE = "Invalid maxAppendedDataSize (must be a number greater than or equal to 0)";
4762
+ const ERR_UNSUPPORTED_UINT64 = "64-bit value exceeds Number.MAX_SAFE_INTEGER";
4761
4763
  const DRIVE_LETTER_REGEXP = /^[a-zA-Z]:/;
4762
4764
  const CHARSET_UTF8 = "utf-8";
4763
4765
  const PROPERTY_NAME_UTF8_SUFFIX = "UTF8";
@@ -4780,6 +4782,7 @@ const ZIP64_EXTRACTION = {
4780
4782
  bytes: 8
4781
4783
  }
4782
4784
  };
4785
+ const MAX_SAFE_UINT64 = BigInt(Number.MAX_SAFE_INTEGER);
4783
4786
  const MAX_END_OF_CENTRAL_DIR_PROBES = 64;
4784
4787
  const MAX_DEFLATE_EXPANSION_RATIO = 1032;
4785
4788
  const CENTRAL_DIRECTORY_UNREACHABLE = 0;
@@ -4875,7 +4878,7 @@ class ZipReader {
4875
4878
  zip64EndOfDirectoryVersion2 = getBigUint64(endOfDirectoryView, 4) > ZIP64_END_OF_CENTRAL_DIR_LENGTH - 12;
4876
4879
  if (zip64EndOfDirectoryVersion2) {
4877
4880
  const extensibleDataLength = Math.min(
4878
- Number(getBigUint64(endOfDirectoryView, 4)) - (ZIP64_END_OF_CENTRAL_DIR_LENGTH - 12),
4881
+ getBigUint64(endOfDirectoryView, 4) - (ZIP64_END_OF_CENTRAL_DIR_LENGTH - 12),
4879
4882
  reader.size - directoryDataOffset - ZIP64_END_OF_CENTRAL_DIR_LENGTH);
4880
4883
  if (extensibleDataLength > 0) {
4881
4884
  zip64EndOfDirectoryLength += extensibleDataLength;
@@ -4975,6 +4978,10 @@ class ZipReader {
4975
4978
  const commentEncoding = getOptionValue$1(zipReader, options, OPTION_COMMENT_ENCODING);
4976
4979
  const filenames = checkAmbiguity ? new Set() : UNDEFINED_VALUE;
4977
4980
  let duplicateFilename;
4981
+ const recoverWrappedFilesLength = !checkAmbiguity && !zip64EndOfDirectory;
4982
+ if (!filesLength && recoverWrappedFilesLength) {
4983
+ filesLength = getWrappedFilesLength(directoryView, directoryArray, offset);
4984
+ }
4978
4985
  for (let indexFile = 0; indexFile < filesLength; indexFile++) {
4979
4986
  const fileEntry = new ZipEntry$1(reader, zipReader.options);
4980
4987
  if (offset + CENTRAL_FILE_HEADER_LENGTH > directoryArray.length || getUint32$1(directoryView, offset) != CENTRAL_FILE_HEADER_SIGNATURE) {
@@ -5084,7 +5091,7 @@ class ZipReader {
5084
5091
  internalFileAttribute: fileEntry.internalFileAttributes,
5085
5092
  externalFileAttribute: fileEntry.externalFileAttributes,
5086
5093
  executable,
5087
- directory: modeIsDir || upperIsDir || (msDosCompatible && msdosAttributes.directory) || (fileEntry.filename.endsWith(DIRECTORY_SIGNATURE) && !fileEntry.uncompressedSize),
5094
+ directory: modeIsDir || upperIsDir || (msDosCompatible && msdosAttributes.directory) || fileEntry.filename.endsWith(DIRECTORY_SIGNATURE),
5088
5095
  zipCrypto: fileEntry.encrypted && !fileEntry.extraFieldAES
5089
5096
  });
5090
5097
  const entry = new Entry(fileEntry);
@@ -5097,6 +5104,9 @@ class ZipReader {
5097
5104
  return arrayBufferPromise;
5098
5105
  };
5099
5106
  offset = endOffset;
5107
+ if (indexFile == filesLength - 1 && recoverWrappedFilesLength) {
5108
+ filesLength += getWrappedFilesLength(directoryView, directoryArray, offset);
5109
+ }
5100
5110
  const { onprogress } = options;
5101
5111
  if (onprogress) {
5102
5112
  try {
@@ -5255,6 +5265,7 @@ let ZipEntry$1 = class ZipEntry {
5255
5265
  extraFieldLength,
5256
5266
  filenameLength
5257
5267
  } = localDirectory;
5268
+ const dataOffset = localDirectory.dataOffset = localHeaderOffset + HEADER_SIZE + filenameLength + extraFieldLength;
5258
5269
  const checkLocalDirectoryOption = getOptionValue$1(zipEntry, options, OPTION_CHECK_LOCAL_DIRECTORY);
5259
5270
  const entryStrictness = getStrictness(options, zipEntry.options);
5260
5271
  const checkLocalDirectory = getCheckLocalDirectory(checkLocalDirectoryOption, entryStrictness);
@@ -5308,7 +5319,6 @@ let ZipEntry$1 = class ZipEntry {
5308
5319
  throw new Error(ERR_ENCRYPTED);
5309
5320
  }
5310
5321
  }
5311
- const dataOffset = localHeaderOffset + HEADER_SIZE + filenameLength + extraFieldLength;
5312
5322
  if (dataOffset + compressedSize > reader.size) {
5313
5323
  throw new Error(ERR_ENTRY_DATA_OUT_OF_BOUNDS);
5314
5324
  }
@@ -5428,6 +5438,16 @@ function detectEncryptedCentralDirectory(directoryView) {
5428
5438
  return false;
5429
5439
  }
5430
5440
 
5441
+ function getWrappedFilesLength(directoryView, directoryArray, offset) {
5442
+ let wrappedFilesLength = 0;
5443
+ while (offset + CENTRAL_FILE_HEADER_LENGTH <= directoryArray.length && getUint32$1(directoryView, offset) == CENTRAL_FILE_HEADER_SIGNATURE) {
5444
+ offset += CENTRAL_FILE_HEADER_LENGTH +
5445
+ getUint16$1(directoryView, offset + 28) + getUint16$1(directoryView, offset + 30) + getUint16$1(directoryView, offset + 32);
5446
+ wrappedFilesLength++;
5447
+ }
5448
+ return wrappedFilesLength % (MAX_16_BITS + 1) ? 0 : wrappedFilesLength;
5449
+ }
5450
+
5431
5451
  function readDigitalSignature(signatureRecordArray) {
5432
5452
  if (signatureRecordArray.length >= 6) {
5433
5453
  const signatureRecordView = getDataView(signatureRecordArray);
@@ -5456,8 +5476,8 @@ function getDirectoryEncryptionInfo(rawExtensibleData) {
5456
5476
  const hashDataLength = getUint16$1(extensibleDataView, 26);
5457
5477
  Object.assign(directoryEncryptionInfo, {
5458
5478
  compressionMethod: getUint16$1(extensibleDataView, 0),
5459
- compressedSize: Number(getBigUint64(extensibleDataView, 2)),
5460
- uncompressedSize: Number(getBigUint64(extensibleDataView, 10)),
5479
+ compressedSize: getBigUint64(extensibleDataView, 2),
5480
+ uncompressedSize: getBigUint64(extensibleDataView, 10),
5461
5481
  encryptionAlgorithm: getUint16$1(extensibleDataView, 18),
5462
5482
  bitLength: getUint16$1(extensibleDataView, 20),
5463
5483
  flags: getUint16$1(extensibleDataView, 22),
@@ -5600,10 +5620,11 @@ function readExtraFieldUnicode(extraFieldUnicode, propertyName, rawPropertyName,
5600
5620
  const computedCrc32View = getDataView(new Uint8Array(4));
5601
5621
  computedCrc32View.setUint32(0, computedCrc32.get(), true);
5602
5622
  const nameCrc32 = getUint32$1(extraFieldView, 1);
5623
+ const version = getUint8(extraFieldView, 0);
5603
5624
  Object.assign(extraFieldUnicode, {
5604
- version: getUint8(extraFieldView, 0),
5625
+ version,
5605
5626
  [propertyName]: decodeText(extraFieldUnicode.data.subarray(5)),
5606
- valid: !fileEntry.bitFlag.languageEncodingFlag && nameCrc32 == getUint32$1(computedCrc32View, 0)
5627
+ valid: version == 1 && !fileEntry.bitFlag.languageEncodingFlag && nameCrc32 == getUint32$1(computedCrc32View, 0)
5607
5628
  });
5608
5629
  if (extraFieldUnicode.valid) {
5609
5630
  directory[propertyName] = extraFieldUnicode[propertyName];
@@ -6072,7 +6093,8 @@ function getFunctionOptionValue$1(zipReader, options, name) {
6072
6093
 
6073
6094
  function getDate(timeRaw) {
6074
6095
  const date = (timeRaw & 0xffff0000) >> 16, time = timeRaw & MAX_16_BITS;
6075
- return new Date(1980 + ((date & 0xFE00) >> 9), ((date & 0x01E0) >> 5) - 1, date & 0x001F, (time & 0xF800) >> 11, (time & 0x07E0) >> 5, (time & 0x001F) * 2, 0);
6096
+ const result = new Date(1980 + ((date & 0xFE00) >> 9), ((date & 0x01E0) >> 5) - 1, date & 0x001F, (time & 0xF800) >> 11, (time & 0x07E0) >> 5, (time & 0x001F) * 2, 0);
6097
+ return result < MIN_DATE ? MIN_DATE : result;
6076
6098
  }
6077
6099
 
6078
6100
  function getDateNTFS(timeRaw) {
@@ -6092,7 +6114,11 @@ function getUint32$1(view, offset) {
6092
6114
  }
6093
6115
 
6094
6116
  function getBigUint64(view, offset) {
6095
- return Number(view.getBigUint64(offset, true));
6117
+ const value = view.getBigUint64(offset, true);
6118
+ if (value > MAX_SAFE_UINT64) {
6119
+ throw new Error(ERR_UNSUPPORTED_UINT64);
6120
+ }
6121
+ return Number(value);
6096
6122
  }
6097
6123
 
6098
6124
  var zipReader = /*#__PURE__*/Object.freeze({
@@ -6121,6 +6147,7 @@ var zipReader = /*#__PURE__*/Object.freeze({
6121
6147
  ERR_UNSAFE_FILENAME: ERR_UNSAFE_FILENAME,
6122
6148
  ERR_UNSUPPORTED_COMPRESSION: ERR_UNSUPPORTED_COMPRESSION$1,
6123
6149
  ERR_UNSUPPORTED_ENCRYPTION: ERR_UNSUPPORTED_ENCRYPTION,
6150
+ ERR_UNSUPPORTED_UINT64: ERR_UNSUPPORTED_UINT64,
6124
6151
  ERR_WORKER_STARTUP_TIMEOUT: ERR_WORKER_STARTUP_TIMEOUT,
6125
6152
  ZipReader: ZipReader,
6126
6153
  ZipReaderStream: ZipReaderStream
@@ -6220,153 +6247,150 @@ class ZipWriter {
6220
6247
  offset: options[OPTION_OFFSET] === UNDEFINED_VALUE ? writer.size || writer.writable.size || 0 : options[OPTION_OFFSET],
6221
6248
  initialOffset: options[OPTION_OFFSET] === UNDEFINED_VALUE ? 0 : options[OPTION_OFFSET] - (writer.size || writer.writable.size || 0),
6222
6249
  pendingAddFileCalls: new Set(),
6250
+ pendingErrors: [],
6223
6251
  bufferedWrites: 0,
6224
6252
  lastFileEntry: UNDEFINED_VALUE
6225
6253
  });
6226
6254
  }
6227
6255
 
6228
- async prependZip(reader) {
6229
- if (this.filenames.size) {
6230
- throw new Error(ERR_ZIP_NOT_EMPTY);
6231
- }
6232
- reader = new GenericReader(reader);
6233
- await initStream(reader);
6234
- if (reader.size === UNDEFINED_VALUE || !reader.readUint8Array) {
6235
- reader = new BlobReader(await streamToBlob(reader.readable));
6236
- await initStream(reader);
6237
- }
6238
- const { ZipReader } = await Promise.resolve().then(function () { return zipReader; });
6239
- const zipReader$1 = new ZipReader(reader);
6240
- const entries = await zipReader$1.getEntries();
6241
- await zipReader$1.close();
6242
- await initStream(this.writer);
6243
- const { directoryOffset } = zipReader$1;
6244
- if (this.addSplitZipSignature) {
6245
- delete this.addSplitZipSignature;
6246
- if (!await startsWithSplitZipSignature(reader)) {
6247
- await writeData(this.writer, getSplitZipSignatureArray());
6248
- this.offset += SPLIT_ZIP_FILE_SIGNATURE_LENGTH;
6249
- }
6250
- }
6251
- const entryPositions = await copyZipData(this, reader, entries, directoryOffset);
6252
- this.filenames = new Set(entries.map(entry => entry.filename));
6253
- this.fileEntries = new Map(entries.map(entry => {
6254
- const {
6255
- version,
6256
- rawLastModDate,
6257
- lastAccessDate,
6258
- creationDate,
6259
- rawFilename,
6260
- bitFlag,
6261
- encrypted,
6262
- uncompressedSize,
6263
- compressedSize,
6264
- zip64
6265
- } = entry;
6266
- let {
6267
- compressionMethod,
6268
- rawExtraFieldZip64,
6269
- rawExtraFieldAES,
6270
- rawExtraFieldExtendedTimestamp,
6271
- rawExtraFieldNTFS,
6272
- rawExtraFieldUnix,
6273
- rawExtraField,
6274
- } = entry;
6275
- const { level, languageEncodingFlag, dataDescriptor } = bitFlag;
6276
- rawExtraFieldZip64 = rawExtraFieldZip64 || EMPTY_UINT8_ARRAY;
6277
- rawExtraFieldAES = rawExtraFieldAES || EMPTY_UINT8_ARRAY;
6278
- rawExtraFieldExtendedTimestamp = rawExtraFieldExtendedTimestamp || EMPTY_UINT8_ARRAY;
6279
- rawExtraFieldNTFS = rawExtraFieldNTFS || EMPTY_UINT8_ARRAY;
6280
- rawExtraFieldUnix = rawExtraFieldUnix || EMPTY_UINT8_ARRAY;
6281
- rawExtraField = rawExtraField || EMPTY_UINT8_ARRAY;
6282
- if (entry.extraFieldAES) {
6283
- compressionMethod = COMPRESSION_METHOD_AES;
6284
- }
6285
- const extraFieldLength = getLength(rawExtraFieldZip64, rawExtraFieldAES, rawExtraFieldExtendedTimestamp, rawExtraFieldNTFS, rawExtraFieldUnix, rawExtraField);
6286
- const zip64UncompressedSize = zip64 && uncompressedSize >= MAX_32_BITS;
6287
- const zip64CompressedSize = zip64 && compressedSize >= MAX_32_BITS;
6288
- const bitFlagValue = (getBitFlag(level, languageEncodingFlag, dataDescriptor, encrypted, compressionMethod) & ~BITFLAG_LEVEL) | (level << 1);
6289
- const {
6290
- headerArray,
6291
- headerView
6292
- } = getHeaderArrayData({
6293
- version,
6294
- bitFlag: bitFlagValue,
6295
- compressionMethod,
6296
- uncompressedSize,
6297
- compressedSize,
6298
- rawLastModDate,
6299
- rawFilename,
6300
- zip64CompressedSize,
6301
- zip64UncompressedSize,
6302
- extraFieldLength
6303
- });
6304
- const { crc32 } = entry;
6305
- if (crc32 !== UNDEFINED_VALUE) {
6306
- setUint32(headerView, HEADER_OFFSET_SIGNATURE, crc32);
6307
- }
6308
- const { offset, diskNumberStart } = entryPositions.get(entry);
6309
- Object.assign(entry, {
6310
- zip64UncompressedSize,
6311
- zip64CompressedSize,
6312
- offset,
6313
- diskNumberStart,
6314
- zip64DiskNumberStart: false,
6315
- rawExtraFieldZip64,
6316
- rawExtraFieldAES,
6317
- rawExtraFieldExtendedTimestamp,
6318
- rawExtraFieldNTFS,
6319
- rawExtraFieldUnix,
6320
- rawExtraField,
6321
- extendedTimestamp: rawExtraFieldExtendedTimestamp.length > 0 || rawExtraFieldNTFS.length > 0,
6322
- extraFieldExtendedTimestampFlag: 0x1 + (lastAccessDate ? 0x2 : 0) + (creationDate ? 0x4 : 0),
6323
- headerArray,
6324
- headerView
6325
- });
6326
- return [entry.filename, entry];
6327
- }));
6256
+ prependZip(reader) {
6257
+ return watchPromiseError(this, prependZipEntries(this, reader));
6328
6258
  }
6329
6259
 
6330
- async add(name = "", reader, options = {}) {
6260
+ appendZip(reader) {
6261
+ return watchPromiseError(this, this.appendZipEntries(reader));
6262
+ }
6263
+
6264
+ async appendZipEntries(reader) {
6331
6265
  const zipWriter = this;
6332
- options = Object.assign({}, options);
6333
- const { pendingAddFileCalls } = zipWriter;
6334
- if (workers < getConfiguration().maxWorkers) {
6335
- workers++;
6336
- } else {
6337
- await new Promise(resolve => pendingEntries.push(resolve));
6266
+ const { pendingAddFileCalls, filenames, fileEntries } = zipWriter;
6267
+ while (pendingAddFileCalls.size) {
6268
+ await Promise.allSettled(Array.from(pendingAddFileCalls));
6338
6269
  }
6339
- let promiseAddFile;
6340
- let nameAdded;
6270
+ let resolveAppendZip;
6271
+ const promiseAppendZip = new Promise(resolve => resolveAppendZip = resolve);
6272
+ pendingAddFileCalls.add(promiseAppendZip);
6273
+ const appendedFilenames = [];
6274
+ let releaseLockWriter;
6341
6275
  try {
6342
- name = name.trim();
6343
- if (getOptionValue(zipWriter, options, PROPERTY_NAME_DIRECTORY) && !name.endsWith(DIRECTORY_SIGNATURE)) {
6344
- name += DIRECTORY_SIGNATURE;
6345
- }
6346
- if (zipWriter.filenames.has(name)) {
6347
- throw new Error(ERR_DUPLICATED_NAME);
6348
- }
6349
- zipWriter.filenames.add(name);
6350
- nameAdded = true;
6351
- promiseAddFile = addFile(zipWriter, name, reader, options);
6352
- pendingAddFileCalls.add(promiseAddFile);
6353
- return await promiseAddFile;
6354
- } catch (error) {
6355
- if (nameAdded) {
6356
- zipWriter.filenames.delete(name);
6276
+ reader = new GenericReader(reader);
6277
+ await initStream(reader);
6278
+ if (reader.size === UNDEFINED_VALUE || !reader.readUint8Array) {
6279
+ reader = new BlobReader(await streamToBlob(reader.readable));
6280
+ await initStream(reader);
6281
+ }
6282
+ const { ZipReader } = await Promise.resolve().then(function () { return zipReader; });
6283
+ const zipReader$1 = new ZipReader(reader);
6284
+ const entries = await zipReader$1.getEntries();
6285
+ await zipReader$1.close();
6286
+ await initStream(zipWriter.writer);
6287
+ const { directoryOffset } = zipReader$1;
6288
+ entries.forEach(({ filename }) => {
6289
+ if (filenames.has(filename)) {
6290
+ throw new Error(ERR_DUPLICATED_NAME);
6291
+ }
6292
+ filenames.add(filename);
6293
+ appendedFilenames.push(filename);
6294
+ });
6295
+ zipWriter.writerLocked = true;
6296
+ const { lockWriter } = zipWriter;
6297
+ zipWriter.lockWriter = new Promise(resolve => releaseLockWriter = () => {
6298
+ zipWriter.writerLocked = false;
6299
+ resolve();
6300
+ });
6301
+ await lockWriter;
6302
+ if (zipWriter.addSplitZipSignature) {
6303
+ delete zipWriter.addSplitZipSignature;
6304
+ if (!await startsWithSplitZipSignature(reader)) {
6305
+ await writeData(zipWriter.writer, getSplitZipSignatureArray());
6306
+ zipWriter.offset += SPLIT_ZIP_FILE_SIGNATURE_LENGTH;
6307
+ }
6357
6308
  }
6309
+ const entryPositions = await copyZipData(zipWriter, reader, entries, directoryOffset);
6310
+ entries.forEach(entry => {
6311
+ const {
6312
+ version,
6313
+ rawLastModDate,
6314
+ rawFilename,
6315
+ bitFlag,
6316
+ encrypted,
6317
+ uncompressedSize,
6318
+ compressedSize,
6319
+ extraFieldZip64
6320
+ } = entry;
6321
+ let {
6322
+ compressionMethod,
6323
+ rawExtraField,
6324
+ } = entry;
6325
+ const { level, languageEncodingFlag, dataDescriptor } = bitFlag;
6326
+ rawExtraField = removeExtraFieldZip64(rawExtraField || EMPTY_UINT8_ARRAY);
6327
+ if (entry.extraFieldAES) {
6328
+ compressionMethod = COMPRESSION_METHOD_AES;
6329
+ }
6330
+ const extraFieldLength = getLength(rawExtraField);
6331
+ const zip64UncompressedSize = Boolean(extraFieldZip64) && extraFieldZip64.uncompressedSize !== UNDEFINED_VALUE;
6332
+ const zip64CompressedSize = Boolean(extraFieldZip64) && extraFieldZip64.compressedSize !== UNDEFINED_VALUE;
6333
+ const bitFlagValue = (getBitFlag(level, languageEncodingFlag, dataDescriptor, encrypted, compressionMethod) & ~BITFLAG_LEVEL) | (level << 1);
6334
+ const {
6335
+ headerArray,
6336
+ headerView
6337
+ } = getHeaderArrayData({
6338
+ version,
6339
+ bitFlag: bitFlagValue,
6340
+ compressionMethod,
6341
+ uncompressedSize,
6342
+ compressedSize,
6343
+ rawLastModDate,
6344
+ rawFilename,
6345
+ zip64CompressedSize,
6346
+ zip64UncompressedSize,
6347
+ extraFieldLength
6348
+ });
6349
+ const { crc32 } = entry;
6350
+ if (crc32 !== UNDEFINED_VALUE) {
6351
+ setUint32(headerView, HEADER_OFFSET_SIGNATURE, crc32);
6352
+ }
6353
+ const { offset, diskNumberStart } = entryPositions.get(entry);
6354
+ Object.assign(entry, {
6355
+ zip64UncompressedSize,
6356
+ zip64CompressedSize,
6357
+ offset,
6358
+ diskNumberStart,
6359
+ zip64DiskNumberStart: false,
6360
+ rawExtraFieldZip64: EMPTY_UINT8_ARRAY,
6361
+ rawExtraFieldAES: EMPTY_UINT8_ARRAY,
6362
+ rawExtraFieldExtendedTimestamp: EMPTY_UINT8_ARRAY,
6363
+ rawExtraFieldNTFS: EMPTY_UINT8_ARRAY,
6364
+ rawExtraFieldUnix: EMPTY_UINT8_ARRAY,
6365
+ rawExtraField,
6366
+ extendedTimestamp: false,
6367
+ headerArray,
6368
+ headerView
6369
+ });
6370
+ fileEntries.set(entry.filename, entry);
6371
+ });
6372
+ } catch (error) {
6373
+ appendedFilenames.forEach(filename => filenames.delete(filename));
6358
6374
  throw error;
6359
6375
  } finally {
6360
- pendingAddFileCalls.delete(promiseAddFile);
6361
- const pendingEntry = pendingEntries.shift();
6362
- if (pendingEntry) {
6363
- pendingEntry();
6364
- } else {
6365
- workers--;
6376
+ resolveAppendZip();
6377
+ pendingAddFileCalls.delete(promiseAppendZip);
6378
+ if (releaseLockWriter) {
6379
+ releaseLockWriter();
6366
6380
  }
6367
6381
  }
6368
6382
  }
6369
6383
 
6384
+ add(name = "", reader, options = {}) {
6385
+ const zipWriter = this;
6386
+ const { pendingAddFileCalls } = zipWriter;
6387
+ const promiseAddFile = addFileEntry(zipWriter, name, reader, options);
6388
+ pendingAddFileCalls.add(promiseAddFile);
6389
+ const deletePendingAddFileCall = () => pendingAddFileCalls.delete(promiseAddFile);
6390
+ Promise.prototype.then.call(promiseAddFile, deletePendingAddFileCall, deletePendingAddFileCall);
6391
+ return watchPromiseError(zipWriter, promiseAddFile);
6392
+ }
6393
+
6370
6394
  remove(entry) {
6371
6395
  const { filenames, fileEntries } = this;
6372
6396
  // deno-lint-ignore valid-typeof
@@ -6397,6 +6421,19 @@ class ZipWriter {
6397
6421
  while (pendingAddFileCalls.size) {
6398
6422
  await Promise.allSettled(Array.from(pendingAddFileCalls));
6399
6423
  }
6424
+ await Promise.allSettled(zipWriter.pendingErrors.map(watcher => watcher.recorded));
6425
+ const unobservedWatchers = zipWriter.pendingErrors.filter(watcher => watcher.error && !watcher.observed);
6426
+ if (unobservedWatchers.length) {
6427
+ const unobservedErrors = unobservedWatchers.map(watcher => watcher.error);
6428
+ unobservedWatchers.forEach(watcher => watcher.observed = true);
6429
+ const [error] = unobservedErrors;
6430
+ try {
6431
+ error.entryErrors = unobservedErrors;
6432
+ } catch {
6433
+ // ignored
6434
+ }
6435
+ throw error;
6436
+ }
6400
6437
  await closeFile(zipWriter, comment, options);
6401
6438
  const preventClose = !ownsWritable(writer) && getOptionValue(zipWriter, options, OPTION_PREVENT_CLOSE);
6402
6439
  if (!preventClose) {
@@ -6431,11 +6468,7 @@ class ZipWriterStream {
6431
6468
  try {
6432
6469
  await zipWriter.close();
6433
6470
  } catch (error) {
6434
- try {
6435
- await zipWriter.writer.writable.abort(error);
6436
- } catch {
6437
- // ignored
6438
- }
6471
+ await abortWritable(zipWriter, error);
6439
6472
  }
6440
6473
  }
6441
6474
  }
@@ -6452,8 +6485,90 @@ class ZipWriterStream {
6452
6485
  }
6453
6486
 
6454
6487
  async close(comment = UNDEFINED_VALUE, options = {}) {
6455
- await Promise.all(Array.from(this.pendingAddFileCalls));
6456
- return this.zipWriter.close(comment, options);
6488
+ const { zipWriter } = this;
6489
+ const results = await Promise.allSettled(Array.from(this.pendingAddFileCalls));
6490
+ const entryErrors = results.filter(result => result.status == "rejected").map(result => result.reason);
6491
+ if (entryErrors.length) {
6492
+ const [error] = entryErrors;
6493
+ try {
6494
+ error.entryErrors = entryErrors;
6495
+ } catch {
6496
+ // ignored
6497
+ }
6498
+ await abortWritable(zipWriter, error);
6499
+ throw error;
6500
+ }
6501
+ try {
6502
+ return await zipWriter.close(comment, options);
6503
+ } catch (error) {
6504
+ await abortWritable(zipWriter, error);
6505
+ throw error;
6506
+ }
6507
+ }
6508
+ }
6509
+
6510
+ class WatchedPromise extends Promise {
6511
+
6512
+ then(onFulfilled, onRejected) {
6513
+ const { watcher } = this;
6514
+ if (watcher) {
6515
+ watcher.observed = true;
6516
+ }
6517
+ return super.then(onFulfilled, onRejected);
6518
+ }
6519
+ }
6520
+
6521
+ function watchPromiseError(zipWriter, promise) {
6522
+ const watchedPromise = new WatchedPromise((resolve, reject) => Promise.prototype.then.call(promise, resolve, reject));
6523
+ const watcher = {};
6524
+ watchedPromise.watcher = watcher;
6525
+ watcher.recorded = Promise.prototype.then.call(watchedPromise, UNDEFINED_VALUE, error => watcher.error = error);
6526
+ zipWriter.pendingErrors.push(watcher);
6527
+ return watchedPromise;
6528
+ }
6529
+
6530
+ async function prependZipEntries(zipWriter, reader) {
6531
+ if (zipWriter.filenames.size) {
6532
+ throw new Error(ERR_ZIP_NOT_EMPTY);
6533
+ }
6534
+ await zipWriter.appendZipEntries(reader);
6535
+ }
6536
+
6537
+ async function addFileEntry(zipWriter, name, reader, options) {
6538
+ options = Object.assign({}, options);
6539
+ name = name.trim();
6540
+ if (getOptionValue(zipWriter, options, PROPERTY_NAME_DIRECTORY) && !name.endsWith(DIRECTORY_SIGNATURE)) {
6541
+ name += DIRECTORY_SIGNATURE;
6542
+ }
6543
+ if (zipWriter.filenames.has(name)) {
6544
+ throw new Error(ERR_DUPLICATED_NAME);
6545
+ }
6546
+ zipWriter.filenames.add(name);
6547
+ if (workers < getConfiguration().maxWorkers) {
6548
+ workers++;
6549
+ } else {
6550
+ await new Promise(resolve => pendingEntries.push(resolve));
6551
+ }
6552
+ try {
6553
+ return await addFile(zipWriter, name, reader, options);
6554
+ } catch (error) {
6555
+ zipWriter.filenames.delete(name);
6556
+ throw error;
6557
+ } finally {
6558
+ const pendingEntry = pendingEntries.shift();
6559
+ if (pendingEntry) {
6560
+ pendingEntry();
6561
+ } else {
6562
+ workers--;
6563
+ }
6564
+ }
6565
+ }
6566
+
6567
+ async function abortWritable(zipWriter, error) {
6568
+ try {
6569
+ await zipWriter.writer.writable.abort(error);
6570
+ } catch {
6571
+ // ignored
6457
6572
  }
6458
6573
  }
6459
6574
 
@@ -6656,11 +6771,12 @@ function resolveMetadata(zipWriter, name, options) {
6656
6771
  if (getLength(rawComment) > MAX_16_BITS) {
6657
6772
  throw new Error(ERR_INVALID_ENTRY_COMMENT);
6658
6773
  }
6659
- const version = getOptionValue(zipWriter, options, PROPERTY_NAME_VERSION, VERSION_DEFLATE);
6660
- if (version > MAX_16_BITS) {
6774
+ const version = getOptionValue(zipWriter, options, PROPERTY_NAME_VERSION);
6775
+ if (version !== UNDEFINED_VALUE && version > MAX_16_BITS) {
6661
6776
  throw new Error(ERR_INVALID_VERSION);
6662
6777
  }
6663
6778
  const lastModDate = getDateOptionValue(zipWriter, options, PROPERTY_NAME_LAST_MODIFICATION_DATE, new Date());
6779
+ const rawLastModDate = getOptionValue(zipWriter, options, PROPERTY_NAME_RAW_LAST_MODIFICATION_DATE);
6664
6780
  const lastAccessDate = getDateOptionValue(zipWriter, options, PROPERTY_NAME_LAST_ACCESS_DATE);
6665
6781
  const creationDate = getDateOptionValue(zipWriter, options, PROPERTY_NAME_CREATION_DATE);
6666
6782
  const internalFileAttributes = getAliasedOptionValue(zipWriter, options, PROPERTY_NAME_INTERNAL_FILE_ATTRIBUTES, PROPERTY_NAME_DEPRECATED_INTERNAL_FILE_ATTRIBUTES, 0);
@@ -6704,7 +6820,7 @@ function resolveMetadata(zipWriter, name, options) {
6704
6820
  if (bufferedWrite && dataDescriptor === UNDEFINED_VALUE) {
6705
6821
  dataDescriptor = false;
6706
6822
  }
6707
- if (dataDescriptor === UNDEFINED_VALUE || zipCrypto) {
6823
+ if (dataDescriptor === UNDEFINED_VALUE || (zipCrypto && !passThrough)) {
6708
6824
  dataDescriptor = true;
6709
6825
  }
6710
6826
  if (level !== UNDEFINED_VALUE && level != 6) {
@@ -6723,6 +6839,7 @@ function resolveMetadata(zipWriter, name, options) {
6723
6839
  rawComment,
6724
6840
  version,
6725
6841
  lastModDate,
6842
+ rawLastModDate,
6726
6843
  lastAccessDate,
6727
6844
  creationDate,
6728
6845
  internalFileAttributes,
@@ -6840,6 +6957,10 @@ function resolveEntrySizes(zipWriter, hasContent, contentSize, metadata, options
6840
6957
  maximumCompressedSize = contentSize === UNDEFINED_VALUE ? getMaximumCompressedSize(uncompressedSize) + encryptionOverhead : contentSize;
6841
6958
  }
6842
6959
  }
6960
+ const emptyEntry = !encryptedEntry && (!hasContent || (contentSize === 0 && !passThrough)) && !isCompressed(compressionMethod, level);
6961
+ if (emptyEntry && !zipCrypto && getOptionValue(zipWriter, options, OPTION_DATA_DESCRIPTOR) === UNDEFINED_VALUE) {
6962
+ dataDescriptor = false;
6963
+ }
6843
6964
  const zip64UncompressedSize = zip64Enabled || uncompressedSize >= MAX_32_BITS;
6844
6965
  const zip64CompressedSize = zip64Enabled || maximumCompressedSize >= MAX_32_BITS;
6845
6966
  if (zip64UncompressedSize || zip64CompressedSize) {
@@ -6854,6 +6975,7 @@ function resolveEntrySizes(zipWriter, hasContent, contentSize, metadata, options
6854
6975
  maximumCompressedSize,
6855
6976
  resolvedOptions: {
6856
6977
  dataDescriptor,
6978
+ emptyEntry,
6857
6979
  zip64,
6858
6980
  zip64UncompressedSize,
6859
6981
  zip64CompressedSize,
@@ -6952,6 +7074,7 @@ async function getFileEntry(zipWriter, name, reader, entryInfo, options) {
6952
7074
  const {
6953
7075
  keepOrder,
6954
7076
  dataDescriptor,
7077
+ emptyEntry,
6955
7078
  signal
6956
7079
  } = options;
6957
7080
  const {
@@ -6976,7 +7099,7 @@ async function getFileEntry(zipWriter, name, reader, entryInfo, options) {
6976
7099
  lockPreviousFileEntry = previousFileEntry && previousFileEntry.lockFileEntry;
6977
7100
  requestLockCurrentFileEntry();
6978
7101
  }
6979
- if (options.bufferedWrite || !keepOrder || zipWriter.writerLocked || zipWriter.bufferedWrites || !dataDescriptor) {
7102
+ if (options.bufferedWrite || !keepOrder || zipWriter.writerLocked || zipWriter.bufferedWrites || (!dataDescriptor && !emptyEntry)) {
6980
7103
  bufferedWrite = true;
6981
7104
  zipWriter.bufferedWrites++;
6982
7105
  if (options.createTempStream) {
@@ -6992,10 +7115,8 @@ async function getFileEntry(zipWriter, name, reader, entryInfo, options) {
6992
7115
  }
6993
7116
  await initStream(fileWriter);
6994
7117
  const diskOffset = getDiskOffset(writer);
6995
- if (zipWriter.addSplitZipSignature) {
6996
- delete zipWriter.addSplitZipSignature;
6997
- await writeData(writer, getSplitZipSignatureArray());
6998
- zipWriter.offset += SPLIT_ZIP_FILE_SIGNATURE_LENGTH;
7118
+ if (zipWriter.addSplitZipSignature && !bufferedWrite) {
7119
+ await writeSplitZipSignature(zipWriter, writer);
6999
7120
  }
7000
7121
  if (usdz && !bufferedWrite) {
7001
7122
  appendExtraFieldUSDZ(entryInfo, zipWriter.offset - diskOffset);
@@ -7022,6 +7143,9 @@ async function getFileEntry(zipWriter, name, reader, entryInfo, options) {
7022
7143
  if (bufferedWrite) {
7023
7144
  await Promise.all([fileWriter.writable.getWriter().close(), lockPreviousFileEntry]);
7024
7145
  await requestLockWriter();
7146
+ if (zipWriter.addSplitZipSignature) {
7147
+ await writeSplitZipSignature(zipWriter, writer);
7148
+ }
7025
7149
  writingBufferedEntryData = true;
7026
7150
  writerSizeBeforeEntry = writer.size;
7027
7151
  await skipDiskIfNeeded();
@@ -7293,6 +7417,7 @@ function getHeaderInfo(options) {
7293
7417
  const {
7294
7418
  rawFilename,
7295
7419
  lastModDate,
7420
+ rawLastModDate: rawLastModDateOption,
7296
7421
  lastAccessDate,
7297
7422
  creationDate,
7298
7423
  level,
@@ -7398,8 +7523,8 @@ function getHeaderInfo(options) {
7398
7523
  try {
7399
7524
  const { uid, gid, unixExtraFieldType } = options;
7400
7525
  if (unixExtraFieldType == INFOZIP_EXTRA_FIELD_TYPE$1 && (uid !== UNDEFINED_VALUE || gid !== UNDEFINED_VALUE)) {
7401
- const uidBytes = packUnixId(uid);
7402
- const gidBytes = packUnixId(gid);
7526
+ const uidBytes = packUnixId(uid === UNDEFINED_VALUE ? 0 : uid);
7527
+ const gidBytes = packUnixId(gid === UNDEFINED_VALUE ? 0 : gid);
7403
7528
  const payloadLength = 3 + uidBytes.length + gidBytes.length;
7404
7529
  const extraFieldUnix = createRecordWriter(4 + payloadLength);
7405
7530
  extraFieldUnix.writeUint16(EXTRAFIELD_TYPE_INFOZIP);
@@ -7426,6 +7551,9 @@ function getHeaderInfo(options) {
7426
7551
  if (compressionMethod === UNDEFINED_VALUE) {
7427
7552
  compressionMethod = compressed ? COMPRESSION_METHOD_DEFLATE : COMPRESSION_METHOD_STORE;
7428
7553
  }
7554
+ if (version === UNDEFINED_VALUE) {
7555
+ version = compressionMethod == COMPRESSION_METHOD_STORE && !directory && !encrypted ? VERSION_STORE : VERSION_DEFLATE;
7556
+ }
7429
7557
  const { codecVersionNeeded } = options;
7430
7558
  if (compressed && codecVersionNeeded !== UNDEFINED_VALUE) {
7431
7559
  version = version > codecVersionNeeded ? version : codecVersionNeeded;
@@ -7458,6 +7586,7 @@ function getHeaderInfo(options) {
7458
7586
  compressionMethod,
7459
7587
  uncompressedSize,
7460
7588
  lastModDate: dosLastModDate < MIN_DATE ? MIN_DATE : dosLastModDate > MAX_DATE ? MAX_DATE : dosLastModDate,
7589
+ rawLastModDate: rawLastModDateOption,
7461
7590
  rawFilename,
7462
7591
  zip64CompressedSize,
7463
7592
  zip64UncompressedSize,
@@ -7530,18 +7659,14 @@ function appendExtraFieldUSDZ(entryInfo, zipWriterOffset) {
7530
7659
  }
7531
7660
 
7532
7661
  function packUnixId(id) {
7533
- if (id === UNDEFINED_VALUE) {
7534
- return EMPTY_UINT8_ARRAY;
7535
- } else {
7536
- const dataArray = new Uint8Array(4);
7537
- const dataView = getDataView(dataArray);
7538
- dataView.setUint32(0, id, true);
7539
- let length = 4;
7540
- while (length > 1 && dataArray[length - 1] === 0) {
7541
- length--;
7542
- }
7543
- return dataArray.subarray(0, length);
7662
+ const dataArray = new Uint8Array(4);
7663
+ const dataView = getDataView(dataArray);
7664
+ dataView.setUint32(0, id, true);
7665
+ let length = 4;
7666
+ while (length > 1 && dataArray[length - 1] === 0) {
7667
+ length--;
7544
7668
  }
7669
+ return dataArray.subarray(0, length);
7545
7670
  }
7546
7671
 
7547
7672
  function normalizeMsdosAttributes(msdosAttributesRaw, msdosAttributes) {
@@ -7668,9 +7793,9 @@ function updateLocalHeader({
7668
7793
 
7669
7794
  async function closeFile(zipWriter, comment, options) {
7670
7795
  const directoryDataLength = createDirectoryRecords(zipWriter.fileEntries);
7671
- const { directoryStart, directoryArray } = await writeDirectoryRecords(zipWriter, directoryDataLength, options);
7796
+ const { directoryStart, directoryEnd, directoryArray } = await writeDirectoryRecords(zipWriter, directoryDataLength, options);
7672
7797
  const signatureLength = await writeDigitalSignatureRecord(zipWriter, directoryArray, options);
7673
- await writeEndOfDirectoryRecord(zipWriter, comment, options, { directoryStart, directoryDataLength, signatureLength });
7798
+ await writeEndOfDirectoryRecord(zipWriter, comment, options, { directoryStart, directoryEnd, directoryDataLength, signatureLength });
7674
7799
  }
7675
7800
 
7676
7801
  function createDirectoryRecords(files) {
@@ -7754,6 +7879,7 @@ async function writeDirectoryRecords(zipWriter, directoryDataLength, options) {
7754
7879
  let directoryDiskOffset = 0;
7755
7880
  let directoryStartDiskNumber = getDiskNumber(writer);
7756
7881
  let directoryStartDiskOffset = getDiskOffset(writer);
7882
+ let directoryEndDiskEntriesLength = 0;
7757
7883
  for (const [indexFileEntry, fileEntry] of Array.from(fileEntries.values()).entries()) {
7758
7884
  const {
7759
7885
  offset: fileEntryOffset,
@@ -7783,6 +7909,7 @@ async function writeDirectoryRecords(zipWriter, directoryDataLength, options) {
7783
7909
  if (exceedsAvailableSize(writer, offset + directoryRecordLength - directoryDiskOffset)) {
7784
7910
  await writeData(writer, directoryArray.slice(directoryDiskOffset, offset));
7785
7911
  directoryDiskOffset = offset;
7912
+ directoryEndDiskEntriesLength = 0;
7786
7913
  await writer.closeDisk();
7787
7914
  }
7788
7915
  if (indexFileEntry == 0) {
@@ -7818,6 +7945,7 @@ async function writeDirectoryRecords(zipWriter, directoryDataLength, options) {
7818
7945
  directoryRecord.writeBytes(rawComment);
7819
7946
  arraySet(directoryArray, directoryRecord.array, offset);
7820
7947
  offset += directoryRecordLength;
7948
+ directoryEndDiskEntriesLength++;
7821
7949
  if (options.onprogress) {
7822
7950
  try {
7823
7951
  await options.onprogress(indexFileEntry + 1, fileEntries.size, new Entry(fileEntry));
@@ -7829,6 +7957,7 @@ async function writeDirectoryRecords(zipWriter, directoryDataLength, options) {
7829
7957
  await writeData(writer, directoryDiskOffset ? directoryArray.slice(directoryDiskOffset) : directoryArray);
7830
7958
  return {
7831
7959
  directoryStart: { diskNumber: directoryStartDiskNumber, diskOffset: directoryStartDiskOffset },
7960
+ directoryEnd: { diskNumber: getDiskNumber(writer), entriesLength: directoryEndDiskEntriesLength },
7832
7961
  directoryArray
7833
7962
  };
7834
7963
  }
@@ -7857,16 +7986,20 @@ async function writeDigitalSignatureRecord(zipWriter, directoryArray, options) {
7857
7986
 
7858
7987
  async function writeEndOfDirectoryRecord(zipWriter, comment, options, cdInfo) {
7859
7988
  const { writer } = zipWriter;
7860
- const { directoryStart, signatureLength } = cdInfo;
7989
+ const { directoryStart, directoryEnd, signatureLength } = cdInfo;
7861
7990
  let { directoryDataLength } = cdInfo;
7862
7991
  let fileEntriesLength = zipWriter.fileEntries.size;
7863
7992
  let diskNumber = directoryStart.diskNumber;
7864
7993
  let directoryOffset = getSegmentOffset(zipWriter, directoryStart);
7994
+ const commentLength = getLength(comment);
7995
+ if (commentLength > MAX_16_BITS) {
7996
+ throw new Error(ERR_INVALID_COMMENT);
7997
+ }
7998
+ let zip64 = getOptionValue(zipWriter, options, PROPERTY_NAME_ZIP64);
7865
7999
  let lastDiskNumber = getDiskNumber(writer);
7866
- if (exceedsAvailableSize(writer, END_OF_CENTRAL_DIR_LENGTH)) {
8000
+ if (exceedsAvailableSize(writer, (zip64 ? ZIP64_END_OF_CENTRAL_DIR_TOTAL_LENGTH : END_OF_CENTRAL_DIR_LENGTH) + commentLength)) {
7867
8001
  lastDiskNumber++;
7868
8002
  }
7869
- let zip64 = getOptionValue(zipWriter, options, PROPERTY_NAME_ZIP64);
7870
8003
  if (directoryOffset >= MAX_32_BITS || directoryDataLength >= MAX_32_BITS || fileEntriesLength >= MAX_16_BITS || lastDiskNumber >= MAX_16_BITS) {
7871
8004
  if (zip64 === false) {
7872
8005
  throw new Error(ERR_UNSUPPORTED_FORMAT);
@@ -7874,15 +8007,12 @@ async function writeEndOfDirectoryRecord(zipWriter, comment, options, cdInfo) {
7874
8007
  zip64 = true;
7875
8008
  }
7876
8009
  }
7877
- const commentLength = getLength(comment);
7878
- if (commentLength > MAX_16_BITS) {
7879
- throw new Error(ERR_INVALID_COMMENT);
7880
- }
7881
8010
  const endOfdirectoryRecord = createRecordWriter(zip64 ? ZIP64_END_OF_CENTRAL_DIR_TOTAL_LENGTH : END_OF_CENTRAL_DIR_LENGTH);
7882
8011
  if (exceedsAvailableSize(writer, getLength(endOfdirectoryRecord.array) + commentLength)) {
7883
8012
  await writer.closeDisk();
7884
8013
  }
7885
8014
  lastDiskNumber = getDiskNumber(writer);
8015
+ let diskFileEntriesLength = lastDiskNumber == directoryEnd.diskNumber ? directoryEnd.entriesLength : 0;
7886
8016
  if (zip64) {
7887
8017
  endOfdirectoryRecord.writeUint32(ZIP64_END_OF_CENTRAL_DIR_SIGNATURE);
7888
8018
  endOfdirectoryRecord.writeUint64(44);
@@ -7890,7 +8020,7 @@ async function writeEndOfDirectoryRecord(zipWriter, comment, options, cdInfo) {
7890
8020
  endOfdirectoryRecord.writeUint16(45);
7891
8021
  endOfdirectoryRecord.writeUint32(lastDiskNumber);
7892
8022
  endOfdirectoryRecord.writeUint32(diskNumber);
7893
- endOfdirectoryRecord.writeUint64(fileEntriesLength);
8023
+ endOfdirectoryRecord.writeUint64(diskFileEntriesLength);
7894
8024
  endOfdirectoryRecord.writeUint64(fileEntriesLength);
7895
8025
  endOfdirectoryRecord.writeUint64(directoryDataLength);
7896
8026
  endOfdirectoryRecord.writeUint64(directoryOffset);
@@ -7903,6 +8033,7 @@ async function writeEndOfDirectoryRecord(zipWriter, comment, options, cdInfo) {
7903
8033
  lastDiskNumber = MAX_16_BITS;
7904
8034
  diskNumber = MAX_16_BITS;
7905
8035
  }
8036
+ diskFileEntriesLength = MAX_16_BITS;
7906
8037
  fileEntriesLength = MAX_16_BITS;
7907
8038
  directoryOffset = MAX_32_BITS;
7908
8039
  directoryDataLength = MAX_32_BITS;
@@ -7910,7 +8041,7 @@ async function writeEndOfDirectoryRecord(zipWriter, comment, options, cdInfo) {
7910
8041
  endOfdirectoryRecord.writeUint32(END_OF_CENTRAL_DIR_SIGNATURE);
7911
8042
  endOfdirectoryRecord.writeUint16(lastDiskNumber);
7912
8043
  endOfdirectoryRecord.writeUint16(diskNumber);
7913
- endOfdirectoryRecord.writeUint16(fileEntriesLength);
8044
+ endOfdirectoryRecord.writeUint16(diskFileEntriesLength);
7914
8045
  endOfdirectoryRecord.writeUint16(fileEntriesLength);
7915
8046
  endOfdirectoryRecord.writeUint32(directoryDataLength);
7916
8047
  endOfdirectoryRecord.writeUint32(directoryOffset);
@@ -7960,6 +8091,21 @@ async function startsWithSplitZipSignature(reader) {
7960
8091
  return getUint32(getDataView(signatureArray), 0) == SPLIT_ZIP_FILE_SIGNATURE;
7961
8092
  }
7962
8093
 
8094
+ function removeExtraFieldZip64(rawExtraField) {
8095
+ const rawExtraFieldView = getDataView(rawExtraField);
8096
+ let offsetExtraField = 0;
8097
+ while (offsetExtraField + 4 <= getLength(rawExtraField)) {
8098
+ const size = 4 + getUint16(rawExtraFieldView, offsetExtraField + 2);
8099
+ if (getUint16(rawExtraFieldView, offsetExtraField) == EXTRAFIELD_TYPE_ZIP64) {
8100
+ return removeExtraFieldZip64(concat(
8101
+ rawExtraField.subarray(0, offsetExtraField),
8102
+ rawExtraField.subarray(Math.min(offsetExtraField + size, getLength(rawExtraField)))));
8103
+ }
8104
+ offsetExtraField += size;
8105
+ }
8106
+ return rawExtraField;
8107
+ }
8108
+
7963
8109
  async function copyZipData(zipWriter, reader, entries, directoryOffset) {
7964
8110
  const { writer } = zipWriter;
7965
8111
  const entryPositions = new Map();
@@ -7994,9 +8140,21 @@ async function copyZipData(zipWriter, reader, entries, directoryOffset) {
7994
8140
  async function copyData(zipWriter, reader, offset, size) {
7995
8141
  if (size > 0) {
7996
8142
  const { writer } = zipWriter;
7997
- await createReadable(reader, { offset, size }).pipeTo(writer.writable, { preventClose: true, preventAbort: true });
7998
- writer.size += size;
7999
- zipWriter.offset += size;
8143
+ let copiedLength = 0;
8144
+ try {
8145
+ await flushBufferedData(createReadable(reader, { offset, size }), writer, UNDEFINED_VALUE, chunkLength => copiedLength += chunkLength);
8146
+ } catch (error) {
8147
+ zipWriter.hasCorruptedEntries = true;
8148
+ try {
8149
+ error.corruptedEntry = true;
8150
+ } catch {
8151
+ // ignored
8152
+ }
8153
+ throw error;
8154
+ } finally {
8155
+ writer.size += copiedLength;
8156
+ zipWriter.offset += copiedLength;
8157
+ }
8000
8158
  }
8001
8159
  }
8002
8160
 
@@ -8021,6 +8179,12 @@ function getSplitZipSignatureArray() {
8021
8179
  return signatureArray;
8022
8180
  }
8023
8181
 
8182
+ async function writeSplitZipSignature(zipWriter, writer) {
8183
+ delete zipWriter.addSplitZipSignature;
8184
+ await writeData(writer, getSplitZipSignatureArray());
8185
+ zipWriter.offset += SPLIT_ZIP_FILE_SIGNATURE_LENGTH;
8186
+ }
8187
+
8024
8188
  async function writeData(writer, array) {
8025
8189
  const { writable } = writer;
8026
8190
  const streamWriter = writable.getWriter();
@@ -9107,6 +9271,7 @@ const ERR_ENTRY_EXISTS = "Entry filename already exists";
9107
9271
  const ERR_READABLE_CONSUMED = "Readable stream already consumed";
9108
9272
  const ERR_INVALID_PASS_THROUGH = "Invalid passThrough option (use readerOptions.passThrough or set uncompressedSize for each entry)";
9109
9273
  const ERR_INVALID_READER_OPTIONS = "Invalid readerOptions (must be an object)";
9274
+ const ERR_ZIP_CRYPTO_LAST_MOD_DATE = "The last modification date of an entry encrypted with ZipCrypto cannot be changed when passThrough is set";
9110
9275
  const ERR_ABORT_EXPORT = "zipjs-abort-export";
9111
9276
  const ERR_ABORTED = "The operation was aborted";
9112
9277
  const ABORT_ERROR_NAME = "AbortError";
@@ -9864,7 +10029,7 @@ function keepsContentType(writer, data) {
9864
10029
  } else if (writer.constructor == BlobWriter) {
9865
10030
  return data.type == contentType;
9866
10031
  } else if (writer.constructor == Data64URIWriter) {
9867
- return data.startsWith(writer.data);
10032
+ return data.startsWith("data:" + (contentType || "") + ";base64,");
9868
10033
  } else {
9869
10034
  return true;
9870
10035
  }
@@ -9974,6 +10139,7 @@ function getChildEntryOptions(child, selectedEntry, options) {
9974
10139
  versionMadeBy,
9975
10140
  comment,
9976
10141
  lastModDate,
10142
+ rawLastModDate,
9977
10143
  creationDate,
9978
10144
  lastAccessDate,
9979
10145
  uncompressedSize,
@@ -9984,6 +10150,7 @@ function getChildEntryOptions(child, selectedEntry, options) {
9984
10150
  extraFieldAES,
9985
10151
  internalFileAttributes,
9986
10152
  extraField,
10153
+ bitFlag,
9987
10154
  uid,
9988
10155
  gid
9989
10156
  } = child.data;
@@ -10021,6 +10188,16 @@ function getChildEntryOptions(child, selectedEntry, options) {
10021
10188
  encryptionStrength,
10022
10189
  compressionMethod
10023
10190
  };
10191
+ if (bitFlag) {
10192
+ passThroughOptions.dataDescriptor = bitFlag.dataDescriptor;
10193
+ }
10194
+ const lastModDateOverride = childOptions.lastModDate === UNDEFINED_VALUE ? options.lastModDate : childOptions.lastModDate;
10195
+ if (lastModDateOverride === UNDEFINED_VALUE) {
10196
+ passThroughOptions.rawLastModDate = rawLastModDate;
10197
+ } else if (zipCrypto && (!bitFlag || bitFlag.dataDescriptor) && lastModDateOverride instanceof Date &&
10198
+ getDosTimeHighByte(lastModDateOverride) != ((rawLastModDate >>> 8) & MAX_8_BITS)) {
10199
+ throw new Error(ERR_ZIP_CRYPTO_LAST_MOD_DATE);
10200
+ }
10024
10201
  }
10025
10202
  }
10026
10203
  const entryOptions = Object.assign({ lastModDate: child.defaultLastModDate }, zipEntryMetadata, options, childOptions, passThroughOptions, { directory: child.directory });
@@ -10030,6 +10207,16 @@ function getChildEntryOptions(child, selectedEntry, options) {
10030
10207
  return { name, entryOptions };
10031
10208
  }
10032
10209
 
10210
+ function getDosTimeHighByte(lastModDate) {
10211
+ let dosLastModDate = new Date(Math.ceil(Math.floor(lastModDate.getTime() / 1000) / 2) * 2000);
10212
+ if (dosLastModDate < MIN_DATE) {
10213
+ dosLastModDate = MIN_DATE;
10214
+ } else if (dosLastModDate > MAX_DATE) {
10215
+ dosLastModDate = MAX_DATE;
10216
+ }
10217
+ return ((dosLastModDate.getHours() << 3) | (dosLastModDate.getMinutes() >> 3)) & MAX_8_BITS;
10218
+ }
10219
+
10033
10220
  function getDeterminedSize(child, passThrough) {
10034
10221
  const { reader } = child;
10035
10222
  if (reader && reader.size !== UNDEFINED_VALUE) {
@@ -10432,4 +10619,4 @@ function decodeMimeTypes(data) {
10432
10619
  return mimeTypes;
10433
10620
  }
10434
10621
 
10435
- export { BlobReader, BlobWriter, Data64URIReader, Data64URIWriter, ERR_ABORTED, ERR_AMBIGUOUS_ARCHIVE, ERR_BAD_FORMAT, ERR_CENTRAL_DIRECTORY_NOT_FOUND, ERR_DUPLICATED_NAME, ERR_ENCRYPTED, ERR_ENCRYPTED_CENTRAL_DIRECTORY, ERR_ENTRY_DATA_OUT_OF_BOUNDS, ERR_ENTRY_EXISTS, ERR_EOCDR_LOCATOR_ZIP64_NOT_FOUND, ERR_EOCDR_NOT_FOUND, ERR_EXTRAFIELD_ZIP64_NOT_FOUND, ERR_HTTP_RANGE, ERR_HTTP_RESOURCE_CHANGED, ERR_INVALID_AUTHENTICATION_CODE, ERR_INVALID_CODEC_DEFINITION, ERR_INVALID_CODEC_MODULE, ERR_INVALID_COMMENT, ERR_INVALID_COMMENT_TYPE, ERR_INVALID_COMPRESSED_DATA, ERR_INVALID_CRC32, ERR_INVALID_DATE, ERR_INVALID_ENCRYPTION_STRENGTH, ERR_INVALID_ENTRY_COMMENT, ERR_INVALID_ENTRY_COMMENT_TYPE, ERR_INVALID_ENTRY_NAME, ERR_INVALID_EXTRAFIELD, ERR_INVALID_EXTRAFIELD_DATA, ERR_INVALID_EXTRAFIELD_DATA_TYPE, ERR_INVALID_EXTRAFIELD_TYPE, ERR_INVALID_FILENAME_VALIDATION, ERR_INVALID_FUNCTION_OPTION, ERR_INVALID_GID, ERR_INVALID_LEVEL, ERR_INVALID_MAX_APPENDED_DATA_SIZE, ERR_INVALID_MAX_WORKERS, ERR_INVALID_MSDOS_ATTRIBUTES, ERR_INVALID_MSDOS_DATA, ERR_INVALID_PASSWORD, ERR_INVALID_PASSWORD_TYPE, ERR_INVALID_PASS_THROUGH, ERR_INVALID_READER_OPTIONS, ERR_INVALID_SIGNAL, ERR_INVALID_SIGNATURE, ERR_INVALID_SIGNATURE_DATA, ERR_INVALID_STRICTNESS, ERR_INVALID_UID, ERR_INVALID_UNCOMPRESSED_SIZE, ERR_INVALID_UNIX_EXTRA_FIELD_TYPE, ERR_INVALID_UNIX_ID_SIZE, ERR_INVALID_UNIX_MODE, ERR_INVALID_VERSION, ERR_ITERATOR_COMPLETED_TOO_SOON, ERR_LOCAL_FILE_HEADER_NOT_FOUND, ERR_OVERLAPPING_ENTRY, ERR_READABLE_CONSUMED, ERR_RESERVED_COMPRESSION_METHOD, ERR_SPLIT_ZIP_FILE, ERR_UNDEFINED_COMPRESSION_METHOD, ERR_UNDEFINED_READER, ERR_UNDEFINED_UNCOMPRESSED_SIZE, ERR_UNDETERMINED_SIZE, ERR_UNSAFE_FILENAME, ERR_UNSUPPORTED_COMPRESSION$1 as ERR_UNSUPPORTED_COMPRESSION, ERR_UNSUPPORTED_CONTEXT, ERR_UNSUPPORTED_CRYPTO_API, ERR_UNSUPPORTED_ENCRYPTION, ERR_UNSUPPORTED_ENCRYPTION_PASS_THROUGH, ERR_UNSUPPORTED_ENCRYPTION_USDZ, ERR_UNSUPPORTED_FORMAT, ERR_WORKER_STARTUP_TIMEOUT, ERR_WRITER_NOT_INITIALIZED, ERR_ZIP_NOT_EMPTY, HttpRangeReader, HttpReader, Reader, SplitDataReader, SplitDataWriter, TextReader, TextWriter, Uint8ArrayReader, Uint8ArrayWriter, Writer, ZipDirectoryEntry, ZipEntry, ZipFS, ZipFileEntry, ZipReader, ZipReaderStream, ZipWriter, ZipWriterStream, configure, createBlobTempStream, createOPFSTempStream, createSyncAccessHandleTempStream, fs, getMimeType, registerCodec, resetConfiguration, terminateWorkersAndModule as terminateWorkers, unregisterCodec };
10622
+ export { BlobReader, BlobWriter, Data64URIReader, Data64URIWriter, ERR_ABORTED, ERR_AMBIGUOUS_ARCHIVE, ERR_BAD_FORMAT, ERR_CENTRAL_DIRECTORY_NOT_FOUND, ERR_DUPLICATED_NAME, ERR_ENCRYPTED, ERR_ENCRYPTED_CENTRAL_DIRECTORY, ERR_ENTRY_DATA_OUT_OF_BOUNDS, ERR_ENTRY_EXISTS, ERR_EOCDR_LOCATOR_ZIP64_NOT_FOUND, ERR_EOCDR_NOT_FOUND, ERR_EXTRAFIELD_ZIP64_NOT_FOUND, ERR_HTTP_RANGE, ERR_HTTP_RESOURCE_CHANGED, ERR_INVALID_AUTHENTICATION_CODE, ERR_INVALID_CODEC_DEFINITION, ERR_INVALID_CODEC_MODULE, ERR_INVALID_COMMENT, ERR_INVALID_COMMENT_TYPE, ERR_INVALID_COMPRESSED_DATA, ERR_INVALID_CRC32, ERR_INVALID_DATE, ERR_INVALID_ENCRYPTION_STRENGTH, ERR_INVALID_ENTRY_COMMENT, ERR_INVALID_ENTRY_COMMENT_TYPE, ERR_INVALID_ENTRY_NAME, ERR_INVALID_EXTRAFIELD, ERR_INVALID_EXTRAFIELD_DATA, ERR_INVALID_EXTRAFIELD_DATA_TYPE, ERR_INVALID_EXTRAFIELD_TYPE, ERR_INVALID_FILENAME_VALIDATION, ERR_INVALID_FUNCTION_OPTION, ERR_INVALID_GID, ERR_INVALID_LEVEL, ERR_INVALID_MAX_APPENDED_DATA_SIZE, ERR_INVALID_MAX_WORKERS, ERR_INVALID_MSDOS_ATTRIBUTES, ERR_INVALID_MSDOS_DATA, ERR_INVALID_PASSWORD, ERR_INVALID_PASSWORD_TYPE, ERR_INVALID_PASS_THROUGH, ERR_INVALID_READER_OPTIONS, ERR_INVALID_SIGNAL, ERR_INVALID_SIGNATURE, ERR_INVALID_SIGNATURE_DATA, ERR_INVALID_STRICTNESS, ERR_INVALID_UID, ERR_INVALID_UNCOMPRESSED_SIZE, ERR_INVALID_UNIX_EXTRA_FIELD_TYPE, ERR_INVALID_UNIX_ID_SIZE, ERR_INVALID_UNIX_MODE, ERR_INVALID_VERSION, ERR_ITERATOR_COMPLETED_TOO_SOON, ERR_LOCAL_FILE_HEADER_NOT_FOUND, ERR_OVERLAPPING_ENTRY, ERR_READABLE_CONSUMED, ERR_RESERVED_COMPRESSION_METHOD, ERR_SPLIT_ZIP_FILE, ERR_UNDEFINED_COMPRESSION_METHOD, ERR_UNDEFINED_READER, ERR_UNDEFINED_UNCOMPRESSED_SIZE, ERR_UNDETERMINED_SIZE, ERR_UNSAFE_FILENAME, ERR_UNSUPPORTED_COMPRESSION$1 as ERR_UNSUPPORTED_COMPRESSION, ERR_UNSUPPORTED_CONTEXT, ERR_UNSUPPORTED_CRYPTO_API, ERR_UNSUPPORTED_ENCRYPTION, ERR_UNSUPPORTED_ENCRYPTION_PASS_THROUGH, ERR_UNSUPPORTED_ENCRYPTION_USDZ, ERR_UNSUPPORTED_FORMAT, ERR_UNSUPPORTED_UINT64, ERR_WORKER_STARTUP_TIMEOUT, ERR_WRITER_NOT_INITIALIZED, ERR_ZIP_CRYPTO_LAST_MOD_DATE, ERR_ZIP_NOT_EMPTY, HttpRangeReader, HttpReader, Reader, SplitDataReader, SplitDataWriter, TextReader, TextWriter, Uint8ArrayReader, Uint8ArrayWriter, Writer, ZipDirectoryEntry, ZipEntry, ZipFS, ZipFileEntry, ZipReader, ZipReaderStream, ZipWriter, ZipWriterStream, configure, createBlobTempStream, createOPFSTempStream, createSyncAccessHandleTempStream, fs, getMimeType, registerCodec, resetConfiguration, terminateWorkersAndModule as terminateWorkers, unregisterCodec };