@zip.js/zip.js 2.8.50 → 2.8.52

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-native.cjs CHANGED
@@ -84,6 +84,8 @@ const FILE_ATTR_MSDOS_SYSTEM_MASK = 0x04;
84
84
  const FILE_ATTR_MSDOS_ARCHIVE_MASK = 0x20;
85
85
  const FILE_ATTR_UNIX_TYPE_MASK = 0o170000;
86
86
  const FILE_ATTR_UNIX_TYPE_DIR = 0o040000;
87
+ const FILE_ATTR_UNIX_TYPE_SYMLINK = 0o120000;
88
+ const FILE_ATTR_UNIX_TYPE_FILE = 0o100000;
87
89
  const FILE_ATTR_UNIX_EXECUTABLE_MASK = 0o111;
88
90
  const FILE_ATTR_UNIX_DEFAULT_MASK = 0o644;
89
91
  const FILE_ATTR_UNIX_SETUID_MASK = 0o4000;
@@ -1775,8 +1777,6 @@ function getInt32(number) {
1775
1777
  */
1776
1778
 
1777
1779
 
1778
- const HTTP_HEADER_CONTENT_TYPE = "Content-Type";
1779
-
1780
1780
  function toCompatibleReadable(readable) {
1781
1781
  if (readable instanceof ReadableStream) {
1782
1782
  return readable;
@@ -1799,12 +1799,9 @@ function toCompatibleReadable(readable) {
1799
1799
 
1800
1800
  function streamToBlob(readable, contentType) {
1801
1801
  readable = toCompatibleReadable(readable);
1802
+ const blobOptions = contentType ? { type: contentType } : {};
1802
1803
  if (responseSupportsGlobalReadable()) {
1803
- const options = {};
1804
- if (contentType) {
1805
- options.headers = [[HTTP_HEADER_CONTENT_TYPE, contentType]];
1806
- }
1807
- return new Response(readable, options).blob();
1804
+ return new Response(readable).blob().then(blob => contentType ? new Blob([blob], blobOptions) : blob);
1808
1805
  }
1809
1806
  const chunks = [];
1810
1807
  return readable
@@ -1813,7 +1810,7 @@ function streamToBlob(readable, contentType) {
1813
1810
  chunks.push(chunk);
1814
1811
  }
1815
1812
  }))
1816
- .then(() => new Blob(chunks, contentType ? { type: contentType } : {}));
1813
+ .then(() => new Blob(chunks, blobOptions));
1817
1814
  }
1818
1815
 
1819
1816
  function responseSupportsGlobalReadable() {
@@ -3344,8 +3341,10 @@ class Reader extends Stream {
3344
3341
  async pull(controller) {
3345
3342
  const dataSize = size === UNDEFINED_VALUE ? chunkSize : Math.min(chunkSize, size - chunkOffset);
3346
3343
  const data = await readUint8Array(reader, offset + chunkOffset, dataSize);
3347
- controller.enqueue(data);
3348
- if ((chunkOffset + chunkSize > size) || (size === UNDEFINED_VALUE && !data.length && dataSize)) {
3344
+ if (data.length) {
3345
+ controller.enqueue(data);
3346
+ }
3347
+ if ((chunkOffset + chunkSize >= size) || (size === UNDEFINED_VALUE && !data.length && dataSize)) {
3349
3348
  controller.close();
3350
3349
  } else {
3351
3350
  chunkOffset += chunkSize;
@@ -3423,6 +3422,7 @@ class Data64URIWriter extends Writer {
3423
3422
  constructor(contentType) {
3424
3423
  super();
3425
3424
  Object.assign(this, {
3425
+ contentType,
3426
3426
  data: "data:" + (contentType || "") + ";base64,",
3427
3427
  pending: []
3428
3428
  });
@@ -3524,6 +3524,7 @@ class BlobWriter extends Stream {
3524
3524
  return transformStream.writable;
3525
3525
  }
3526
3526
  });
3527
+ writer.contentType = contentType;
3527
3528
  writer.blob = streamToBlob(transformStream.readable, contentType);
3528
3529
  writer.blob.catch(() => { });
3529
3530
  }
@@ -3540,6 +3541,26 @@ class TextReader extends BlobReader {
3540
3541
  }
3541
3542
  }
3542
3543
 
3544
+ function getTextSize(text) {
3545
+ let size = 0;
3546
+ for (let indexCharacter = 0; indexCharacter < text.length; indexCharacter++) {
3547
+ const characterCode = text.charCodeAt(indexCharacter);
3548
+ if (characterCode < 0x80) {
3549
+ size += 1;
3550
+ } else if (characterCode < 0x800) {
3551
+ size += 2;
3552
+ } else if (characterCode < 0xd800 || characterCode >= 0xe000) {
3553
+ size += 3;
3554
+ } else if (characterCode < 0xdc00 && (text.charCodeAt(indexCharacter + 1) & 0xfc00) == 0xdc00) {
3555
+ size += 4;
3556
+ indexCharacter++;
3557
+ } else {
3558
+ size += 3;
3559
+ }
3560
+ }
3561
+ return size;
3562
+ }
3563
+
3543
3564
  class TextWriter extends BlobWriter {
3544
3565
 
3545
3566
  constructor(encoding) {
@@ -4203,6 +4224,10 @@ class GenericWriter {
4203
4224
  }
4204
4225
  }
4205
4226
 
4227
+ function ownsWritable(writer) {
4228
+ return Boolean(writer && writer.getData);
4229
+ }
4230
+
4206
4231
  function isHttpFamily(url) {
4207
4232
  const { baseURI } = getConfiguration();
4208
4233
  const { protocol } = new URL(url, baseURI);
@@ -4347,6 +4372,8 @@ const PROPERTY_NAME_CREATION_DATE = "creationDate";
4347
4372
  const PROPERTY_NAME_RAW_CREATION_DATE = "rawCreationDate";
4348
4373
  const PROPERTY_NAME_INTERNAL_FILE_ATTRIBUTES = "internalFileAttributes";
4349
4374
  const PROPERTY_NAME_EXTERNAL_FILE_ATTRIBUTES = "externalFileAttributes";
4375
+ const PROPERTY_NAME_DEPRECATED_INTERNAL_FILE_ATTRIBUTES = "internalFileAttribute";
4376
+ const PROPERTY_NAME_DEPRECATED_EXTERNAL_FILE_ATTRIBUTES = "externalFileAttribute";
4350
4377
  const PROPERTY_NAME_MSDOS_ATTRIBUTES_RAW = "msdosAttributesRaw";
4351
4378
  const PROPERTY_NAME_MSDOS_ATTRIBUTES = "msdosAttributes";
4352
4379
  const PROPERTY_NAME_MS_DOS_COMPATIBLE = "msDosCompatible";
@@ -4357,6 +4384,7 @@ const PROPERTY_NAME_VERSION_MADE_BY = "versionMadeBy";
4357
4384
  const PROPERTY_NAME_ZIPCRYPTO = "zipCrypto";
4358
4385
  const PROPERTY_NAME_DIRECTORY = "directory";
4359
4386
  const PROPERTY_NAME_EXECUTABLE = "executable";
4387
+ const PROPERTY_NAME_SYMLINK = "symlink";
4360
4388
  const PROPERTY_NAME_COMPRESSION_METHOD = "compressionMethod";
4361
4389
  const PROPERTY_NAME_SIGNATURE = "signature";
4362
4390
  const PROPERTY_NAME_CRC32 = "crc32";
@@ -4400,6 +4428,8 @@ const PROPERTY_NAMES = [
4400
4428
  PROPERTY_NAME_DISK_NUMBER_START,
4401
4429
  PROPERTY_NAME_INTERNAL_FILE_ATTRIBUTES,
4402
4430
  PROPERTY_NAME_EXTERNAL_FILE_ATTRIBUTES,
4431
+ PROPERTY_NAME_DEPRECATED_INTERNAL_FILE_ATTRIBUTES,
4432
+ PROPERTY_NAME_DEPRECATED_EXTERNAL_FILE_ATTRIBUTES,
4403
4433
  PROPERTY_NAME_MSDOS_ATTRIBUTES_RAW,
4404
4434
  PROPERTY_NAME_MSDOS_ATTRIBUTES,
4405
4435
  PROPERTY_NAME_MS_DOS_COMPATIBLE,
@@ -4410,6 +4440,7 @@ const PROPERTY_NAMES = [
4410
4440
  PROPERTY_NAME_ZIPCRYPTO,
4411
4441
  PROPERTY_NAME_DIRECTORY,
4412
4442
  PROPERTY_NAME_EXECUTABLE,
4443
+ PROPERTY_NAME_SYMLINK,
4413
4444
  PROPERTY_NAME_COMPRESSION_METHOD,
4414
4445
  PROPERTY_NAME_SIGNATURE,
4415
4446
  PROPERTY_NAME_CRC32,
@@ -4872,15 +4903,18 @@ class ZipReader {
4872
4903
  const setuid = Boolean(fileEntry.unixMode & FILE_ATTR_UNIX_SETUID_MASK);
4873
4904
  const setgid = Boolean(fileEntry.unixMode & FILE_ATTR_UNIX_SETGID_MASK);
4874
4905
  const sticky = Boolean(fileEntry.unixMode & FILE_ATTR_UNIX_STICKY_MASK);
4875
- const executable = (fileEntry.unixMode !== UNDEFINED_VALUE)
4906
+ const unixType = fileEntry.unixMode === UNDEFINED_VALUE ? unixExternalUpper : fileEntry.unixMode;
4907
+ const symlink = (unixType & FILE_ATTR_UNIX_TYPE_MASK) == FILE_ATTR_UNIX_TYPE_SYMLINK;
4908
+ const executable = !symlink && ((fileEntry.unixMode !== UNDEFINED_VALUE)
4876
4909
  ? ((fileEntry.unixMode & FILE_ATTR_UNIX_EXECUTABLE_MASK) != 0)
4877
- : (unixCompatible && ((unixExternalUpper & FILE_ATTR_UNIX_EXECUTABLE_MASK) != 0));
4910
+ : (unixCompatible && ((unixExternalUpper & FILE_ATTR_UNIX_EXECUTABLE_MASK) != 0)));
4878
4911
  const modeIsDir = fileEntry.unixMode !== UNDEFINED_VALUE && ((fileEntry.unixMode & FILE_ATTR_UNIX_TYPE_MASK) == FILE_ATTR_UNIX_TYPE_DIR);
4879
4912
  const upperIsDir = ((unixExternalUpper & FILE_ATTR_UNIX_TYPE_MASK) == FILE_ATTR_UNIX_TYPE_DIR);
4880
4913
  Object.assign(fileEntry, {
4881
4914
  setuid,
4882
4915
  setgid,
4883
4916
  sticky,
4917
+ symlink,
4884
4918
  unixExternalUpper,
4885
4919
  internalFileAttribute: fileEntry.internalFileAttributes,
4886
4920
  externalFileAttribute: fileEntry.externalFileAttributes,
@@ -4946,6 +4980,10 @@ class ZipReader {
4946
4980
  }
4947
4981
 
4948
4982
  async close() {
4983
+ const { reader } = this;
4984
+ if (!reader.readUint8Array && reader.readable && !reader.readable.locked) {
4985
+ await reader.readable.cancel();
4986
+ }
4949
4987
  }
4950
4988
  }
4951
4989
 
@@ -5170,7 +5208,7 @@ let ZipEntry$1 = class ZipEntry {
5170
5208
  throw error;
5171
5209
  }
5172
5210
  } finally {
5173
- const preventClose = getOptionValue$1(zipEntry, options, OPTION_PREVENT_CLOSE);
5211
+ const preventClose = !ownsWritable(writer) && getOptionValue$1(zipEntry, options, OPTION_PREVENT_CLOSE);
5174
5212
  if (!preventClose && writable && !writable.locked) {
5175
5213
  const writableWriter = writable.getWriter();
5176
5214
  if (abortError) {
@@ -5414,8 +5452,8 @@ function readExtraFieldUnixDates(extraField, directory) {
5414
5452
  return;
5415
5453
  }
5416
5454
  const extraFieldView = getDataView(extraField.data);
5417
- const lastAccessDate = new Date(getUint32(extraFieldView, 0) * 1000);
5418
- const lastModDate = new Date(getUint32(extraFieldView, 4) * 1000);
5455
+ const lastAccessDate = new Date((getUint32(extraFieldView, 0) | 0) * 1000);
5456
+ const lastModDate = new Date((getUint32(extraFieldView, 4) | 0) * 1000);
5419
5457
  const extraFieldData = { lastAccessDate, lastModDate };
5420
5458
  if (extraField.data.length >= 12) {
5421
5459
  extraFieldData.uid = getUint16(extraFieldView, 8);
@@ -5846,6 +5884,7 @@ const ERR_INVALID_ENTRY_NAME = "File entry name exceeds 64KB";
5846
5884
  const ERR_INVALID_VERSION = "Version exceeds 65535";
5847
5885
  const ERR_INVALID_ENCRYPTION_STRENGTH = "The strength must equal 1, 2, or 3";
5848
5886
  const ERR_UNSUPPORTED_ENCRYPTION_USDZ = "Encryption is not supported in USDZ files";
5887
+ const ERR_UNSUPPORTED_ENCRYPTION_PASS_THROUGH = "Encryption is not supported when the 'passThrough' option is set";
5849
5888
  const ERR_INVALID_EXTRAFIELD_TYPE = "Extra field type exceeds 65535";
5850
5889
  const ERR_INVALID_EXTRAFIELD_DATA = "Extra field data exceeds 64KB";
5851
5890
  const ERR_UNSUPPORTED_COMPRESSION = "Compression method not supported";
@@ -5855,6 +5894,7 @@ const MIN_NTFS_TIME = BigInt(0);
5855
5894
  const MAX_NTFS_TIME = BigInt("0x7fffffffffffffff");
5856
5895
  const ERR_UNSUPPORTED_FORMAT = "Zip64 is not supported (set the 'zip64' option to 'true')";
5857
5896
  const ERR_UNDEFINED_UNCOMPRESSED_SIZE = "Undefined uncompressed size";
5897
+ const ERR_UNDETERMINED_SIZE = "Undetermined size";
5858
5898
  const ERR_UNDEFINED_READER = "Undefined reader";
5859
5899
  const ERR_ZIP_NOT_EMPTY = "Zip file not empty";
5860
5900
  const ERR_INVALID_UID = "Invalid uid (must be integer 0..2^32-1)";
@@ -6062,7 +6102,7 @@ class ZipWriter {
6062
6102
  await Promise.allSettled(Array.from(pendingAddFileCalls));
6063
6103
  }
6064
6104
  await closeFile(zipWriter, comment, options);
6065
- const preventClose = getOptionValue(zipWriter, options, OPTION_PREVENT_CLOSE);
6105
+ const preventClose = !ownsWritable(writer) && getOptionValue(zipWriter, options, OPTION_PREVENT_CLOSE);
6066
6106
  if (!preventClose) {
6067
6107
  await writable.getWriter().close();
6068
6108
  }
@@ -6221,7 +6261,7 @@ function resolveAttributes(zipWriter, name, options) {
6221
6261
  if (versionMadeBy > MAX_16_BITS) {
6222
6262
  throw new Error(ERR_INVALID_VERSION);
6223
6263
  }
6224
- let externalFileAttributes = getOptionValue(zipWriter, options, PROPERTY_NAME_EXTERNAL_FILE_ATTRIBUTES);
6264
+ let externalFileAttributes = getAliasedOptionValue(zipWriter, options, PROPERTY_NAME_EXTERNAL_FILE_ATTRIBUTES, PROPERTY_NAME_DEPRECATED_EXTERNAL_FILE_ATTRIBUTES);
6225
6265
  const externalFileAttributesProvided = externalFileAttributes !== UNDEFINED_VALUE;
6226
6266
  if (!externalFileAttributesProvided) {
6227
6267
  externalFileAttributes = 0;
@@ -6269,7 +6309,9 @@ function resolveAttributes(zipWriter, name, options) {
6269
6309
  }
6270
6310
  if (!externalFileAttributesProvided || unixModeProvided) {
6271
6311
  if (directory) {
6272
- unixMode |= FILE_ATTR_UNIX_TYPE_DIR;
6312
+ unixMode = (unixMode & ~FILE_ATTR_UNIX_TYPE_MASK) | FILE_ATTR_UNIX_TYPE_DIR;
6313
+ } else if (!(unixMode & FILE_ATTR_UNIX_TYPE_MASK)) {
6314
+ unixMode |= FILE_ATTR_UNIX_TYPE_FILE;
6273
6315
  }
6274
6316
  externalFileAttributes = ((unixMode & MAX_16_BITS) << 16) | (externalFileAttributes & MAX_16_BITS);
6275
6317
  }
@@ -6322,15 +6364,12 @@ function resolveMetadata(zipWriter, name, options) {
6322
6364
  const lastModDate = getOptionValue(zipWriter, options, PROPERTY_NAME_LAST_MODIFICATION_DATE, new Date());
6323
6365
  const lastAccessDate = getOptionValue(zipWriter, options, PROPERTY_NAME_LAST_ACCESS_DATE);
6324
6366
  const creationDate = getOptionValue(zipWriter, options, PROPERTY_NAME_CREATION_DATE);
6325
- const internalFileAttributes = getOptionValue(zipWriter, options, PROPERTY_NAME_INTERNAL_FILE_ATTRIBUTES, 0);
6367
+ const internalFileAttributes = getAliasedOptionValue(zipWriter, options, PROPERTY_NAME_INTERNAL_FILE_ATTRIBUTES, PROPERTY_NAME_DEPRECATED_INTERNAL_FILE_ATTRIBUTES, 0);
6326
6368
  const passThrough = getOptionValue(zipWriter, options, OPTION_PASS_THROUGH);
6327
- let password, rawPassword;
6328
- if (!passThrough) {
6329
- password = getOptionValue(zipWriter, options, OPTION_PASSWORD);
6330
- rawPassword = getOptionValue(zipWriter, options, OPTION_RAW_PASSWORD);
6331
- if ((password && typeof password != STRING_TYPE) || (rawPassword && !(rawPassword instanceof Uint8Array))) {
6332
- throw new Error(ERR_INVALID_PASSWORD_TYPE);
6333
- }
6369
+ const password = getOptionValue(zipWriter, options, OPTION_PASSWORD);
6370
+ const rawPassword = getOptionValue(zipWriter, options, OPTION_RAW_PASSWORD);
6371
+ if ((password && typeof password != STRING_TYPE) || (rawPassword && !(rawPassword instanceof Uint8Array))) {
6372
+ throw new Error(ERR_INVALID_PASSWORD_TYPE);
6334
6373
  }
6335
6374
  const encryptionStrength = getNumberOptionValue(zipWriter, options, OPTION_ENCRYPTION_STRENGTH, 3);
6336
6375
  const zipCrypto = getOptionValue(zipWriter, options, PROPERTY_NAME_ZIPCRYPTO);
@@ -6443,14 +6482,24 @@ function serializeExtraField(extraField) {
6443
6482
  }
6444
6483
 
6445
6484
  async function resolveSizes(zipWriter, reader, { resolvedOptions: metadata }, options) {
6485
+ if (metadata.passThrough && !reader && !getOptionValue(zipWriter, options, PROPERTY_NAME_DIRECTORY)) {
6486
+ throw new Error(ERR_UNDEFINED_READER);
6487
+ }
6488
+ let contentSize;
6489
+ if (reader) {
6490
+ reader = new GenericReader(reader);
6491
+ await initStream(reader);
6492
+ ({ size: contentSize } = reader);
6493
+ }
6494
+ return Object.assign({ reader }, resolveEntrySizes(zipWriter, Boolean(reader), contentSize, metadata, options));
6495
+ }
6496
+
6497
+ function resolveEntrySizes(zipWriter, hasContent, contentSize, metadata, options) {
6446
6498
  const { passThrough, zipCrypto, password, rawPassword, encryptionStrength } = metadata;
6447
6499
  let { dataDescriptor, zip64, level, compressionMethod } = metadata;
6448
6500
  let maximumCompressedSize = 0;
6449
6501
  let uncompressedSize = 0;
6450
- if (passThrough) {
6451
- if (!reader) {
6452
- throw new Error(ERR_UNDEFINED_READER);
6453
- }
6502
+ if (passThrough && hasContent) {
6454
6503
  uncompressedSize = options[PROPERTY_NAME_UNCOMPRESSED_SIZE];
6455
6504
  if (uncompressedSize === UNDEFINED_VALUE) {
6456
6505
  throw new Error(ERR_UNDEFINED_UNCOMPRESSED_SIZE);
@@ -6458,29 +6507,30 @@ async function resolveSizes(zipWriter, reader, { resolvedOptions: metadata }, op
6458
6507
  }
6459
6508
  const zip64Enabled = zip64 === true;
6460
6509
  const encrypted = getOptionValue(zipWriter, options, PROPERTY_NAME_ENCRYPTED);
6461
- const encryptedEntry = Boolean(reader) && (Boolean((password && getLength(password)) || (rawPassword && getLength(rawPassword))) || (passThrough && encrypted));
6462
- if (!reader) {
6510
+ if (hasContent && passThrough && !encrypted && getLength(password, rawPassword)) {
6511
+ throw new Error(ERR_UNSUPPORTED_ENCRYPTION_PASS_THROUGH);
6512
+ }
6513
+ const encryptedEntry = hasContent && (Boolean((password && getLength(password)) || (rawPassword && getLength(rawPassword))) || (passThrough && encrypted));
6514
+ if (!hasContent) {
6463
6515
  level = 0;
6464
6516
  compressionMethod = COMPRESSION_METHOD_STORE;
6465
6517
  }
6466
6518
  const encryptionOverhead = encryptedEntry ? (zipCrypto ? 12 : 16 + encryptionStrength * 4) : 0;
6467
- if (reader) {
6468
- reader = new GenericReader(reader);
6469
- await initStream(reader);
6519
+ if (hasContent) {
6470
6520
  if (!passThrough) {
6471
- if (reader.size === UNDEFINED_VALUE) {
6521
+ if (contentSize === UNDEFINED_VALUE) {
6472
6522
  dataDescriptor = true;
6473
6523
  if (zip64 || zip64 === UNDEFINED_VALUE) {
6474
6524
  zip64 = true;
6475
6525
  uncompressedSize = maximumCompressedSize = MAX_32_BITS + 1;
6476
6526
  }
6477
6527
  } else {
6478
- options.uncompressedSize = uncompressedSize = reader.size;
6479
- maximumCompressedSize = getMaximumCompressedSize(uncompressedSize) + encryptionOverhead;
6528
+ options.uncompressedSize = uncompressedSize = contentSize;
6529
+ maximumCompressedSize = (isCompressed(compressionMethod, level) ? getMaximumCompressedSize(uncompressedSize) : uncompressedSize) + encryptionOverhead;
6480
6530
  }
6481
6531
  } else {
6482
6532
  options.uncompressedSize = uncompressedSize;
6483
- maximumCompressedSize = getMaximumCompressedSize(uncompressedSize) + encryptionOverhead;
6533
+ maximumCompressedSize = contentSize === UNDEFINED_VALUE ? getMaximumCompressedSize(uncompressedSize) + encryptionOverhead : contentSize;
6484
6534
  }
6485
6535
  }
6486
6536
  const zip64UncompressedSize = zip64Enabled || uncompressedSize >= MAX_32_BITS;
@@ -6494,7 +6544,7 @@ async function resolveSizes(zipWriter, reader, { resolvedOptions: metadata }, op
6494
6544
  }
6495
6545
  zip64 = zip64 || false;
6496
6546
  return {
6497
- reader,
6547
+ maximumCompressedSize,
6498
6548
  resolvedOptions: {
6499
6549
  dataDescriptor,
6500
6550
  zip64,
@@ -6508,6 +6558,78 @@ async function resolveSizes(zipWriter, reader, { resolvedOptions: metadata }, op
6508
6558
  };
6509
6559
  }
6510
6560
 
6561
+ async function getEntriesSize(writerOptions, entries, writeOrderGuaranteed, comment) {
6562
+ const zipWriter = { options: writerOptions, config: getConfiguration() };
6563
+ if (writerOptions[OPTION_SIGN_CENTRAL_DIRECTORY]) {
6564
+ throw new Error(ERR_UNDETERMINED_SIZE);
6565
+ }
6566
+ const commentLength = getLength(comment);
6567
+ if (commentLength > MAX_16_BITS) {
6568
+ throw new Error(ERR_INVALID_COMMENT);
6569
+ }
6570
+ const usdz = writerOptions[OPTION_USDZ];
6571
+ const files = new Map();
6572
+ let layoutDependsOnWriteOrder = Boolean(usdz);
6573
+ let offset = 0;
6574
+ for (const entry of entries) {
6575
+ let { name } = entry;
6576
+ const { size } = entry;
6577
+ const options = Object.assign({}, entry.options);
6578
+ name = name.trim();
6579
+ if (getOptionValue(zipWriter, options, PROPERTY_NAME_DIRECTORY) && !name.endsWith(DIRECTORY_SIGNATURE)) {
6580
+ name += DIRECTORY_SIGNATURE;
6581
+ }
6582
+ const attributesInfo = resolveAttributes(zipWriter, name, options);
6583
+ ({ name } = attributesInfo);
6584
+ const { resolvedOptions: metadata } = resolveMetadata(zipWriter, name, options);
6585
+ if (metadata.level != 0 && metadata.compressionMethod === UNDEFINED_VALUE &&
6586
+ !metadata.passThrough && !(await supportsDeflate(zipWriter.config))) {
6587
+ metadata.level = 0;
6588
+ }
6589
+ const hasContent = !getOptionValue(zipWriter, options, PROPERTY_NAME_DIRECTORY);
6590
+ if (hasContent && size === UNDEFINED_VALUE) {
6591
+ throw new Error(ERR_UNDETERMINED_SIZE);
6592
+ }
6593
+ const { maximumCompressedSize, resolvedOptions: sizes } = resolveEntrySizes(zipWriter, hasContent, size, metadata, options);
6594
+ if (hasContent && !metadata.passThrough && isCompressed(sizes.compressionMethod, sizes.level)) {
6595
+ throw new Error(ERR_UNDETERMINED_SIZE);
6596
+ }
6597
+ const entryOptions = Object.assign({}, options, attributesInfo.resolvedOptions, metadata, sizes);
6598
+ const headerInfo = getHeaderInfo(entryOptions);
6599
+ const dataDescriptorInfo = getDataDescriptorInfo(entryOptions);
6600
+ const entryInfo = {
6601
+ headerInfo,
6602
+ metadataSize: getLength(headerInfo.localHeaderArray, dataDescriptorInfo.dataDescriptorArray)
6603
+ };
6604
+ if (usdz) {
6605
+ appendExtraFieldUSDZ(entryInfo, offset);
6606
+ }
6607
+ const compressedSize = hasContent ? maximumCompressedSize : 0;
6608
+ if (offset >= MAX_32_BITS) {
6609
+ layoutDependsOnWriteOrder = true;
6610
+ }
6611
+ files.set(name, Object.assign({}, entryOptions, headerInfo, {
6612
+ offset,
6613
+ diskNumberStart: 0,
6614
+ compressedSize
6615
+ }));
6616
+ offset += entryInfo.metadataSize + compressedSize;
6617
+ }
6618
+ if (layoutDependsOnWriteOrder && !writeOrderGuaranteed) {
6619
+ throw new Error(ERR_UNDETERMINED_SIZE);
6620
+ }
6621
+ const directoryDataLength = createDirectoryRecords(files);
6622
+ let zip64 = getOptionValue(zipWriter, writerOptions, PROPERTY_NAME_ZIP64);
6623
+ if (offset >= MAX_32_BITS || directoryDataLength >= MAX_32_BITS || files.size >= MAX_16_BITS) {
6624
+ if (zip64 === false) {
6625
+ throw new Error(ERR_UNSUPPORTED_FORMAT);
6626
+ } else {
6627
+ zip64 = true;
6628
+ }
6629
+ }
6630
+ return offset + directoryDataLength + commentLength + (zip64 ? ZIP64_END_OF_CENTRAL_DIR_TOTAL_LENGTH : END_OF_CENTRAL_DIR_LENGTH);
6631
+ }
6632
+
6511
6633
  async function getFileEntry(zipWriter, name, reader, entryInfo, options) {
6512
6634
  const {
6513
6635
  files,
@@ -6879,9 +7001,7 @@ function getHeaderInfo(options) {
6879
7001
  crc32
6880
7002
  } = options;
6881
7003
  let { version, compressionMethod } = options;
6882
- const compressed = !directory && (compressionMethod === UNDEFINED_VALUE
6883
- ? (level === UNDEFINED_VALUE || level > 0)
6884
- : compressionMethod !== COMPRESSION_METHOD_STORE);
7004
+ const compressed = !directory && isCompressed(compressionMethod, level);
6885
7005
  let rawLocalExtraFieldZip64;
6886
7006
  const uncompressedFile = passThrough || !compressed;
6887
7007
  const zip64ExtraFieldComplete = zip64 && (options.bufferedWrite || !dataDescriptor || ((!zip64UncompressedSize && !zip64CompressedSize) || uncompressedFile));
@@ -7568,6 +7688,16 @@ function getOptionValue(zipWriter, options, name, defaultValue) {
7568
7688
  return result === UNDEFINED_VALUE ? defaultValue : result;
7569
7689
  }
7570
7690
 
7691
+ function getAliasedOptionValue(zipWriter, options, name, deprecatedName, defaultValue) {
7692
+ const value = getAliasedValue(options, name, deprecatedName);
7693
+ const result = value === UNDEFINED_VALUE ? getAliasedValue(zipWriter.options, name, deprecatedName) : value;
7694
+ return result === UNDEFINED_VALUE ? defaultValue : result;
7695
+ }
7696
+
7697
+ function getAliasedValue(options, name, deprecatedName) {
7698
+ return options[name] === UNDEFINED_VALUE ? options[deprecatedName] : options[name];
7699
+ }
7700
+
7571
7701
  function getNumberOptionValue(zipWriter, options, name, defaultValue) {
7572
7702
  return toNumber(getOptionValue(zipWriter, options, name, defaultValue));
7573
7703
  }
@@ -7580,6 +7710,12 @@ function getMaximumCompressedSize(uncompressedSize) {
7580
7710
  return uncompressedSize + (5 * (Math.floor(uncompressedSize / 16383) + 1));
7581
7711
  }
7582
7712
 
7713
+ function isCompressed(compressionMethod, level) {
7714
+ return compressionMethod === UNDEFINED_VALUE
7715
+ ? (level === UNDEFINED_VALUE || level > 0)
7716
+ : compressionMethod !== COMPRESSION_METHOD_STORE;
7717
+ }
7718
+
7583
7719
  function setUint8(view, offset, value) {
7584
7720
  view.setUint8(offset, value);
7585
7721
  }
@@ -8228,7 +8364,10 @@ setDefaultConfiguration({
8228
8364
 
8229
8365
  const ERR_ENTRY_EXISTS = "Entry filename already exists";
8230
8366
  const ERR_READABLE_CONSUMED = "Readable stream already consumed";
8367
+ const ERR_INVALID_PASS_THROUGH = "Invalid passThrough option (use readerOptions.passThrough or set uncompressedSize for each entry)";
8231
8368
  const ERR_ABORT_EXPORT = "zipjs-abort-export";
8369
+ const ERR_ABORTED = "The operation was aborted";
8370
+ const ABORT_ERROR_NAME = "AbortError";
8232
8371
  const INFOZIP_EXTRA_FIELD_TYPE = "infozip";
8233
8372
  const INTERPRETED_EXTRA_FIELD_TYPES = new Set([
8234
8373
  EXTRAFIELD_TYPE_ZIP64,
@@ -8263,6 +8402,7 @@ class ZipEntry {
8263
8402
  parent,
8264
8403
  children: [],
8265
8404
  uncompressedSize: params.uncompressedSize || 0,
8405
+ undeterminedSize: params.undeterminedSize || params.uncompressedSize === UNDEFINED_VALUE,
8266
8406
  passThrough: params.passThrough
8267
8407
  });
8268
8408
  if (parent || !fs.root) {
@@ -8330,16 +8470,17 @@ class ZipFileEntry extends ZipEntry {
8330
8470
 
8331
8471
  async getData(writer, options = {}) {
8332
8472
  const zipEntry = this;
8333
- if (!writer || (writer.constructor == zipEntry.Writer && zipEntry.data)) {
8473
+ if (!writer || (writer.constructor == zipEntry.Writer && zipEntry.data && keepsContentType(writer, zipEntry.data))) {
8334
8474
  return zipEntry.data;
8335
8475
  } else {
8336
8476
  const reader = zipEntry.reader = createReader(zipEntry.Reader, zipEntry.data, options);
8337
- const uncompressedSize = zipEntry.data ? zipEntry.data.uncompressedSize : reader.size;
8338
- await Promise.all([initStream(reader), initStream(writer, uncompressedSize)]);
8339
- const { readable } = reader;
8477
+ const dataSize = zipEntry.uncompressedSize || reader.size;
8478
+ await Promise.all([initStream(reader), initStream(writer, dataSize)]);
8340
8479
  const { signal } = options;
8480
+ const readable = createProgressReadable(zipEntry, reader, options, signal);
8481
+ const preventClose = !ownsWritable(writer) && Boolean(options.preventClose);
8341
8482
  zipEntry.uncompressedSize = reader.size;
8342
- await toCompatibleReadable(readable).pipeTo(toCompatibleWritable(writer.writable), { signal });
8483
+ await toCompatibleReadable(readable).pipeTo(toCompatibleWritable(writer.writable), { signal, preventClose, preventAbort: preventClose });
8343
8484
  return writer.getData ? writer.getData() : writer.writable;
8344
8485
  }
8345
8486
  }
@@ -8470,7 +8611,7 @@ class ZipDirectoryEntry extends ZipEntry {
8470
8611
  Reader: TextReader,
8471
8612
  Writer: TextWriter,
8472
8613
  options,
8473
- uncompressedSize: text.length
8614
+ uncompressedSize: getTextSize(text)
8474
8615
  });
8475
8616
  }
8476
8617
 
@@ -8599,10 +8740,16 @@ class ZipDirectoryEntry extends ZipEntry {
8599
8740
  }
8600
8741
 
8601
8742
  async importZip(reader, options = {}) {
8602
- await initStream(reader);
8603
- const zipReader = new ZipReader(reader, options);
8743
+ let zipReader;
8744
+ if (reader && typeof reader.getEntries == FUNCTION_TYPE) {
8745
+ zipReader = reader;
8746
+ options = Object.assign({}, zipReader.options, options);
8747
+ } else {
8748
+ await initStream(reader);
8749
+ zipReader = new ZipReader(reader, options);
8750
+ }
8604
8751
  const importedEntries = [];
8605
- const entries = await zipReader.getEntries();
8752
+ const entries = await zipReader.getEntries(options);
8606
8753
  for (const entry of entries) {
8607
8754
  let parent = this;
8608
8755
  try {
@@ -8624,7 +8771,7 @@ class ZipDirectoryEntry extends ZipEntry {
8624
8771
  importedEntries.push(addChild(parent, name, {
8625
8772
  data: entry,
8626
8773
  Reader: getZipBlobReader(Object.assign({}, options)),
8627
- uncompressedSize: entry.uncompressedSize,
8774
+ uncompressedSize: options.passThrough ? entry.compressedSize : entry.uncompressedSize,
8628
8775
  passThrough: options.passThrough
8629
8776
  }));
8630
8777
  } else {
@@ -8666,11 +8813,25 @@ class ZipDirectoryEntry extends ZipEntry {
8666
8813
  }
8667
8814
  const [readers] = await Promise.all([initReaders(zipEntry, options.readerOptions), initStream(writer)]);
8668
8815
  const zipWriter = new ZipWriter(writer, options);
8669
- await exportZip(zipWriter, zipEntry, getTotalSize([zipEntry], "uncompressedSize"), options, readers);
8670
- await zipWriter.close();
8816
+ await exportZip(zipWriter, zipEntry, getTotalSize([zipEntry], getUncompressedSize), options, readers);
8817
+ await zipWriter.close(options.globalComment);
8671
8818
  return writer.getData ? writer.getData() : writer.writable;
8672
8819
  }
8673
8820
 
8821
+ getExportedSize(options = {}) {
8822
+ const zipEntry = this;
8823
+ options = Object.assign({}, options);
8824
+ if (options.bufferedWrite === UNDEFINED_VALUE) {
8825
+ options.bufferedWrite = true;
8826
+ }
8827
+ const writeOrderGuaranteed = !options.bufferedWrite ||
8828
+ (options.keepOrder !== false && zipEntry.children.every(child => !child.children.length));
8829
+ return getEntriesSize(options, Array.from(zipEntry.getChildren({ recursive: true }), child => {
8830
+ const { name, entryOptions } = getChildEntryOptions(child, zipEntry, options);
8831
+ return { name, size: child.directory ? 0 : getDeterminedSize(child, isPassThrough(child, options)), options: entryOptions };
8832
+ }), writeOrderGuaranteed, options.globalComment);
8833
+ }
8834
+
8674
8835
  getChildByName(name) {
8675
8836
  const children = this.children;
8676
8837
  for (let childIndex = 0; childIndex < children.length; childIndex++) {
@@ -8681,6 +8842,10 @@ class ZipDirectoryEntry extends ZipEntry {
8681
8842
  }
8682
8843
  }
8683
8844
 
8845
+ getChildren(options = {}) {
8846
+ return collectChildren(this, options.recursive);
8847
+ }
8848
+
8684
8849
  isPasswordProtected() {
8685
8850
  const children = this.children;
8686
8851
  for (let childIndex = 0; childIndex < children.length; childIndex++) {
@@ -8772,6 +8937,10 @@ class FS {
8772
8937
  return this.root.getChildByName(name);
8773
8938
  }
8774
8939
 
8940
+ getChildren(options) {
8941
+ return this.root.getChildren(options);
8942
+ }
8943
+
8775
8944
  addDirectory(name, options) {
8776
8945
  return this.root.addDirectory(name, options);
8777
8946
  }
@@ -8870,6 +9039,10 @@ class FS {
8870
9039
  return this.root.exportZip(writer, options);
8871
9040
  }
8872
9041
 
9042
+ getExportedSize(options) {
9043
+ return this.root.getExportedSize(options);
9044
+ }
9045
+
8873
9046
  isPasswordProtected() {
8874
9047
  return this.root.isPasswordProtected();
8875
9048
  }
@@ -8881,12 +9054,12 @@ class FS {
8881
9054
 
8882
9055
  const fs = { FS, ZipDirectoryEntry, ZipFileEntry };
8883
9056
 
8884
- function getTotalSize(entries, propertyName) {
9057
+ function getTotalSize(entries, getEntrySize) {
8885
9058
  let size = 0;
8886
9059
  const pendingEntries = Array.from(entries);
8887
9060
  while (pendingEntries.length) {
8888
9061
  const entry = pendingEntries.pop();
8889
- size += entry[propertyName] || 0;
9062
+ size += getEntrySize(entry) || 0;
8890
9063
  for (const child of entry.children) {
8891
9064
  pendingEntries.push(child);
8892
9065
  }
@@ -8894,6 +9067,15 @@ function getTotalSize(entries, propertyName) {
8894
9067
  return size;
8895
9068
  }
8896
9069
 
9070
+ function getUncompressedSize(entry) {
9071
+ return entry.uncompressedSize;
9072
+ }
9073
+
9074
+ function getExtractedSize(entry, passThrough) {
9075
+ const { data } = entry;
9076
+ return passThrough && data instanceof Entry ? data.compressedSize : entry.uncompressedSize;
9077
+ }
9078
+
8897
9079
  function getReadableReader(readable) {
8898
9080
  let consumed;
8899
9081
  return function () {
@@ -8916,10 +9098,17 @@ function getZipBlobReader(options) {
8916
9098
 
8917
9099
  async init() {
8918
9100
  const zipBlobReader = this;
8919
- zipBlobReader.size = zipBlobReader.entry.uncompressedSize;
8920
- const data = await zipBlobReader.entry.getData(new BlobWriter(), Object.assign({}, options, zipBlobReader.options));
9101
+ const readerOptions = Object.assign({}, options, zipBlobReader.options);
9102
+ const { checkOverlappingEntry, checkOverlappingEntryOnly } = readerOptions;
9103
+ const data = await zipBlobReader.entry.getData(new BlobWriter(), Object.assign(readerOptions, {
9104
+ checkPasswordOnly: false,
9105
+ checkOverlappingEntry: checkOverlappingEntryOnly || checkOverlappingEntry,
9106
+ checkOverlappingEntryOnly: false,
9107
+ preventClose: false
9108
+ }));
8921
9109
  zipBlobReader.data = data;
8922
9110
  zipBlobReader.blobReader = new BlobReader(data);
9111
+ zipBlobReader.size = data.size;
8923
9112
  super.init();
8924
9113
  }
8925
9114
 
@@ -8933,6 +9122,30 @@ function createReader(Reader, data, options) {
8933
9122
  return Reader.prototype ? new Reader(data, options) : Reader(data, options);
8934
9123
  }
8935
9124
 
9125
+ function keepsContentType(writer, data) {
9126
+ const { contentType } = writer;
9127
+ if (contentType === UNDEFINED_VALUE) {
9128
+ return true;
9129
+ } else if (writer.constructor == BlobWriter) {
9130
+ return data.type == contentType;
9131
+ } else if (writer.constructor == Data64URIWriter) {
9132
+ return data.startsWith(writer.data);
9133
+ } else {
9134
+ return true;
9135
+ }
9136
+ }
9137
+
9138
+ function createProgressReadable(zipEntry, reader, options, signal) {
9139
+ const { onstart, onprogress, onend } = options;
9140
+ const { readable } = reader;
9141
+ const coreReaderReportsProgress = zipEntry.data instanceof Entry;
9142
+ if (coreReaderReportsProgress || (!onstart && !onprogress && !onend)) {
9143
+ return readable;
9144
+ } else {
9145
+ return toCompatibleReadable(readable).pipeThrough(new ProgressWatcherStream({ onstart, onprogress, onend, size: reader.size }), { signal });
9146
+ }
9147
+ }
9148
+
8936
9149
  async function initReaders(entry, options) {
8937
9150
  const fileEntries = [];
8938
9151
  const pendingEntries = [entry];
@@ -8965,6 +9178,7 @@ async function initReaders(entry, options) {
8965
9178
  }
8966
9179
  if (reader.size !== UNDEFINED_VALUE) {
8967
9180
  child.uncompressedSize = reader.size;
9181
+ child.undeterminedSize = false;
8968
9182
  }
8969
9183
  }));
8970
9184
  return readers;
@@ -9014,6 +9228,90 @@ function aggregateEntryErrors(errors) {
9014
9228
  return error;
9015
9229
  }
9016
9230
 
9231
+ function getChildEntryOptions(child, selectedEntry, options) {
9232
+ const name = options.relativePath ? child.getRelativeName(selectedEntry) : child.getFullname();
9233
+ const childOptions = child.options || {};
9234
+ let zipEntryMetadata = {};
9235
+ let passThroughOptions = {};
9236
+ if (child.data instanceof Entry) {
9237
+ const {
9238
+ externalFileAttributes,
9239
+ versionMadeBy,
9240
+ comment,
9241
+ lastModDate,
9242
+ creationDate,
9243
+ lastAccessDate,
9244
+ uncompressedSize,
9245
+ encrypted,
9246
+ zipCrypto,
9247
+ crc32,
9248
+ compressionMethod,
9249
+ extraFieldAES,
9250
+ internalFileAttributes,
9251
+ extraField,
9252
+ uid,
9253
+ gid
9254
+ } = child.data;
9255
+ zipEntryMetadata = {
9256
+ externalFileAttributes,
9257
+ versionMadeBy,
9258
+ comment,
9259
+ lastModDate,
9260
+ creationDate,
9261
+ lastAccessDate,
9262
+ internalFileAttributes
9263
+ };
9264
+ const userExtraField = getUserExtraField(extraField);
9265
+ if (userExtraField) {
9266
+ zipEntryMetadata.extraField = userExtraField;
9267
+ }
9268
+ if (uid !== UNDEFINED_VALUE || gid !== UNDEFINED_VALUE) {
9269
+ Object.assign(zipEntryMetadata, {
9270
+ uid,
9271
+ gid,
9272
+ unixExtraFieldType: INFOZIP_EXTRA_FIELD_TYPE
9273
+ });
9274
+ }
9275
+ if (isPassThrough(child, options)) {
9276
+ let level, encryptionStrength;
9277
+ if (compressionMethod === 0) {
9278
+ level = 0;
9279
+ }
9280
+ if (extraFieldAES) {
9281
+ encryptionStrength = extraFieldAES.strength;
9282
+ }
9283
+ passThroughOptions = {
9284
+ passThrough: true,
9285
+ encrypted,
9286
+ zipCrypto,
9287
+ crc32,
9288
+ uncompressedSize,
9289
+ level,
9290
+ encryptionStrength,
9291
+ compressionMethod
9292
+ };
9293
+ }
9294
+ }
9295
+ const entryOptions = Object.assign({}, zipEntryMetadata, options, passThroughOptions, childOptions, { directory: child.directory });
9296
+ if (!child.directory && entryOptions.passThrough && entryOptions.uncompressedSize === UNDEFINED_VALUE) {
9297
+ throw new Error(ERR_INVALID_PASS_THROUGH);
9298
+ }
9299
+ return { name, entryOptions };
9300
+ }
9301
+
9302
+ function getDeterminedSize(child, passThrough) {
9303
+ const { reader } = child;
9304
+ if (reader && reader.size !== UNDEFINED_VALUE) {
9305
+ return reader.size;
9306
+ }
9307
+ return child.undeterminedSize ? UNDEFINED_VALUE : getExtractedSize(child, passThrough);
9308
+ }
9309
+
9310
+ function isPassThrough(child, options) {
9311
+ const { readerOptions } = options;
9312
+ return Boolean(!child.directory && (child.passThrough || (readerOptions && readerOptions.passThrough)));
9313
+ }
9314
+
9017
9315
  function getUserExtraField(extraField) {
9018
9316
  if (extraField) {
9019
9317
  const userExtraField = new Map();
@@ -9029,104 +9327,53 @@ function getUserExtraField(extraField) {
9029
9327
  }
9030
9328
 
9031
9329
  async function exportZip(zipWriter, entry, totalSize, options, readers) {
9330
+ const { onstart, onprogress, onend, onentryprogress } = options;
9032
9331
  const selectedEntry = entry;
9033
- const entryOffsets = new Map();
9034
- await process(zipWriter, entry);
9035
-
9036
- async function process(zipWriter, entry) {
9037
- await exportChild();
9038
-
9039
- async function exportChild() {
9040
- if (options.bufferedWrite) {
9041
- const results = await Promise.allSettled(entry.children.map(processChild));
9042
- const errorResult = results.find(result => result.status == "rejected");
9043
- if (errorResult) {
9044
- throw errorResult.reason;
9045
- }
9046
- } else {
9047
- for (const child of entry.children) {
9048
- await processChild(child);
9049
- }
9050
- }
9332
+ const totalEntries = getTotalSize(entry.children, () => 1);
9333
+ let writtenSize = 0;
9334
+ let writtenEntries = 0;
9335
+ if (onstart) {
9336
+ await callHandler(onstart, totalSize);
9337
+ }
9338
+ if (options.bufferedWrite) {
9339
+ await processChildren(entry);
9340
+ } else {
9341
+ for (const child of entry.getChildren({ recursive: true })) {
9342
+ await addChild(child);
9051
9343
  }
9344
+ }
9345
+ if (onend) {
9346
+ await callHandler(onend, writtenSize);
9347
+ }
9052
9348
 
9053
- async function processChild(child) {
9054
- const name = options.relativePath ? child.getRelativeName(selectedEntry) : child.getFullname();
9055
- const childOptions = child.options || {};
9056
- let zipEntryOptions = {};
9057
- if (child.data instanceof Entry) {
9058
- const {
9059
- externalFileAttributes,
9060
- versionMadeBy,
9061
- comment,
9062
- lastModDate,
9063
- creationDate,
9064
- lastAccessDate,
9065
- uncompressedSize,
9066
- encrypted,
9067
- zipCrypto,
9068
- crc32,
9069
- compressionMethod,
9070
- extraFieldAES,
9071
- internalFileAttributes,
9072
- extraField,
9073
- uid,
9074
- gid
9075
- } = child.data;
9076
- zipEntryOptions = {
9077
- externalFileAttributes,
9078
- versionMadeBy,
9079
- comment,
9080
- lastModDate,
9081
- creationDate,
9082
- lastAccessDate,
9083
- internalFileAttributes
9084
- };
9085
- const userExtraField = getUserExtraField(extraField);
9086
- if (userExtraField) {
9087
- zipEntryOptions.extraField = userExtraField;
9088
- }
9089
- if (uid !== UNDEFINED_VALUE || gid !== UNDEFINED_VALUE) {
9090
- Object.assign(zipEntryOptions, {
9091
- uid,
9092
- gid,
9093
- unixExtraFieldType: options.unixExtraFieldType || INFOZIP_EXTRA_FIELD_TYPE
9094
- });
9095
- }
9096
- if (child.passThrough) {
9097
- let level, encryptionStrength;
9098
- if (compressionMethod === 0) {
9099
- level = 0;
9100
- }
9101
- if (extraFieldAES) {
9102
- encryptionStrength = extraFieldAES.strength;
9103
- }
9104
- zipEntryOptions = Object.assign(zipEntryOptions, {
9105
- passThrough: true,
9106
- encrypted,
9107
- zipCrypto,
9108
- crc32,
9109
- uncompressedSize,
9110
- level,
9111
- encryptionStrength,
9112
- compressionMethod
9113
- });
9349
+ async function processChildren(entry) {
9350
+ const results = await Promise.allSettled(entry.children.map(async child => {
9351
+ await addChild(child);
9352
+ await processChildren(child);
9353
+ }));
9354
+ const errorResult = results.find(result => result.status == "rejected");
9355
+ if (errorResult) {
9356
+ throw errorResult.reason;
9357
+ }
9358
+ }
9359
+
9360
+ async function addChild(child) {
9361
+ const { name, entryOptions } = getChildEntryOptions(child, selectedEntry, options);
9362
+ let entryWrittenSize = 0;
9363
+ const entryMetadata = await zipWriter.add(name, readers.get(child), Object.assign(entryOptions, {
9364
+ onstart: UNDEFINED_VALUE,
9365
+ onend: UNDEFINED_VALUE,
9366
+ onprogress: async indexProgress => {
9367
+ writtenSize += indexProgress - entryWrittenSize;
9368
+ entryWrittenSize = indexProgress;
9369
+ if (onprogress) {
9370
+ await callHandler(onprogress, writtenSize, totalSize);
9114
9371
  }
9115
9372
  }
9116
- await zipWriter.add(name, readers.get(child), Object.assign({}, options, zipEntryOptions, childOptions, {
9117
- directory: child.directory,
9118
- onprogress: async indexProgress => {
9119
- if (options.onprogress) {
9120
- entryOffsets.set(name, indexProgress);
9121
- try {
9122
- await options.onprogress(Array.from(entryOffsets.values()).reduce((previousValue, currentValue) => previousValue + currentValue), totalSize);
9123
- } catch {
9124
- // ignored
9125
- }
9126
- }
9127
- }
9128
- }));
9129
- await process(zipWriter, child);
9373
+ }));
9374
+ writtenEntries++;
9375
+ if (onentryprogress) {
9376
+ await callHandler(onentryprogress, writtenEntries, totalEntries, entryMetadata);
9130
9377
  }
9131
9378
  }
9132
9379
  }
@@ -9155,7 +9402,7 @@ function addFileSystemHandle(zipEntry, handle, options) {
9155
9402
  })
9156
9403
  );
9157
9404
  } else if (handle.kind == "directory") {
9158
- const directoryEntry = parentEntry.addDirectory(handle.name);
9405
+ const directoryEntry = parentEntry.addDirectory(handle.name, options);
9159
9406
  addedEntries.push(directoryEntry);
9160
9407
  for await (const childHandle of handle.values()) {
9161
9408
  await addFile(directoryEntry, childHandle, addedEntries, entryName);
@@ -9177,14 +9424,29 @@ function addFileSystemHandle(zipEntry, handle, options) {
9177
9424
  }
9178
9425
 
9179
9426
  async function exportFileSystemHandle(zipEntry, directoryHandle, options) {
9180
- const totalSize = getTotalSize([zipEntry], "uncompressedSize");
9181
- const writtenSizes = new Map();
9427
+ const { onstart, onprogress, onend } = options;
9182
9428
  const abortController = new AbortController();
9183
9429
  const { signal } = abortController;
9184
9430
  const releaseSignal = forwardAbort(options.signal, abortController);
9431
+ const getDataOptions = Object.assign({}, options, options.readerOptions, {
9432
+ signal,
9433
+ onstart: UNDEFINED_VALUE,
9434
+ onprogress: UNDEFINED_VALUE,
9435
+ onend: UNDEFINED_VALUE,
9436
+ preventClose: false
9437
+ });
9438
+ const totalSize = getTotalSize([zipEntry], entry => getExtractedSize(entry, getDataOptions.passThrough));
9185
9439
  const exportedEntryNames = [];
9440
+ let exportAborted = false;
9441
+ let writtenSize = 0;
9186
9442
  try {
9443
+ if (onstart) {
9444
+ await callHandler(onstart, totalSize);
9445
+ }
9187
9446
  await exportChildren(zipEntry, directoryHandle);
9447
+ if (onend) {
9448
+ await callHandler(onend, writtenSize);
9449
+ }
9188
9450
  } catch (error) {
9189
9451
  try {
9190
9452
  error.exportedEntryNames = exportedEntryNames;
@@ -9197,6 +9459,25 @@ async function exportFileSystemHandle(zipEntry, directoryHandle, options) {
9197
9459
  }
9198
9460
  return directoryHandle;
9199
9461
 
9462
+ function createProgressWritable(writable) {
9463
+ const writer = writable.getWriter();
9464
+ return new WritableStream({
9465
+ async write(chunk) {
9466
+ await writer.write(chunk);
9467
+ writtenSize += chunk.length;
9468
+ if (onprogress) {
9469
+ await callHandler(onprogress, writtenSize, totalSize);
9470
+ }
9471
+ },
9472
+ close() {
9473
+ return writer.close();
9474
+ },
9475
+ abort(reason) {
9476
+ return writer.abort(reason);
9477
+ }
9478
+ });
9479
+ }
9480
+
9200
9481
  async function exportChildren(entry, parentHandle) {
9201
9482
  if (options.concurrent) {
9202
9483
  const results = await Promise.allSettled(entry.children.map(child => exportChild(child, parentHandle)));
@@ -9215,10 +9496,10 @@ async function exportFileSystemHandle(zipEntry, directoryHandle, options) {
9215
9496
 
9216
9497
  async function exportChild(child, parentHandle) {
9217
9498
  if (signal.aborted) {
9218
- if (isExportAborted(signal.reason)) {
9499
+ if (exportAborted || isExportAborted(signal.reason)) {
9219
9500
  return;
9220
9501
  }
9221
- throw signal.reason;
9502
+ throw signal.reason === UNDEFINED_VALUE ? new DOMException(ERR_ABORTED, ABORT_ERROR_NAME) : signal.reason;
9222
9503
  }
9223
9504
  try {
9224
9505
  if (child.directory) {
@@ -9227,22 +9508,15 @@ async function exportFileSystemHandle(zipEntry, directoryHandle, options) {
9227
9508
  } else {
9228
9509
  const fileHandle = await parentHandle.getFileHandle(child.name, { create: true });
9229
9510
  const writable = await fileHandle.createWritable();
9230
- await child.getData({ writable }, Object.assign({}, options, {
9231
- signal,
9232
- onprogress: async progress => {
9233
- if (options.onprogress) {
9234
- writtenSizes.set(child.id, progress);
9235
- try {
9236
- await options.onprogress(Array.from(writtenSizes.values()).reduce((previousValue, currentValue) => previousValue + currentValue, 0), totalSize);
9237
- } catch {
9238
- // ignored
9239
- }
9240
- }
9241
- }
9242
- }));
9511
+ try {
9512
+ await child.getData({ writable: createProgressWritable(writable) }, getDataOptions);
9513
+ } catch (error) {
9514
+ throw exportAborted ? new Error(ERR_ABORT_EXPORT) : error;
9515
+ }
9243
9516
  exportedEntryNames.push(child.getRelativeName(zipEntry));
9244
9517
  }
9245
9518
  } catch (error) {
9519
+ exportAborted = true;
9246
9520
  abortController.abort(new Error(ERR_ABORT_EXPORT));
9247
9521
  try {
9248
9522
  if (error.entryName === UNDEFINED_VALUE) {
@@ -9314,6 +9588,21 @@ function resetFS(fs) {
9314
9588
  fs.root = new ZipDirectoryEntry(fs);
9315
9589
  }
9316
9590
 
9591
+ function collectChildren(directory, recursive) {
9592
+ const children = [];
9593
+ const pendingDirectories = [directory];
9594
+ let directoryIndex = 0;
9595
+ while (directoryIndex < pendingDirectories.length) {
9596
+ for (const child of pendingDirectories[directoryIndex++].children) {
9597
+ children.push(child);
9598
+ if (recursive) {
9599
+ pendingDirectories.push(child);
9600
+ }
9601
+ }
9602
+ }
9603
+ return children;
9604
+ }
9605
+
9317
9606
  function registerEntries(fs, entry) {
9318
9607
  const pendingEntries = [entry];
9319
9608
  while (pendingEntries.length) {
@@ -9432,6 +9721,7 @@ exports.BlobReader = BlobReader;
9432
9721
  exports.BlobWriter = BlobWriter;
9433
9722
  exports.Data64URIReader = Data64URIReader;
9434
9723
  exports.Data64URIWriter = Data64URIWriter;
9724
+ exports.ERR_ABORTED = ERR_ABORTED;
9435
9725
  exports.ERR_AMBIGUOUS_ARCHIVE = ERR_AMBIGUOUS_ARCHIVE;
9436
9726
  exports.ERR_BAD_FORMAT = ERR_BAD_FORMAT;
9437
9727
  exports.ERR_CENTRAL_DIRECTORY_NOT_FOUND = ERR_CENTRAL_DIRECTORY_NOT_FOUND;
@@ -9463,6 +9753,7 @@ exports.ERR_INVALID_MSDOS_ATTRIBUTES = ERR_INVALID_MSDOS_ATTRIBUTES;
9463
9753
  exports.ERR_INVALID_MSDOS_DATA = ERR_INVALID_MSDOS_DATA;
9464
9754
  exports.ERR_INVALID_PASSWORD = ERR_INVALID_PASSWORD;
9465
9755
  exports.ERR_INVALID_PASSWORD_TYPE = ERR_INVALID_PASSWORD_TYPE;
9756
+ exports.ERR_INVALID_PASS_THROUGH = ERR_INVALID_PASS_THROUGH;
9466
9757
  exports.ERR_INVALID_SIGNATURE = ERR_INVALID_SIGNATURE;
9467
9758
  exports.ERR_INVALID_SIGNATURE_DATA = ERR_INVALID_SIGNATURE_DATA;
9468
9759
  exports.ERR_INVALID_STRICTNESS = ERR_INVALID_STRICTNESS;
@@ -9480,11 +9771,13 @@ exports.ERR_RESERVED_COMPRESSION_METHOD = ERR_RESERVED_COMPRESSION_METHOD;
9480
9771
  exports.ERR_SPLIT_ZIP_FILE = ERR_SPLIT_ZIP_FILE;
9481
9772
  exports.ERR_UNDEFINED_READER = ERR_UNDEFINED_READER;
9482
9773
  exports.ERR_UNDEFINED_UNCOMPRESSED_SIZE = ERR_UNDEFINED_UNCOMPRESSED_SIZE;
9774
+ exports.ERR_UNDETERMINED_SIZE = ERR_UNDETERMINED_SIZE;
9483
9775
  exports.ERR_UNSAFE_FILENAME = ERR_UNSAFE_FILENAME;
9484
9776
  exports.ERR_UNSUPPORTED_COMPRESSION = ERR_UNSUPPORTED_COMPRESSION$1;
9485
9777
  exports.ERR_UNSUPPORTED_CONTEXT = ERR_UNSUPPORTED_CONTEXT;
9486
9778
  exports.ERR_UNSUPPORTED_CRYPTO_API = ERR_UNSUPPORTED_CRYPTO_API;
9487
9779
  exports.ERR_UNSUPPORTED_ENCRYPTION = ERR_UNSUPPORTED_ENCRYPTION;
9780
+ exports.ERR_UNSUPPORTED_ENCRYPTION_PASS_THROUGH = ERR_UNSUPPORTED_ENCRYPTION_PASS_THROUGH;
9488
9781
  exports.ERR_UNSUPPORTED_ENCRYPTION_USDZ = ERR_UNSUPPORTED_ENCRYPTION_USDZ;
9489
9782
  exports.ERR_UNSUPPORTED_FORMAT = ERR_UNSUPPORTED_FORMAT;
9490
9783
  exports.ERR_WORKER_STARTUP_TIMEOUT = ERR_WORKER_STARTUP_TIMEOUT;