@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/dist/zip-fs.js CHANGED
@@ -90,6 +90,8 @@
90
90
  const FILE_ATTR_MSDOS_ARCHIVE_MASK = 0x20;
91
91
  const FILE_ATTR_UNIX_TYPE_MASK = 0o170000;
92
92
  const FILE_ATTR_UNIX_TYPE_DIR = 0o040000;
93
+ const FILE_ATTR_UNIX_TYPE_SYMLINK = 0o120000;
94
+ const FILE_ATTR_UNIX_TYPE_FILE = 0o100000;
93
95
  const FILE_ATTR_UNIX_EXECUTABLE_MASK = 0o111;
94
96
  const FILE_ATTR_UNIX_DEFAULT_MASK = 0o644;
95
97
  const FILE_ATTR_UNIX_SETUID_MASK = 0o4000;
@@ -1781,8 +1783,6 @@
1781
1783
  */
1782
1784
 
1783
1785
 
1784
- const HTTP_HEADER_CONTENT_TYPE = "Content-Type";
1785
-
1786
1786
  function toCompatibleReadable(readable) {
1787
1787
  if (readable instanceof ReadableStream) {
1788
1788
  return readable;
@@ -1805,12 +1805,9 @@
1805
1805
 
1806
1806
  function streamToBlob(readable, contentType) {
1807
1807
  readable = toCompatibleReadable(readable);
1808
+ const blobOptions = contentType ? { type: contentType } : {};
1808
1809
  if (responseSupportsGlobalReadable()) {
1809
- const options = {};
1810
- if (contentType) {
1811
- options.headers = [[HTTP_HEADER_CONTENT_TYPE, contentType]];
1812
- }
1813
- return new Response(readable, options).blob();
1810
+ return new Response(readable).blob().then(blob => contentType ? new Blob([blob], blobOptions) : blob);
1814
1811
  }
1815
1812
  const chunks = [];
1816
1813
  return readable
@@ -1819,7 +1816,7 @@
1819
1816
  chunks.push(chunk);
1820
1817
  }
1821
1818
  }))
1822
- .then(() => new Blob(chunks, contentType ? { type: contentType } : {}));
1819
+ .then(() => new Blob(chunks, blobOptions));
1823
1820
  }
1824
1821
 
1825
1822
  function responseSupportsGlobalReadable() {
@@ -3354,8 +3351,10 @@
3354
3351
  async pull(controller) {
3355
3352
  const dataSize = size === UNDEFINED_VALUE ? chunkSize : Math.min(chunkSize, size - chunkOffset);
3356
3353
  const data = await readUint8Array(reader, offset + chunkOffset, dataSize);
3357
- controller.enqueue(data);
3358
- if ((chunkOffset + chunkSize > size) || (size === UNDEFINED_VALUE && !data.length && dataSize)) {
3354
+ if (data.length) {
3355
+ controller.enqueue(data);
3356
+ }
3357
+ if ((chunkOffset + chunkSize >= size) || (size === UNDEFINED_VALUE && !data.length && dataSize)) {
3359
3358
  controller.close();
3360
3359
  } else {
3361
3360
  chunkOffset += chunkSize;
@@ -3433,6 +3432,7 @@
3433
3432
  constructor(contentType) {
3434
3433
  super();
3435
3434
  Object.assign(this, {
3435
+ contentType,
3436
3436
  data: "data:" + (contentType || "") + ";base64,",
3437
3437
  pending: []
3438
3438
  });
@@ -3534,6 +3534,7 @@
3534
3534
  return transformStream.writable;
3535
3535
  }
3536
3536
  });
3537
+ writer.contentType = contentType;
3537
3538
  writer.blob = streamToBlob(transformStream.readable, contentType);
3538
3539
  writer.blob.catch(() => { });
3539
3540
  }
@@ -3550,6 +3551,26 @@
3550
3551
  }
3551
3552
  }
3552
3553
 
3554
+ function getTextSize(text) {
3555
+ let size = 0;
3556
+ for (let indexCharacter = 0; indexCharacter < text.length; indexCharacter++) {
3557
+ const characterCode = text.charCodeAt(indexCharacter);
3558
+ if (characterCode < 0x80) {
3559
+ size += 1;
3560
+ } else if (characterCode < 0x800) {
3561
+ size += 2;
3562
+ } else if (characterCode < 0xd800 || characterCode >= 0xe000) {
3563
+ size += 3;
3564
+ } else if (characterCode < 0xdc00 && (text.charCodeAt(indexCharacter + 1) & 0xfc00) == 0xdc00) {
3565
+ size += 4;
3566
+ indexCharacter++;
3567
+ } else {
3568
+ size += 3;
3569
+ }
3570
+ }
3571
+ return size;
3572
+ }
3573
+
3553
3574
  class TextWriter extends BlobWriter {
3554
3575
 
3555
3576
  constructor(encoding) {
@@ -4213,6 +4234,10 @@
4213
4234
  }
4214
4235
  }
4215
4236
 
4237
+ function ownsWritable(writer) {
4238
+ return Boolean(writer && writer.getData);
4239
+ }
4240
+
4216
4241
  function isHttpFamily(url) {
4217
4242
  const { baseURI } = getConfiguration();
4218
4243
  const { protocol } = new URL(url, baseURI);
@@ -4357,6 +4382,8 @@
4357
4382
  const PROPERTY_NAME_RAW_CREATION_DATE = "rawCreationDate";
4358
4383
  const PROPERTY_NAME_INTERNAL_FILE_ATTRIBUTES = "internalFileAttributes";
4359
4384
  const PROPERTY_NAME_EXTERNAL_FILE_ATTRIBUTES = "externalFileAttributes";
4385
+ const PROPERTY_NAME_DEPRECATED_INTERNAL_FILE_ATTRIBUTES = "internalFileAttribute";
4386
+ const PROPERTY_NAME_DEPRECATED_EXTERNAL_FILE_ATTRIBUTES = "externalFileAttribute";
4360
4387
  const PROPERTY_NAME_MSDOS_ATTRIBUTES_RAW = "msdosAttributesRaw";
4361
4388
  const PROPERTY_NAME_MSDOS_ATTRIBUTES = "msdosAttributes";
4362
4389
  const PROPERTY_NAME_MS_DOS_COMPATIBLE = "msDosCompatible";
@@ -4367,6 +4394,7 @@
4367
4394
  const PROPERTY_NAME_ZIPCRYPTO = "zipCrypto";
4368
4395
  const PROPERTY_NAME_DIRECTORY = "directory";
4369
4396
  const PROPERTY_NAME_EXECUTABLE = "executable";
4397
+ const PROPERTY_NAME_SYMLINK = "symlink";
4370
4398
  const PROPERTY_NAME_COMPRESSION_METHOD = "compressionMethod";
4371
4399
  const PROPERTY_NAME_SIGNATURE = "signature";
4372
4400
  const PROPERTY_NAME_CRC32 = "crc32";
@@ -4410,6 +4438,8 @@
4410
4438
  PROPERTY_NAME_DISK_NUMBER_START,
4411
4439
  PROPERTY_NAME_INTERNAL_FILE_ATTRIBUTES,
4412
4440
  PROPERTY_NAME_EXTERNAL_FILE_ATTRIBUTES,
4441
+ PROPERTY_NAME_DEPRECATED_INTERNAL_FILE_ATTRIBUTES,
4442
+ PROPERTY_NAME_DEPRECATED_EXTERNAL_FILE_ATTRIBUTES,
4413
4443
  PROPERTY_NAME_MSDOS_ATTRIBUTES_RAW,
4414
4444
  PROPERTY_NAME_MSDOS_ATTRIBUTES,
4415
4445
  PROPERTY_NAME_MS_DOS_COMPATIBLE,
@@ -4420,6 +4450,7 @@
4420
4450
  PROPERTY_NAME_ZIPCRYPTO,
4421
4451
  PROPERTY_NAME_DIRECTORY,
4422
4452
  PROPERTY_NAME_EXECUTABLE,
4453
+ PROPERTY_NAME_SYMLINK,
4423
4454
  PROPERTY_NAME_COMPRESSION_METHOD,
4424
4455
  PROPERTY_NAME_SIGNATURE,
4425
4456
  PROPERTY_NAME_CRC32,
@@ -4882,15 +4913,18 @@
4882
4913
  const setuid = Boolean(fileEntry.unixMode & FILE_ATTR_UNIX_SETUID_MASK);
4883
4914
  const setgid = Boolean(fileEntry.unixMode & FILE_ATTR_UNIX_SETGID_MASK);
4884
4915
  const sticky = Boolean(fileEntry.unixMode & FILE_ATTR_UNIX_STICKY_MASK);
4885
- const executable = (fileEntry.unixMode !== UNDEFINED_VALUE)
4916
+ const unixType = fileEntry.unixMode === UNDEFINED_VALUE ? unixExternalUpper : fileEntry.unixMode;
4917
+ const symlink = (unixType & FILE_ATTR_UNIX_TYPE_MASK) == FILE_ATTR_UNIX_TYPE_SYMLINK;
4918
+ const executable = !symlink && ((fileEntry.unixMode !== UNDEFINED_VALUE)
4886
4919
  ? ((fileEntry.unixMode & FILE_ATTR_UNIX_EXECUTABLE_MASK) != 0)
4887
- : (unixCompatible && ((unixExternalUpper & FILE_ATTR_UNIX_EXECUTABLE_MASK) != 0));
4920
+ : (unixCompatible && ((unixExternalUpper & FILE_ATTR_UNIX_EXECUTABLE_MASK) != 0)));
4888
4921
  const modeIsDir = fileEntry.unixMode !== UNDEFINED_VALUE && ((fileEntry.unixMode & FILE_ATTR_UNIX_TYPE_MASK) == FILE_ATTR_UNIX_TYPE_DIR);
4889
4922
  const upperIsDir = ((unixExternalUpper & FILE_ATTR_UNIX_TYPE_MASK) == FILE_ATTR_UNIX_TYPE_DIR);
4890
4923
  Object.assign(fileEntry, {
4891
4924
  setuid,
4892
4925
  setgid,
4893
4926
  sticky,
4927
+ symlink,
4894
4928
  unixExternalUpper,
4895
4929
  internalFileAttribute: fileEntry.internalFileAttributes,
4896
4930
  externalFileAttribute: fileEntry.externalFileAttributes,
@@ -4956,6 +4990,10 @@
4956
4990
  }
4957
4991
 
4958
4992
  async close() {
4993
+ const { reader } = this;
4994
+ if (!reader.readUint8Array && reader.readable && !reader.readable.locked) {
4995
+ await reader.readable.cancel();
4996
+ }
4959
4997
  }
4960
4998
  }
4961
4999
 
@@ -5180,7 +5218,7 @@
5180
5218
  throw error;
5181
5219
  }
5182
5220
  } finally {
5183
- const preventClose = getOptionValue$1(zipEntry, options, OPTION_PREVENT_CLOSE);
5221
+ const preventClose = !ownsWritable(writer) && getOptionValue$1(zipEntry, options, OPTION_PREVENT_CLOSE);
5184
5222
  if (!preventClose && writable && !writable.locked) {
5185
5223
  const writableWriter = writable.getWriter();
5186
5224
  if (abortError) {
@@ -5424,8 +5462,8 @@
5424
5462
  return;
5425
5463
  }
5426
5464
  const extraFieldView = getDataView(extraField.data);
5427
- const lastAccessDate = new Date(getUint32(extraFieldView, 0) * 1000);
5428
- const lastModDate = new Date(getUint32(extraFieldView, 4) * 1000);
5465
+ const lastAccessDate = new Date((getUint32(extraFieldView, 0) | 0) * 1000);
5466
+ const lastModDate = new Date((getUint32(extraFieldView, 4) | 0) * 1000);
5429
5467
  const extraFieldData = { lastAccessDate, lastModDate };
5430
5468
  if (extraField.data.length >= 12) {
5431
5469
  extraFieldData.uid = getUint16(extraFieldView, 8);
@@ -5856,6 +5894,7 @@
5856
5894
  const ERR_INVALID_VERSION = "Version exceeds 65535";
5857
5895
  const ERR_INVALID_ENCRYPTION_STRENGTH = "The strength must equal 1, 2, or 3";
5858
5896
  const ERR_UNSUPPORTED_ENCRYPTION_USDZ = "Encryption is not supported in USDZ files";
5897
+ const ERR_UNSUPPORTED_ENCRYPTION_PASS_THROUGH = "Encryption is not supported when the 'passThrough' option is set";
5859
5898
  const ERR_INVALID_EXTRAFIELD_TYPE = "Extra field type exceeds 65535";
5860
5899
  const ERR_INVALID_EXTRAFIELD_DATA = "Extra field data exceeds 64KB";
5861
5900
  const ERR_UNSUPPORTED_COMPRESSION = "Compression method not supported";
@@ -5865,6 +5904,7 @@
5865
5904
  const MAX_NTFS_TIME = BigInt("0x7fffffffffffffff");
5866
5905
  const ERR_UNSUPPORTED_FORMAT = "Zip64 is not supported (set the 'zip64' option to 'true')";
5867
5906
  const ERR_UNDEFINED_UNCOMPRESSED_SIZE = "Undefined uncompressed size";
5907
+ const ERR_UNDETERMINED_SIZE = "Undetermined size";
5868
5908
  const ERR_UNDEFINED_READER = "Undefined reader";
5869
5909
  const ERR_ZIP_NOT_EMPTY = "Zip file not empty";
5870
5910
  const ERR_INVALID_UID = "Invalid uid (must be integer 0..2^32-1)";
@@ -6072,7 +6112,7 @@
6072
6112
  await Promise.allSettled(Array.from(pendingAddFileCalls));
6073
6113
  }
6074
6114
  await closeFile(zipWriter, comment, options);
6075
- const preventClose = getOptionValue(zipWriter, options, OPTION_PREVENT_CLOSE);
6115
+ const preventClose = !ownsWritable(writer) && getOptionValue(zipWriter, options, OPTION_PREVENT_CLOSE);
6076
6116
  if (!preventClose) {
6077
6117
  await writable.getWriter().close();
6078
6118
  }
@@ -6231,7 +6271,7 @@
6231
6271
  if (versionMadeBy > MAX_16_BITS) {
6232
6272
  throw new Error(ERR_INVALID_VERSION);
6233
6273
  }
6234
- let externalFileAttributes = getOptionValue(zipWriter, options, PROPERTY_NAME_EXTERNAL_FILE_ATTRIBUTES);
6274
+ let externalFileAttributes = getAliasedOptionValue(zipWriter, options, PROPERTY_NAME_EXTERNAL_FILE_ATTRIBUTES, PROPERTY_NAME_DEPRECATED_EXTERNAL_FILE_ATTRIBUTES);
6235
6275
  const externalFileAttributesProvided = externalFileAttributes !== UNDEFINED_VALUE;
6236
6276
  if (!externalFileAttributesProvided) {
6237
6277
  externalFileAttributes = 0;
@@ -6279,7 +6319,9 @@
6279
6319
  }
6280
6320
  if (!externalFileAttributesProvided || unixModeProvided) {
6281
6321
  if (directory) {
6282
- unixMode |= FILE_ATTR_UNIX_TYPE_DIR;
6322
+ unixMode = (unixMode & ~FILE_ATTR_UNIX_TYPE_MASK) | FILE_ATTR_UNIX_TYPE_DIR;
6323
+ } else if (!(unixMode & FILE_ATTR_UNIX_TYPE_MASK)) {
6324
+ unixMode |= FILE_ATTR_UNIX_TYPE_FILE;
6283
6325
  }
6284
6326
  externalFileAttributes = ((unixMode & MAX_16_BITS) << 16) | (externalFileAttributes & MAX_16_BITS);
6285
6327
  }
@@ -6332,15 +6374,12 @@
6332
6374
  const lastModDate = getOptionValue(zipWriter, options, PROPERTY_NAME_LAST_MODIFICATION_DATE, new Date());
6333
6375
  const lastAccessDate = getOptionValue(zipWriter, options, PROPERTY_NAME_LAST_ACCESS_DATE);
6334
6376
  const creationDate = getOptionValue(zipWriter, options, PROPERTY_NAME_CREATION_DATE);
6335
- const internalFileAttributes = getOptionValue(zipWriter, options, PROPERTY_NAME_INTERNAL_FILE_ATTRIBUTES, 0);
6377
+ const internalFileAttributes = getAliasedOptionValue(zipWriter, options, PROPERTY_NAME_INTERNAL_FILE_ATTRIBUTES, PROPERTY_NAME_DEPRECATED_INTERNAL_FILE_ATTRIBUTES, 0);
6336
6378
  const passThrough = getOptionValue(zipWriter, options, OPTION_PASS_THROUGH);
6337
- let password, rawPassword;
6338
- if (!passThrough) {
6339
- password = getOptionValue(zipWriter, options, OPTION_PASSWORD);
6340
- rawPassword = getOptionValue(zipWriter, options, OPTION_RAW_PASSWORD);
6341
- if ((password && typeof password != STRING_TYPE) || (rawPassword && !(rawPassword instanceof Uint8Array))) {
6342
- throw new Error(ERR_INVALID_PASSWORD_TYPE);
6343
- }
6379
+ const password = getOptionValue(zipWriter, options, OPTION_PASSWORD);
6380
+ const rawPassword = getOptionValue(zipWriter, options, OPTION_RAW_PASSWORD);
6381
+ if ((password && typeof password != STRING_TYPE) || (rawPassword && !(rawPassword instanceof Uint8Array))) {
6382
+ throw new Error(ERR_INVALID_PASSWORD_TYPE);
6344
6383
  }
6345
6384
  const encryptionStrength = getNumberOptionValue(zipWriter, options, OPTION_ENCRYPTION_STRENGTH, 3);
6346
6385
  const zipCrypto = getOptionValue(zipWriter, options, PROPERTY_NAME_ZIPCRYPTO);
@@ -6453,14 +6492,24 @@
6453
6492
  }
6454
6493
 
6455
6494
  async function resolveSizes(zipWriter, reader, { resolvedOptions: metadata }, options) {
6495
+ if (metadata.passThrough && !reader && !getOptionValue(zipWriter, options, PROPERTY_NAME_DIRECTORY)) {
6496
+ throw new Error(ERR_UNDEFINED_READER);
6497
+ }
6498
+ let contentSize;
6499
+ if (reader) {
6500
+ reader = new GenericReader(reader);
6501
+ await initStream(reader);
6502
+ ({ size: contentSize } = reader);
6503
+ }
6504
+ return Object.assign({ reader }, resolveEntrySizes(zipWriter, Boolean(reader), contentSize, metadata, options));
6505
+ }
6506
+
6507
+ function resolveEntrySizes(zipWriter, hasContent, contentSize, metadata, options) {
6456
6508
  const { passThrough, zipCrypto, password, rawPassword, encryptionStrength } = metadata;
6457
6509
  let { dataDescriptor, zip64, level, compressionMethod } = metadata;
6458
6510
  let maximumCompressedSize = 0;
6459
6511
  let uncompressedSize = 0;
6460
- if (passThrough) {
6461
- if (!reader) {
6462
- throw new Error(ERR_UNDEFINED_READER);
6463
- }
6512
+ if (passThrough && hasContent) {
6464
6513
  uncompressedSize = options[PROPERTY_NAME_UNCOMPRESSED_SIZE];
6465
6514
  if (uncompressedSize === UNDEFINED_VALUE) {
6466
6515
  throw new Error(ERR_UNDEFINED_UNCOMPRESSED_SIZE);
@@ -6468,29 +6517,30 @@
6468
6517
  }
6469
6518
  const zip64Enabled = zip64 === true;
6470
6519
  const encrypted = getOptionValue(zipWriter, options, PROPERTY_NAME_ENCRYPTED);
6471
- const encryptedEntry = Boolean(reader) && (Boolean((password && getLength(password)) || (rawPassword && getLength(rawPassword))) || (passThrough && encrypted));
6472
- if (!reader) {
6520
+ if (hasContent && passThrough && !encrypted && getLength(password, rawPassword)) {
6521
+ throw new Error(ERR_UNSUPPORTED_ENCRYPTION_PASS_THROUGH);
6522
+ }
6523
+ const encryptedEntry = hasContent && (Boolean((password && getLength(password)) || (rawPassword && getLength(rawPassword))) || (passThrough && encrypted));
6524
+ if (!hasContent) {
6473
6525
  level = 0;
6474
6526
  compressionMethod = COMPRESSION_METHOD_STORE;
6475
6527
  }
6476
6528
  const encryptionOverhead = encryptedEntry ? (zipCrypto ? 12 : 16 + encryptionStrength * 4) : 0;
6477
- if (reader) {
6478
- reader = new GenericReader(reader);
6479
- await initStream(reader);
6529
+ if (hasContent) {
6480
6530
  if (!passThrough) {
6481
- if (reader.size === UNDEFINED_VALUE) {
6531
+ if (contentSize === UNDEFINED_VALUE) {
6482
6532
  dataDescriptor = true;
6483
6533
  if (zip64 || zip64 === UNDEFINED_VALUE) {
6484
6534
  zip64 = true;
6485
6535
  uncompressedSize = maximumCompressedSize = MAX_32_BITS + 1;
6486
6536
  }
6487
6537
  } else {
6488
- options.uncompressedSize = uncompressedSize = reader.size;
6489
- maximumCompressedSize = getMaximumCompressedSize(uncompressedSize) + encryptionOverhead;
6538
+ options.uncompressedSize = uncompressedSize = contentSize;
6539
+ maximumCompressedSize = (isCompressed(compressionMethod, level) ? getMaximumCompressedSize(uncompressedSize) : uncompressedSize) + encryptionOverhead;
6490
6540
  }
6491
6541
  } else {
6492
6542
  options.uncompressedSize = uncompressedSize;
6493
- maximumCompressedSize = getMaximumCompressedSize(uncompressedSize) + encryptionOverhead;
6543
+ maximumCompressedSize = contentSize === UNDEFINED_VALUE ? getMaximumCompressedSize(uncompressedSize) + encryptionOverhead : contentSize;
6494
6544
  }
6495
6545
  }
6496
6546
  const zip64UncompressedSize = zip64Enabled || uncompressedSize >= MAX_32_BITS;
@@ -6504,7 +6554,7 @@
6504
6554
  }
6505
6555
  zip64 = zip64 || false;
6506
6556
  return {
6507
- reader,
6557
+ maximumCompressedSize,
6508
6558
  resolvedOptions: {
6509
6559
  dataDescriptor,
6510
6560
  zip64,
@@ -6518,6 +6568,78 @@
6518
6568
  };
6519
6569
  }
6520
6570
 
6571
+ async function getEntriesSize(writerOptions, entries, writeOrderGuaranteed, comment) {
6572
+ const zipWriter = { options: writerOptions, config: getConfiguration() };
6573
+ if (writerOptions[OPTION_SIGN_CENTRAL_DIRECTORY]) {
6574
+ throw new Error(ERR_UNDETERMINED_SIZE);
6575
+ }
6576
+ const commentLength = getLength(comment);
6577
+ if (commentLength > MAX_16_BITS) {
6578
+ throw new Error(ERR_INVALID_COMMENT);
6579
+ }
6580
+ const usdz = writerOptions[OPTION_USDZ];
6581
+ const files = new Map();
6582
+ let layoutDependsOnWriteOrder = Boolean(usdz);
6583
+ let offset = 0;
6584
+ for (const entry of entries) {
6585
+ let { name } = entry;
6586
+ const { size } = entry;
6587
+ const options = Object.assign({}, entry.options);
6588
+ name = name.trim();
6589
+ if (getOptionValue(zipWriter, options, PROPERTY_NAME_DIRECTORY) && !name.endsWith(DIRECTORY_SIGNATURE)) {
6590
+ name += DIRECTORY_SIGNATURE;
6591
+ }
6592
+ const attributesInfo = resolveAttributes(zipWriter, name, options);
6593
+ ({ name } = attributesInfo);
6594
+ const { resolvedOptions: metadata } = resolveMetadata(zipWriter, name, options);
6595
+ if (metadata.level != 0 && metadata.compressionMethod === UNDEFINED_VALUE &&
6596
+ !metadata.passThrough && !(await supportsDeflate(zipWriter.config))) {
6597
+ metadata.level = 0;
6598
+ }
6599
+ const hasContent = !getOptionValue(zipWriter, options, PROPERTY_NAME_DIRECTORY);
6600
+ if (hasContent && size === UNDEFINED_VALUE) {
6601
+ throw new Error(ERR_UNDETERMINED_SIZE);
6602
+ }
6603
+ const { maximumCompressedSize, resolvedOptions: sizes } = resolveEntrySizes(zipWriter, hasContent, size, metadata, options);
6604
+ if (hasContent && !metadata.passThrough && isCompressed(sizes.compressionMethod, sizes.level)) {
6605
+ throw new Error(ERR_UNDETERMINED_SIZE);
6606
+ }
6607
+ const entryOptions = Object.assign({}, options, attributesInfo.resolvedOptions, metadata, sizes);
6608
+ const headerInfo = getHeaderInfo(entryOptions);
6609
+ const dataDescriptorInfo = getDataDescriptorInfo(entryOptions);
6610
+ const entryInfo = {
6611
+ headerInfo,
6612
+ metadataSize: getLength(headerInfo.localHeaderArray, dataDescriptorInfo.dataDescriptorArray)
6613
+ };
6614
+ if (usdz) {
6615
+ appendExtraFieldUSDZ(entryInfo, offset);
6616
+ }
6617
+ const compressedSize = hasContent ? maximumCompressedSize : 0;
6618
+ if (offset >= MAX_32_BITS) {
6619
+ layoutDependsOnWriteOrder = true;
6620
+ }
6621
+ files.set(name, Object.assign({}, entryOptions, headerInfo, {
6622
+ offset,
6623
+ diskNumberStart: 0,
6624
+ compressedSize
6625
+ }));
6626
+ offset += entryInfo.metadataSize + compressedSize;
6627
+ }
6628
+ if (layoutDependsOnWriteOrder && !writeOrderGuaranteed) {
6629
+ throw new Error(ERR_UNDETERMINED_SIZE);
6630
+ }
6631
+ const directoryDataLength = createDirectoryRecords(files);
6632
+ let zip64 = getOptionValue(zipWriter, writerOptions, PROPERTY_NAME_ZIP64);
6633
+ if (offset >= MAX_32_BITS || directoryDataLength >= MAX_32_BITS || files.size >= MAX_16_BITS) {
6634
+ if (zip64 === false) {
6635
+ throw new Error(ERR_UNSUPPORTED_FORMAT);
6636
+ } else {
6637
+ zip64 = true;
6638
+ }
6639
+ }
6640
+ return offset + directoryDataLength + commentLength + (zip64 ? ZIP64_END_OF_CENTRAL_DIR_TOTAL_LENGTH : END_OF_CENTRAL_DIR_LENGTH);
6641
+ }
6642
+
6521
6643
  async function getFileEntry(zipWriter, name, reader, entryInfo, options) {
6522
6644
  const {
6523
6645
  files,
@@ -6889,9 +7011,7 @@
6889
7011
  crc32
6890
7012
  } = options;
6891
7013
  let { version, compressionMethod } = options;
6892
- const compressed = !directory && (compressionMethod === UNDEFINED_VALUE
6893
- ? (level === UNDEFINED_VALUE || level > 0)
6894
- : compressionMethod !== COMPRESSION_METHOD_STORE);
7014
+ const compressed = !directory && isCompressed(compressionMethod, level);
6895
7015
  let rawLocalExtraFieldZip64;
6896
7016
  const uncompressedFile = passThrough || !compressed;
6897
7017
  const zip64ExtraFieldComplete = zip64 && (options.bufferedWrite || !dataDescriptor || ((!zip64UncompressedSize && !zip64CompressedSize) || uncompressedFile));
@@ -7578,6 +7698,16 @@
7578
7698
  return result === UNDEFINED_VALUE ? defaultValue : result;
7579
7699
  }
7580
7700
 
7701
+ function getAliasedOptionValue(zipWriter, options, name, deprecatedName, defaultValue) {
7702
+ const value = getAliasedValue(options, name, deprecatedName);
7703
+ const result = value === UNDEFINED_VALUE ? getAliasedValue(zipWriter.options, name, deprecatedName) : value;
7704
+ return result === UNDEFINED_VALUE ? defaultValue : result;
7705
+ }
7706
+
7707
+ function getAliasedValue(options, name, deprecatedName) {
7708
+ return options[name] === UNDEFINED_VALUE ? options[deprecatedName] : options[name];
7709
+ }
7710
+
7581
7711
  function getNumberOptionValue(zipWriter, options, name, defaultValue) {
7582
7712
  return toNumber(getOptionValue(zipWriter, options, name, defaultValue));
7583
7713
  }
@@ -7590,6 +7720,12 @@
7590
7720
  return uncompressedSize + (5 * (Math.floor(uncompressedSize / 16383) + 1));
7591
7721
  }
7592
7722
 
7723
+ function isCompressed(compressionMethod, level) {
7724
+ return compressionMethod === UNDEFINED_VALUE
7725
+ ? (level === UNDEFINED_VALUE || level > 0)
7726
+ : compressionMethod !== COMPRESSION_METHOD_STORE;
7727
+ }
7728
+
7593
7729
  function setUint8(view, offset, value) {
7594
7730
  view.setUint8(offset, value);
7595
7731
  }
@@ -8603,7 +8739,10 @@
8603
8739
 
8604
8740
  const ERR_ENTRY_EXISTS = "Entry filename already exists";
8605
8741
  const ERR_READABLE_CONSUMED = "Readable stream already consumed";
8742
+ const ERR_INVALID_PASS_THROUGH = "Invalid passThrough option (use readerOptions.passThrough or set uncompressedSize for each entry)";
8606
8743
  const ERR_ABORT_EXPORT = "zipjs-abort-export";
8744
+ const ERR_ABORTED = "The operation was aborted";
8745
+ const ABORT_ERROR_NAME = "AbortError";
8607
8746
  const INFOZIP_EXTRA_FIELD_TYPE = "infozip";
8608
8747
  const INTERPRETED_EXTRA_FIELD_TYPES = new Set([
8609
8748
  EXTRAFIELD_TYPE_ZIP64,
@@ -8638,6 +8777,7 @@
8638
8777
  parent,
8639
8778
  children: [],
8640
8779
  uncompressedSize: params.uncompressedSize || 0,
8780
+ undeterminedSize: params.undeterminedSize || params.uncompressedSize === UNDEFINED_VALUE,
8641
8781
  passThrough: params.passThrough
8642
8782
  });
8643
8783
  if (parent || !fs.root) {
@@ -8705,16 +8845,17 @@
8705
8845
 
8706
8846
  async getData(writer, options = {}) {
8707
8847
  const zipEntry = this;
8708
- if (!writer || (writer.constructor == zipEntry.Writer && zipEntry.data)) {
8848
+ if (!writer || (writer.constructor == zipEntry.Writer && zipEntry.data && keepsContentType(writer, zipEntry.data))) {
8709
8849
  return zipEntry.data;
8710
8850
  } else {
8711
8851
  const reader = zipEntry.reader = createReader(zipEntry.Reader, zipEntry.data, options);
8712
- const uncompressedSize = zipEntry.data ? zipEntry.data.uncompressedSize : reader.size;
8713
- await Promise.all([initStream(reader), initStream(writer, uncompressedSize)]);
8714
- const { readable } = reader;
8852
+ const dataSize = zipEntry.uncompressedSize || reader.size;
8853
+ await Promise.all([initStream(reader), initStream(writer, dataSize)]);
8715
8854
  const { signal } = options;
8855
+ const readable = createProgressReadable(zipEntry, reader, options, signal);
8856
+ const preventClose = !ownsWritable(writer) && Boolean(options.preventClose);
8716
8857
  zipEntry.uncompressedSize = reader.size;
8717
- await toCompatibleReadable(readable).pipeTo(toCompatibleWritable(writer.writable), { signal });
8858
+ await toCompatibleReadable(readable).pipeTo(toCompatibleWritable(writer.writable), { signal, preventClose, preventAbort: preventClose });
8718
8859
  return writer.getData ? writer.getData() : writer.writable;
8719
8860
  }
8720
8861
  }
@@ -8845,7 +8986,7 @@
8845
8986
  Reader: TextReader,
8846
8987
  Writer: TextWriter,
8847
8988
  options,
8848
- uncompressedSize: text.length
8989
+ uncompressedSize: getTextSize(text)
8849
8990
  });
8850
8991
  }
8851
8992
 
@@ -8974,10 +9115,16 @@
8974
9115
  }
8975
9116
 
8976
9117
  async importZip(reader, options = {}) {
8977
- await initStream(reader);
8978
- const zipReader = new ZipReader(reader, options);
9118
+ let zipReader;
9119
+ if (reader && typeof reader.getEntries == FUNCTION_TYPE) {
9120
+ zipReader = reader;
9121
+ options = Object.assign({}, zipReader.options, options);
9122
+ } else {
9123
+ await initStream(reader);
9124
+ zipReader = new ZipReader(reader, options);
9125
+ }
8979
9126
  const importedEntries = [];
8980
- const entries = await zipReader.getEntries();
9127
+ const entries = await zipReader.getEntries(options);
8981
9128
  for (const entry of entries) {
8982
9129
  let parent = this;
8983
9130
  try {
@@ -8999,7 +9146,7 @@
8999
9146
  importedEntries.push(addChild(parent, name, {
9000
9147
  data: entry,
9001
9148
  Reader: getZipBlobReader(Object.assign({}, options)),
9002
- uncompressedSize: entry.uncompressedSize,
9149
+ uncompressedSize: options.passThrough ? entry.compressedSize : entry.uncompressedSize,
9003
9150
  passThrough: options.passThrough
9004
9151
  }));
9005
9152
  } else {
@@ -9041,11 +9188,25 @@
9041
9188
  }
9042
9189
  const [readers] = await Promise.all([initReaders(zipEntry, options.readerOptions), initStream(writer)]);
9043
9190
  const zipWriter = new ZipWriter(writer, options);
9044
- await exportZip(zipWriter, zipEntry, getTotalSize([zipEntry], "uncompressedSize"), options, readers);
9045
- await zipWriter.close();
9191
+ await exportZip(zipWriter, zipEntry, getTotalSize([zipEntry], getUncompressedSize), options, readers);
9192
+ await zipWriter.close(options.globalComment);
9046
9193
  return writer.getData ? writer.getData() : writer.writable;
9047
9194
  }
9048
9195
 
9196
+ getExportedSize(options = {}) {
9197
+ const zipEntry = this;
9198
+ options = Object.assign({}, options);
9199
+ if (options.bufferedWrite === UNDEFINED_VALUE) {
9200
+ options.bufferedWrite = true;
9201
+ }
9202
+ const writeOrderGuaranteed = !options.bufferedWrite ||
9203
+ (options.keepOrder !== false && zipEntry.children.every(child => !child.children.length));
9204
+ return getEntriesSize(options, Array.from(zipEntry.getChildren({ recursive: true }), child => {
9205
+ const { name, entryOptions } = getChildEntryOptions(child, zipEntry, options);
9206
+ return { name, size: child.directory ? 0 : getDeterminedSize(child, isPassThrough(child, options)), options: entryOptions };
9207
+ }), writeOrderGuaranteed, options.globalComment);
9208
+ }
9209
+
9049
9210
  getChildByName(name) {
9050
9211
  const children = this.children;
9051
9212
  for (let childIndex = 0; childIndex < children.length; childIndex++) {
@@ -9056,6 +9217,10 @@
9056
9217
  }
9057
9218
  }
9058
9219
 
9220
+ getChildren(options = {}) {
9221
+ return collectChildren(this, options.recursive);
9222
+ }
9223
+
9059
9224
  isPasswordProtected() {
9060
9225
  const children = this.children;
9061
9226
  for (let childIndex = 0; childIndex < children.length; childIndex++) {
@@ -9147,6 +9312,10 @@
9147
9312
  return this.root.getChildByName(name);
9148
9313
  }
9149
9314
 
9315
+ getChildren(options) {
9316
+ return this.root.getChildren(options);
9317
+ }
9318
+
9150
9319
  addDirectory(name, options) {
9151
9320
  return this.root.addDirectory(name, options);
9152
9321
  }
@@ -9245,6 +9414,10 @@
9245
9414
  return this.root.exportZip(writer, options);
9246
9415
  }
9247
9416
 
9417
+ getExportedSize(options) {
9418
+ return this.root.getExportedSize(options);
9419
+ }
9420
+
9248
9421
  isPasswordProtected() {
9249
9422
  return this.root.isPasswordProtected();
9250
9423
  }
@@ -9256,12 +9429,12 @@
9256
9429
 
9257
9430
  const fs = { FS, ZipDirectoryEntry, ZipFileEntry };
9258
9431
 
9259
- function getTotalSize(entries, propertyName) {
9432
+ function getTotalSize(entries, getEntrySize) {
9260
9433
  let size = 0;
9261
9434
  const pendingEntries = Array.from(entries);
9262
9435
  while (pendingEntries.length) {
9263
9436
  const entry = pendingEntries.pop();
9264
- size += entry[propertyName] || 0;
9437
+ size += getEntrySize(entry) || 0;
9265
9438
  for (const child of entry.children) {
9266
9439
  pendingEntries.push(child);
9267
9440
  }
@@ -9269,6 +9442,15 @@
9269
9442
  return size;
9270
9443
  }
9271
9444
 
9445
+ function getUncompressedSize(entry) {
9446
+ return entry.uncompressedSize;
9447
+ }
9448
+
9449
+ function getExtractedSize(entry, passThrough) {
9450
+ const { data } = entry;
9451
+ return passThrough && data instanceof Entry ? data.compressedSize : entry.uncompressedSize;
9452
+ }
9453
+
9272
9454
  function getReadableReader(readable) {
9273
9455
  let consumed;
9274
9456
  return function () {
@@ -9291,10 +9473,17 @@
9291
9473
 
9292
9474
  async init() {
9293
9475
  const zipBlobReader = this;
9294
- zipBlobReader.size = zipBlobReader.entry.uncompressedSize;
9295
- const data = await zipBlobReader.entry.getData(new BlobWriter(), Object.assign({}, options, zipBlobReader.options));
9476
+ const readerOptions = Object.assign({}, options, zipBlobReader.options);
9477
+ const { checkOverlappingEntry, checkOverlappingEntryOnly } = readerOptions;
9478
+ const data = await zipBlobReader.entry.getData(new BlobWriter(), Object.assign(readerOptions, {
9479
+ checkPasswordOnly: false,
9480
+ checkOverlappingEntry: checkOverlappingEntryOnly || checkOverlappingEntry,
9481
+ checkOverlappingEntryOnly: false,
9482
+ preventClose: false
9483
+ }));
9296
9484
  zipBlobReader.data = data;
9297
9485
  zipBlobReader.blobReader = new BlobReader(data);
9486
+ zipBlobReader.size = data.size;
9298
9487
  super.init();
9299
9488
  }
9300
9489
 
@@ -9308,6 +9497,30 @@
9308
9497
  return Reader.prototype ? new Reader(data, options) : Reader(data, options);
9309
9498
  }
9310
9499
 
9500
+ function keepsContentType(writer, data) {
9501
+ const { contentType } = writer;
9502
+ if (contentType === UNDEFINED_VALUE) {
9503
+ return true;
9504
+ } else if (writer.constructor == BlobWriter) {
9505
+ return data.type == contentType;
9506
+ } else if (writer.constructor == Data64URIWriter) {
9507
+ return data.startsWith(writer.data);
9508
+ } else {
9509
+ return true;
9510
+ }
9511
+ }
9512
+
9513
+ function createProgressReadable(zipEntry, reader, options, signal) {
9514
+ const { onstart, onprogress, onend } = options;
9515
+ const { readable } = reader;
9516
+ const coreReaderReportsProgress = zipEntry.data instanceof Entry;
9517
+ if (coreReaderReportsProgress || (!onstart && !onprogress && !onend)) {
9518
+ return readable;
9519
+ } else {
9520
+ return toCompatibleReadable(readable).pipeThrough(new ProgressWatcherStream({ onstart, onprogress, onend, size: reader.size }), { signal });
9521
+ }
9522
+ }
9523
+
9311
9524
  async function initReaders(entry, options) {
9312
9525
  const fileEntries = [];
9313
9526
  const pendingEntries = [entry];
@@ -9340,6 +9553,7 @@
9340
9553
  }
9341
9554
  if (reader.size !== UNDEFINED_VALUE) {
9342
9555
  child.uncompressedSize = reader.size;
9556
+ child.undeterminedSize = false;
9343
9557
  }
9344
9558
  }));
9345
9559
  return readers;
@@ -9389,6 +9603,90 @@
9389
9603
  return error;
9390
9604
  }
9391
9605
 
9606
+ function getChildEntryOptions(child, selectedEntry, options) {
9607
+ const name = options.relativePath ? child.getRelativeName(selectedEntry) : child.getFullname();
9608
+ const childOptions = child.options || {};
9609
+ let zipEntryMetadata = {};
9610
+ let passThroughOptions = {};
9611
+ if (child.data instanceof Entry) {
9612
+ const {
9613
+ externalFileAttributes,
9614
+ versionMadeBy,
9615
+ comment,
9616
+ lastModDate,
9617
+ creationDate,
9618
+ lastAccessDate,
9619
+ uncompressedSize,
9620
+ encrypted,
9621
+ zipCrypto,
9622
+ crc32,
9623
+ compressionMethod,
9624
+ extraFieldAES,
9625
+ internalFileAttributes,
9626
+ extraField,
9627
+ uid,
9628
+ gid
9629
+ } = child.data;
9630
+ zipEntryMetadata = {
9631
+ externalFileAttributes,
9632
+ versionMadeBy,
9633
+ comment,
9634
+ lastModDate,
9635
+ creationDate,
9636
+ lastAccessDate,
9637
+ internalFileAttributes
9638
+ };
9639
+ const userExtraField = getUserExtraField(extraField);
9640
+ if (userExtraField) {
9641
+ zipEntryMetadata.extraField = userExtraField;
9642
+ }
9643
+ if (uid !== UNDEFINED_VALUE || gid !== UNDEFINED_VALUE) {
9644
+ Object.assign(zipEntryMetadata, {
9645
+ uid,
9646
+ gid,
9647
+ unixExtraFieldType: INFOZIP_EXTRA_FIELD_TYPE
9648
+ });
9649
+ }
9650
+ if (isPassThrough(child, options)) {
9651
+ let level, encryptionStrength;
9652
+ if (compressionMethod === 0) {
9653
+ level = 0;
9654
+ }
9655
+ if (extraFieldAES) {
9656
+ encryptionStrength = extraFieldAES.strength;
9657
+ }
9658
+ passThroughOptions = {
9659
+ passThrough: true,
9660
+ encrypted,
9661
+ zipCrypto,
9662
+ crc32,
9663
+ uncompressedSize,
9664
+ level,
9665
+ encryptionStrength,
9666
+ compressionMethod
9667
+ };
9668
+ }
9669
+ }
9670
+ const entryOptions = Object.assign({}, zipEntryMetadata, options, passThroughOptions, childOptions, { directory: child.directory });
9671
+ if (!child.directory && entryOptions.passThrough && entryOptions.uncompressedSize === UNDEFINED_VALUE) {
9672
+ throw new Error(ERR_INVALID_PASS_THROUGH);
9673
+ }
9674
+ return { name, entryOptions };
9675
+ }
9676
+
9677
+ function getDeterminedSize(child, passThrough) {
9678
+ const { reader } = child;
9679
+ if (reader && reader.size !== UNDEFINED_VALUE) {
9680
+ return reader.size;
9681
+ }
9682
+ return child.undeterminedSize ? UNDEFINED_VALUE : getExtractedSize(child, passThrough);
9683
+ }
9684
+
9685
+ function isPassThrough(child, options) {
9686
+ const { readerOptions } = options;
9687
+ return Boolean(!child.directory && (child.passThrough || (readerOptions && readerOptions.passThrough)));
9688
+ }
9689
+
9392
9690
  function getUserExtraField(extraField) {
9393
9691
  if (extraField) {
9394
9692
  const userExtraField = new Map();
@@ -9404,104 +9702,53 @@
9404
9702
  }
9405
9703
 
9406
9704
  async function exportZip(zipWriter, entry, totalSize, options, readers) {
9705
+ const { onstart, onprogress, onend, onentryprogress } = options;
9407
9706
  const selectedEntry = entry;
9408
- const entryOffsets = new Map();
9409
- await process(zipWriter, entry);
9410
-
9411
- async function process(zipWriter, entry) {
9412
- await exportChild();
9413
-
9414
- async function exportChild() {
9415
- if (options.bufferedWrite) {
9416
- const results = await Promise.allSettled(entry.children.map(processChild));
9417
- const errorResult = results.find(result => result.status == "rejected");
9418
- if (errorResult) {
9419
- throw errorResult.reason;
9420
- }
9421
- } else {
9422
- for (const child of entry.children) {
9423
- await processChild(child);
9424
- }
9425
- }
9707
+ const totalEntries = getTotalSize(entry.children, () => 1);
9708
+ let writtenSize = 0;
9709
+ let writtenEntries = 0;
9710
+ if (onstart) {
9711
+ await callHandler(onstart, totalSize);
9712
+ }
9713
+ if (options.bufferedWrite) {
9714
+ await processChildren(entry);
9715
+ } else {
9716
+ for (const child of entry.getChildren({ recursive: true })) {
9717
+ await addChild(child);
9426
9718
  }
9719
+ }
9720
+ if (onend) {
9721
+ await callHandler(onend, writtenSize);
9722
+ }
9427
9723
 
9428
- async function processChild(child) {
9429
- const name = options.relativePath ? child.getRelativeName(selectedEntry) : child.getFullname();
9430
- const childOptions = child.options || {};
9431
- let zipEntryOptions = {};
9432
- if (child.data instanceof Entry) {
9433
- const {
9434
- externalFileAttributes,
9435
- versionMadeBy,
9436
- comment,
9437
- lastModDate,
9438
- creationDate,
9439
- lastAccessDate,
9440
- uncompressedSize,
9441
- encrypted,
9442
- zipCrypto,
9443
- crc32,
9444
- compressionMethod,
9445
- extraFieldAES,
9446
- internalFileAttributes,
9447
- extraField,
9448
- uid,
9449
- gid
9450
- } = child.data;
9451
- zipEntryOptions = {
9452
- externalFileAttributes,
9453
- versionMadeBy,
9454
- comment,
9455
- lastModDate,
9456
- creationDate,
9457
- lastAccessDate,
9458
- internalFileAttributes
9459
- };
9460
- const userExtraField = getUserExtraField(extraField);
9461
- if (userExtraField) {
9462
- zipEntryOptions.extraField = userExtraField;
9463
- }
9464
- if (uid !== UNDEFINED_VALUE || gid !== UNDEFINED_VALUE) {
9465
- Object.assign(zipEntryOptions, {
9466
- uid,
9467
- gid,
9468
- unixExtraFieldType: options.unixExtraFieldType || INFOZIP_EXTRA_FIELD_TYPE
9469
- });
9470
- }
9471
- if (child.passThrough) {
9472
- let level, encryptionStrength;
9473
- if (compressionMethod === 0) {
9474
- level = 0;
9475
- }
9476
- if (extraFieldAES) {
9477
- encryptionStrength = extraFieldAES.strength;
9478
- }
9479
- zipEntryOptions = Object.assign(zipEntryOptions, {
9480
- passThrough: true,
9481
- encrypted,
9482
- zipCrypto,
9483
- crc32,
9484
- uncompressedSize,
9485
- level,
9486
- encryptionStrength,
9487
- compressionMethod
9488
- });
9724
+ async function processChildren(entry) {
9725
+ const results = await Promise.allSettled(entry.children.map(async child => {
9726
+ await addChild(child);
9727
+ await processChildren(child);
9728
+ }));
9729
+ const errorResult = results.find(result => result.status == "rejected");
9730
+ if (errorResult) {
9731
+ throw errorResult.reason;
9732
+ }
9733
+ }
9734
+
9735
+ async function addChild(child) {
9736
+ const { name, entryOptions } = getChildEntryOptions(child, selectedEntry, options);
9737
+ let entryWrittenSize = 0;
9738
+ const entryMetadata = await zipWriter.add(name, readers.get(child), Object.assign(entryOptions, {
9739
+ onstart: UNDEFINED_VALUE,
9740
+ onend: UNDEFINED_VALUE,
9741
+ onprogress: async indexProgress => {
9742
+ writtenSize += indexProgress - entryWrittenSize;
9743
+ entryWrittenSize = indexProgress;
9744
+ if (onprogress) {
9745
+ await callHandler(onprogress, writtenSize, totalSize);
9489
9746
  }
9490
9747
  }
9491
- await zipWriter.add(name, readers.get(child), Object.assign({}, options, zipEntryOptions, childOptions, {
9492
- directory: child.directory,
9493
- onprogress: async indexProgress => {
9494
- if (options.onprogress) {
9495
- entryOffsets.set(name, indexProgress);
9496
- try {
9497
- await options.onprogress(Array.from(entryOffsets.values()).reduce((previousValue, currentValue) => previousValue + currentValue), totalSize);
9498
- } catch {
9499
- // ignored
9500
- }
9501
- }
9502
- }
9503
- }));
9504
- await process(zipWriter, child);
9748
+ }));
9749
+ writtenEntries++;
9750
+ if (onentryprogress) {
9751
+ await callHandler(onentryprogress, writtenEntries, totalEntries, entryMetadata);
9505
9752
  }
9506
9753
  }
9507
9754
  }
@@ -9530,7 +9777,7 @@
9530
9777
  })
9531
9778
  );
9532
9779
  } else if (handle.kind == "directory") {
9533
- const directoryEntry = parentEntry.addDirectory(handle.name);
9780
+ const directoryEntry = parentEntry.addDirectory(handle.name, options);
9534
9781
  addedEntries.push(directoryEntry);
9535
9782
  for await (const childHandle of handle.values()) {
9536
9783
  await addFile(directoryEntry, childHandle, addedEntries, entryName);
@@ -9552,14 +9799,29 @@
9552
9799
  }
9553
9800
 
9554
9801
  async function exportFileSystemHandle(zipEntry, directoryHandle, options) {
9555
- const totalSize = getTotalSize([zipEntry], "uncompressedSize");
9556
- const writtenSizes = new Map();
9802
+ const { onstart, onprogress, onend } = options;
9557
9803
  const abortController = new AbortController();
9558
9804
  const { signal } = abortController;
9559
9805
  const releaseSignal = forwardAbort(options.signal, abortController);
9806
+ const getDataOptions = Object.assign({}, options, options.readerOptions, {
9807
+ signal,
9808
+ onstart: UNDEFINED_VALUE,
9809
+ onprogress: UNDEFINED_VALUE,
9810
+ onend: UNDEFINED_VALUE,
9811
+ preventClose: false
9812
+ });
9813
+ const totalSize = getTotalSize([zipEntry], entry => getExtractedSize(entry, getDataOptions.passThrough));
9560
9814
  const exportedEntryNames = [];
9815
+ let exportAborted = false;
9816
+ let writtenSize = 0;
9561
9817
  try {
9818
+ if (onstart) {
9819
+ await callHandler(onstart, totalSize);
9820
+ }
9562
9821
  await exportChildren(zipEntry, directoryHandle);
9822
+ if (onend) {
9823
+ await callHandler(onend, writtenSize);
9824
+ }
9563
9825
  } catch (error) {
9564
9826
  try {
9565
9827
  error.exportedEntryNames = exportedEntryNames;
@@ -9572,6 +9834,25 @@
9572
9834
  }
9573
9835
  return directoryHandle;
9574
9836
 
9837
+ function createProgressWritable(writable) {
9838
+ const writer = writable.getWriter();
9839
+ return new WritableStream({
9840
+ async write(chunk) {
9841
+ await writer.write(chunk);
9842
+ writtenSize += chunk.length;
9843
+ if (onprogress) {
9844
+ await callHandler(onprogress, writtenSize, totalSize);
9845
+ }
9846
+ },
9847
+ close() {
9848
+ return writer.close();
9849
+ },
9850
+ abort(reason) {
9851
+ return writer.abort(reason);
9852
+ }
9853
+ });
9854
+ }
9855
+
9575
9856
  async function exportChildren(entry, parentHandle) {
9576
9857
  if (options.concurrent) {
9577
9858
  const results = await Promise.allSettled(entry.children.map(child => exportChild(child, parentHandle)));
@@ -9590,10 +9871,10 @@
9590
9871
 
9591
9872
  async function exportChild(child, parentHandle) {
9592
9873
  if (signal.aborted) {
9593
- if (isExportAborted(signal.reason)) {
9874
+ if (exportAborted || isExportAborted(signal.reason)) {
9594
9875
  return;
9595
9876
  }
9596
- throw signal.reason;
9877
+ throw signal.reason === UNDEFINED_VALUE ? new DOMException(ERR_ABORTED, ABORT_ERROR_NAME) : signal.reason;
9597
9878
  }
9598
9879
  try {
9599
9880
  if (child.directory) {
@@ -9602,22 +9883,15 @@
9602
9883
  } else {
9603
9884
  const fileHandle = await parentHandle.getFileHandle(child.name, { create: true });
9604
9885
  const writable = await fileHandle.createWritable();
9605
- await child.getData({ writable }, Object.assign({}, options, {
9606
- signal,
9607
- onprogress: async progress => {
9608
- if (options.onprogress) {
9609
- writtenSizes.set(child.id, progress);
9610
- try {
9611
- await options.onprogress(Array.from(writtenSizes.values()).reduce((previousValue, currentValue) => previousValue + currentValue, 0), totalSize);
9612
- } catch {
9613
- // ignored
9614
- }
9615
- }
9616
- }
9617
- }));
9886
+ try {
9887
+ await child.getData({ writable: createProgressWritable(writable) }, getDataOptions);
9888
+ } catch (error) {
9889
+ throw exportAborted ? new Error(ERR_ABORT_EXPORT) : error;
9890
+ }
9618
9891
  exportedEntryNames.push(child.getRelativeName(zipEntry));
9619
9892
  }
9620
9893
  } catch (error) {
9894
+ exportAborted = true;
9621
9895
  abortController.abort(new Error(ERR_ABORT_EXPORT));
9622
9896
  try {
9623
9897
  if (error.entryName === UNDEFINED_VALUE) {
@@ -9689,6 +9963,21 @@
9689
9963
  fs.root = new ZipDirectoryEntry(fs);
9690
9964
  }
9691
9965
 
9966
+ function collectChildren(directory, recursive) {
9967
+ const children = [];
9968
+ const pendingDirectories = [directory];
9969
+ let directoryIndex = 0;
9970
+ while (directoryIndex < pendingDirectories.length) {
9971
+ for (const child of pendingDirectories[directoryIndex++].children) {
9972
+ children.push(child);
9973
+ if (recursive) {
9974
+ pendingDirectories.push(child);
9975
+ }
9976
+ }
9977
+ }
9978
+ return children;
9979
+ }
9980
+
9692
9981
  function registerEntries(fs, entry) {
9693
9982
  const pendingEntries = [entry];
9694
9983
  while (pendingEntries.length) {
@@ -9807,6 +10096,7 @@
9807
10096
  exports.BlobWriter = BlobWriter;
9808
10097
  exports.Data64URIReader = Data64URIReader;
9809
10098
  exports.Data64URIWriter = Data64URIWriter;
10099
+ exports.ERR_ABORTED = ERR_ABORTED;
9810
10100
  exports.ERR_AMBIGUOUS_ARCHIVE = ERR_AMBIGUOUS_ARCHIVE;
9811
10101
  exports.ERR_BAD_FORMAT = ERR_BAD_FORMAT;
9812
10102
  exports.ERR_CENTRAL_DIRECTORY_NOT_FOUND = ERR_CENTRAL_DIRECTORY_NOT_FOUND;
@@ -9838,6 +10128,7 @@
9838
10128
  exports.ERR_INVALID_MSDOS_DATA = ERR_INVALID_MSDOS_DATA;
9839
10129
  exports.ERR_INVALID_PASSWORD = ERR_INVALID_PASSWORD;
9840
10130
  exports.ERR_INVALID_PASSWORD_TYPE = ERR_INVALID_PASSWORD_TYPE;
10131
+ exports.ERR_INVALID_PASS_THROUGH = ERR_INVALID_PASS_THROUGH;
9841
10132
  exports.ERR_INVALID_SIGNATURE = ERR_INVALID_SIGNATURE;
9842
10133
  exports.ERR_INVALID_SIGNATURE_DATA = ERR_INVALID_SIGNATURE_DATA;
9843
10134
  exports.ERR_INVALID_STRICTNESS = ERR_INVALID_STRICTNESS;
@@ -9855,11 +10146,13 @@
9855
10146
  exports.ERR_SPLIT_ZIP_FILE = ERR_SPLIT_ZIP_FILE;
9856
10147
  exports.ERR_UNDEFINED_READER = ERR_UNDEFINED_READER;
9857
10148
  exports.ERR_UNDEFINED_UNCOMPRESSED_SIZE = ERR_UNDEFINED_UNCOMPRESSED_SIZE;
10149
+ exports.ERR_UNDETERMINED_SIZE = ERR_UNDETERMINED_SIZE;
9858
10150
  exports.ERR_UNSAFE_FILENAME = ERR_UNSAFE_FILENAME;
9859
10151
  exports.ERR_UNSUPPORTED_COMPRESSION = ERR_UNSUPPORTED_COMPRESSION$1;
9860
10152
  exports.ERR_UNSUPPORTED_CONTEXT = ERR_UNSUPPORTED_CONTEXT;
9861
10153
  exports.ERR_UNSUPPORTED_CRYPTO_API = ERR_UNSUPPORTED_CRYPTO_API;
9862
10154
  exports.ERR_UNSUPPORTED_ENCRYPTION = ERR_UNSUPPORTED_ENCRYPTION;
10155
+ exports.ERR_UNSUPPORTED_ENCRYPTION_PASS_THROUGH = ERR_UNSUPPORTED_ENCRYPTION_PASS_THROUGH;
9863
10156
  exports.ERR_UNSUPPORTED_ENCRYPTION_USDZ = ERR_UNSUPPORTED_ENCRYPTION_USDZ;
9864
10157
  exports.ERR_UNSUPPORTED_FORMAT = ERR_UNSUPPORTED_FORMAT;
9865
10158
  exports.ERR_WORKER_STARTUP_TIMEOUT = ERR_WORKER_STARTUP_TIMEOUT;