@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.
@@ -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() {
@@ -3350,8 +3347,10 @@
3350
3347
  async pull(controller) {
3351
3348
  const dataSize = size === UNDEFINED_VALUE ? chunkSize : Math.min(chunkSize, size - chunkOffset);
3352
3349
  const data = await readUint8Array(reader, offset + chunkOffset, dataSize);
3353
- controller.enqueue(data);
3354
- if ((chunkOffset + chunkSize > size) || (size === UNDEFINED_VALUE && !data.length && dataSize)) {
3350
+ if (data.length) {
3351
+ controller.enqueue(data);
3352
+ }
3353
+ if ((chunkOffset + chunkSize >= size) || (size === UNDEFINED_VALUE && !data.length && dataSize)) {
3355
3354
  controller.close();
3356
3355
  } else {
3357
3356
  chunkOffset += chunkSize;
@@ -3429,6 +3428,7 @@
3429
3428
  constructor(contentType) {
3430
3429
  super();
3431
3430
  Object.assign(this, {
3431
+ contentType,
3432
3432
  data: "data:" + (contentType || "") + ";base64,",
3433
3433
  pending: []
3434
3434
  });
@@ -3530,6 +3530,7 @@
3530
3530
  return transformStream.writable;
3531
3531
  }
3532
3532
  });
3533
+ writer.contentType = contentType;
3533
3534
  writer.blob = streamToBlob(transformStream.readable, contentType);
3534
3535
  writer.blob.catch(() => { });
3535
3536
  }
@@ -3546,6 +3547,26 @@
3546
3547
  }
3547
3548
  }
3548
3549
 
3550
+ function getTextSize(text) {
3551
+ let size = 0;
3552
+ for (let indexCharacter = 0; indexCharacter < text.length; indexCharacter++) {
3553
+ const characterCode = text.charCodeAt(indexCharacter);
3554
+ if (characterCode < 0x80) {
3555
+ size += 1;
3556
+ } else if (characterCode < 0x800) {
3557
+ size += 2;
3558
+ } else if (characterCode < 0xd800 || characterCode >= 0xe000) {
3559
+ size += 3;
3560
+ } else if (characterCode < 0xdc00 && (text.charCodeAt(indexCharacter + 1) & 0xfc00) == 0xdc00) {
3561
+ size += 4;
3562
+ indexCharacter++;
3563
+ } else {
3564
+ size += 3;
3565
+ }
3566
+ }
3567
+ return size;
3568
+ }
3569
+
3549
3570
  class TextWriter extends BlobWriter {
3550
3571
 
3551
3572
  constructor(encoding) {
@@ -4209,6 +4230,10 @@
4209
4230
  }
4210
4231
  }
4211
4232
 
4233
+ function ownsWritable(writer) {
4234
+ return Boolean(writer && writer.getData);
4235
+ }
4236
+
4212
4237
  function isHttpFamily(url) {
4213
4238
  const { baseURI } = getConfiguration();
4214
4239
  const { protocol } = new URL(url, baseURI);
@@ -4353,6 +4378,8 @@
4353
4378
  const PROPERTY_NAME_RAW_CREATION_DATE = "rawCreationDate";
4354
4379
  const PROPERTY_NAME_INTERNAL_FILE_ATTRIBUTES = "internalFileAttributes";
4355
4380
  const PROPERTY_NAME_EXTERNAL_FILE_ATTRIBUTES = "externalFileAttributes";
4381
+ const PROPERTY_NAME_DEPRECATED_INTERNAL_FILE_ATTRIBUTES = "internalFileAttribute";
4382
+ const PROPERTY_NAME_DEPRECATED_EXTERNAL_FILE_ATTRIBUTES = "externalFileAttribute";
4356
4383
  const PROPERTY_NAME_MSDOS_ATTRIBUTES_RAW = "msdosAttributesRaw";
4357
4384
  const PROPERTY_NAME_MSDOS_ATTRIBUTES = "msdosAttributes";
4358
4385
  const PROPERTY_NAME_MS_DOS_COMPATIBLE = "msDosCompatible";
@@ -4363,6 +4390,7 @@
4363
4390
  const PROPERTY_NAME_ZIPCRYPTO = "zipCrypto";
4364
4391
  const PROPERTY_NAME_DIRECTORY = "directory";
4365
4392
  const PROPERTY_NAME_EXECUTABLE = "executable";
4393
+ const PROPERTY_NAME_SYMLINK = "symlink";
4366
4394
  const PROPERTY_NAME_COMPRESSION_METHOD = "compressionMethod";
4367
4395
  const PROPERTY_NAME_SIGNATURE = "signature";
4368
4396
  const PROPERTY_NAME_CRC32 = "crc32";
@@ -4406,6 +4434,8 @@
4406
4434
  PROPERTY_NAME_DISK_NUMBER_START,
4407
4435
  PROPERTY_NAME_INTERNAL_FILE_ATTRIBUTES,
4408
4436
  PROPERTY_NAME_EXTERNAL_FILE_ATTRIBUTES,
4437
+ PROPERTY_NAME_DEPRECATED_INTERNAL_FILE_ATTRIBUTES,
4438
+ PROPERTY_NAME_DEPRECATED_EXTERNAL_FILE_ATTRIBUTES,
4409
4439
  PROPERTY_NAME_MSDOS_ATTRIBUTES_RAW,
4410
4440
  PROPERTY_NAME_MSDOS_ATTRIBUTES,
4411
4441
  PROPERTY_NAME_MS_DOS_COMPATIBLE,
@@ -4416,6 +4446,7 @@
4416
4446
  PROPERTY_NAME_ZIPCRYPTO,
4417
4447
  PROPERTY_NAME_DIRECTORY,
4418
4448
  PROPERTY_NAME_EXECUTABLE,
4449
+ PROPERTY_NAME_SYMLINK,
4419
4450
  PROPERTY_NAME_COMPRESSION_METHOD,
4420
4451
  PROPERTY_NAME_SIGNATURE,
4421
4452
  PROPERTY_NAME_CRC32,
@@ -4878,15 +4909,18 @@
4878
4909
  const setuid = Boolean(fileEntry.unixMode & FILE_ATTR_UNIX_SETUID_MASK);
4879
4910
  const setgid = Boolean(fileEntry.unixMode & FILE_ATTR_UNIX_SETGID_MASK);
4880
4911
  const sticky = Boolean(fileEntry.unixMode & FILE_ATTR_UNIX_STICKY_MASK);
4881
- const executable = (fileEntry.unixMode !== UNDEFINED_VALUE)
4912
+ const unixType = fileEntry.unixMode === UNDEFINED_VALUE ? unixExternalUpper : fileEntry.unixMode;
4913
+ const symlink = (unixType & FILE_ATTR_UNIX_TYPE_MASK) == FILE_ATTR_UNIX_TYPE_SYMLINK;
4914
+ const executable = !symlink && ((fileEntry.unixMode !== UNDEFINED_VALUE)
4882
4915
  ? ((fileEntry.unixMode & FILE_ATTR_UNIX_EXECUTABLE_MASK) != 0)
4883
- : (unixCompatible && ((unixExternalUpper & FILE_ATTR_UNIX_EXECUTABLE_MASK) != 0));
4916
+ : (unixCompatible && ((unixExternalUpper & FILE_ATTR_UNIX_EXECUTABLE_MASK) != 0)));
4884
4917
  const modeIsDir = fileEntry.unixMode !== UNDEFINED_VALUE && ((fileEntry.unixMode & FILE_ATTR_UNIX_TYPE_MASK) == FILE_ATTR_UNIX_TYPE_DIR);
4885
4918
  const upperIsDir = ((unixExternalUpper & FILE_ATTR_UNIX_TYPE_MASK) == FILE_ATTR_UNIX_TYPE_DIR);
4886
4919
  Object.assign(fileEntry, {
4887
4920
  setuid,
4888
4921
  setgid,
4889
4922
  sticky,
4923
+ symlink,
4890
4924
  unixExternalUpper,
4891
4925
  internalFileAttribute: fileEntry.internalFileAttributes,
4892
4926
  externalFileAttribute: fileEntry.externalFileAttributes,
@@ -4952,6 +4986,10 @@
4952
4986
  }
4953
4987
 
4954
4988
  async close() {
4989
+ const { reader } = this;
4990
+ if (!reader.readUint8Array && reader.readable && !reader.readable.locked) {
4991
+ await reader.readable.cancel();
4992
+ }
4955
4993
  }
4956
4994
  }
4957
4995
 
@@ -5176,7 +5214,7 @@
5176
5214
  throw error;
5177
5215
  }
5178
5216
  } finally {
5179
- const preventClose = getOptionValue$1(zipEntry, options, OPTION_PREVENT_CLOSE);
5217
+ const preventClose = !ownsWritable(writer) && getOptionValue$1(zipEntry, options, OPTION_PREVENT_CLOSE);
5180
5218
  if (!preventClose && writable && !writable.locked) {
5181
5219
  const writableWriter = writable.getWriter();
5182
5220
  if (abortError) {
@@ -5420,8 +5458,8 @@
5420
5458
  return;
5421
5459
  }
5422
5460
  const extraFieldView = getDataView(extraField.data);
5423
- const lastAccessDate = new Date(getUint32(extraFieldView, 0) * 1000);
5424
- const lastModDate = new Date(getUint32(extraFieldView, 4) * 1000);
5461
+ const lastAccessDate = new Date((getUint32(extraFieldView, 0) | 0) * 1000);
5462
+ const lastModDate = new Date((getUint32(extraFieldView, 4) | 0) * 1000);
5425
5463
  const extraFieldData = { lastAccessDate, lastModDate };
5426
5464
  if (extraField.data.length >= 12) {
5427
5465
  extraFieldData.uid = getUint16(extraFieldView, 8);
@@ -5852,6 +5890,7 @@
5852
5890
  const ERR_INVALID_VERSION = "Version exceeds 65535";
5853
5891
  const ERR_INVALID_ENCRYPTION_STRENGTH = "The strength must equal 1, 2, or 3";
5854
5892
  const ERR_UNSUPPORTED_ENCRYPTION_USDZ = "Encryption is not supported in USDZ files";
5893
+ const ERR_UNSUPPORTED_ENCRYPTION_PASS_THROUGH = "Encryption is not supported when the 'passThrough' option is set";
5855
5894
  const ERR_INVALID_EXTRAFIELD_TYPE = "Extra field type exceeds 65535";
5856
5895
  const ERR_INVALID_EXTRAFIELD_DATA = "Extra field data exceeds 64KB";
5857
5896
  const ERR_UNSUPPORTED_COMPRESSION = "Compression method not supported";
@@ -5861,6 +5900,7 @@
5861
5900
  const MAX_NTFS_TIME = BigInt("0x7fffffffffffffff");
5862
5901
  const ERR_UNSUPPORTED_FORMAT = "Zip64 is not supported (set the 'zip64' option to 'true')";
5863
5902
  const ERR_UNDEFINED_UNCOMPRESSED_SIZE = "Undefined uncompressed size";
5903
+ const ERR_UNDETERMINED_SIZE = "Undetermined size";
5864
5904
  const ERR_UNDEFINED_READER = "Undefined reader";
5865
5905
  const ERR_ZIP_NOT_EMPTY = "Zip file not empty";
5866
5906
  const ERR_INVALID_UID = "Invalid uid (must be integer 0..2^32-1)";
@@ -6068,7 +6108,7 @@
6068
6108
  await Promise.allSettled(Array.from(pendingAddFileCalls));
6069
6109
  }
6070
6110
  await closeFile(zipWriter, comment, options);
6071
- const preventClose = getOptionValue(zipWriter, options, OPTION_PREVENT_CLOSE);
6111
+ const preventClose = !ownsWritable(writer) && getOptionValue(zipWriter, options, OPTION_PREVENT_CLOSE);
6072
6112
  if (!preventClose) {
6073
6113
  await writable.getWriter().close();
6074
6114
  }
@@ -6227,7 +6267,7 @@
6227
6267
  if (versionMadeBy > MAX_16_BITS) {
6228
6268
  throw new Error(ERR_INVALID_VERSION);
6229
6269
  }
6230
- let externalFileAttributes = getOptionValue(zipWriter, options, PROPERTY_NAME_EXTERNAL_FILE_ATTRIBUTES);
6270
+ let externalFileAttributes = getAliasedOptionValue(zipWriter, options, PROPERTY_NAME_EXTERNAL_FILE_ATTRIBUTES, PROPERTY_NAME_DEPRECATED_EXTERNAL_FILE_ATTRIBUTES);
6231
6271
  const externalFileAttributesProvided = externalFileAttributes !== UNDEFINED_VALUE;
6232
6272
  if (!externalFileAttributesProvided) {
6233
6273
  externalFileAttributes = 0;
@@ -6275,7 +6315,9 @@
6275
6315
  }
6276
6316
  if (!externalFileAttributesProvided || unixModeProvided) {
6277
6317
  if (directory) {
6278
- unixMode |= FILE_ATTR_UNIX_TYPE_DIR;
6318
+ unixMode = (unixMode & ~FILE_ATTR_UNIX_TYPE_MASK) | FILE_ATTR_UNIX_TYPE_DIR;
6319
+ } else if (!(unixMode & FILE_ATTR_UNIX_TYPE_MASK)) {
6320
+ unixMode |= FILE_ATTR_UNIX_TYPE_FILE;
6279
6321
  }
6280
6322
  externalFileAttributes = ((unixMode & MAX_16_BITS) << 16) | (externalFileAttributes & MAX_16_BITS);
6281
6323
  }
@@ -6328,15 +6370,12 @@
6328
6370
  const lastModDate = getOptionValue(zipWriter, options, PROPERTY_NAME_LAST_MODIFICATION_DATE, new Date());
6329
6371
  const lastAccessDate = getOptionValue(zipWriter, options, PROPERTY_NAME_LAST_ACCESS_DATE);
6330
6372
  const creationDate = getOptionValue(zipWriter, options, PROPERTY_NAME_CREATION_DATE);
6331
- const internalFileAttributes = getOptionValue(zipWriter, options, PROPERTY_NAME_INTERNAL_FILE_ATTRIBUTES, 0);
6373
+ const internalFileAttributes = getAliasedOptionValue(zipWriter, options, PROPERTY_NAME_INTERNAL_FILE_ATTRIBUTES, PROPERTY_NAME_DEPRECATED_INTERNAL_FILE_ATTRIBUTES, 0);
6332
6374
  const passThrough = getOptionValue(zipWriter, options, OPTION_PASS_THROUGH);
6333
- let password, rawPassword;
6334
- if (!passThrough) {
6335
- password = getOptionValue(zipWriter, options, OPTION_PASSWORD);
6336
- rawPassword = getOptionValue(zipWriter, options, OPTION_RAW_PASSWORD);
6337
- if ((password && typeof password != STRING_TYPE) || (rawPassword && !(rawPassword instanceof Uint8Array))) {
6338
- throw new Error(ERR_INVALID_PASSWORD_TYPE);
6339
- }
6375
+ const password = getOptionValue(zipWriter, options, OPTION_PASSWORD);
6376
+ const rawPassword = getOptionValue(zipWriter, options, OPTION_RAW_PASSWORD);
6377
+ if ((password && typeof password != STRING_TYPE) || (rawPassword && !(rawPassword instanceof Uint8Array))) {
6378
+ throw new Error(ERR_INVALID_PASSWORD_TYPE);
6340
6379
  }
6341
6380
  const encryptionStrength = getNumberOptionValue(zipWriter, options, OPTION_ENCRYPTION_STRENGTH, 3);
6342
6381
  const zipCrypto = getOptionValue(zipWriter, options, PROPERTY_NAME_ZIPCRYPTO);
@@ -6449,14 +6488,24 @@
6449
6488
  }
6450
6489
 
6451
6490
  async function resolveSizes(zipWriter, reader, { resolvedOptions: metadata }, options) {
6491
+ if (metadata.passThrough && !reader && !getOptionValue(zipWriter, options, PROPERTY_NAME_DIRECTORY)) {
6492
+ throw new Error(ERR_UNDEFINED_READER);
6493
+ }
6494
+ let contentSize;
6495
+ if (reader) {
6496
+ reader = new GenericReader(reader);
6497
+ await initStream(reader);
6498
+ ({ size: contentSize } = reader);
6499
+ }
6500
+ return Object.assign({ reader }, resolveEntrySizes(zipWriter, Boolean(reader), contentSize, metadata, options));
6501
+ }
6502
+
6503
+ function resolveEntrySizes(zipWriter, hasContent, contentSize, metadata, options) {
6452
6504
  const { passThrough, zipCrypto, password, rawPassword, encryptionStrength } = metadata;
6453
6505
  let { dataDescriptor, zip64, level, compressionMethod } = metadata;
6454
6506
  let maximumCompressedSize = 0;
6455
6507
  let uncompressedSize = 0;
6456
- if (passThrough) {
6457
- if (!reader) {
6458
- throw new Error(ERR_UNDEFINED_READER);
6459
- }
6508
+ if (passThrough && hasContent) {
6460
6509
  uncompressedSize = options[PROPERTY_NAME_UNCOMPRESSED_SIZE];
6461
6510
  if (uncompressedSize === UNDEFINED_VALUE) {
6462
6511
  throw new Error(ERR_UNDEFINED_UNCOMPRESSED_SIZE);
@@ -6464,29 +6513,30 @@
6464
6513
  }
6465
6514
  const zip64Enabled = zip64 === true;
6466
6515
  const encrypted = getOptionValue(zipWriter, options, PROPERTY_NAME_ENCRYPTED);
6467
- const encryptedEntry = Boolean(reader) && (Boolean((password && getLength(password)) || (rawPassword && getLength(rawPassword))) || (passThrough && encrypted));
6468
- if (!reader) {
6516
+ if (hasContent && passThrough && !encrypted && getLength(password, rawPassword)) {
6517
+ throw new Error(ERR_UNSUPPORTED_ENCRYPTION_PASS_THROUGH);
6518
+ }
6519
+ const encryptedEntry = hasContent && (Boolean((password && getLength(password)) || (rawPassword && getLength(rawPassword))) || (passThrough && encrypted));
6520
+ if (!hasContent) {
6469
6521
  level = 0;
6470
6522
  compressionMethod = COMPRESSION_METHOD_STORE;
6471
6523
  }
6472
6524
  const encryptionOverhead = encryptedEntry ? (zipCrypto ? 12 : 16 + encryptionStrength * 4) : 0;
6473
- if (reader) {
6474
- reader = new GenericReader(reader);
6475
- await initStream(reader);
6525
+ if (hasContent) {
6476
6526
  if (!passThrough) {
6477
- if (reader.size === UNDEFINED_VALUE) {
6527
+ if (contentSize === UNDEFINED_VALUE) {
6478
6528
  dataDescriptor = true;
6479
6529
  if (zip64 || zip64 === UNDEFINED_VALUE) {
6480
6530
  zip64 = true;
6481
6531
  uncompressedSize = maximumCompressedSize = MAX_32_BITS + 1;
6482
6532
  }
6483
6533
  } else {
6484
- options.uncompressedSize = uncompressedSize = reader.size;
6485
- maximumCompressedSize = getMaximumCompressedSize(uncompressedSize) + encryptionOverhead;
6534
+ options.uncompressedSize = uncompressedSize = contentSize;
6535
+ maximumCompressedSize = (isCompressed(compressionMethod, level) ? getMaximumCompressedSize(uncompressedSize) : uncompressedSize) + encryptionOverhead;
6486
6536
  }
6487
6537
  } else {
6488
6538
  options.uncompressedSize = uncompressedSize;
6489
- maximumCompressedSize = getMaximumCompressedSize(uncompressedSize) + encryptionOverhead;
6539
+ maximumCompressedSize = contentSize === UNDEFINED_VALUE ? getMaximumCompressedSize(uncompressedSize) + encryptionOverhead : contentSize;
6490
6540
  }
6491
6541
  }
6492
6542
  const zip64UncompressedSize = zip64Enabled || uncompressedSize >= MAX_32_BITS;
@@ -6500,7 +6550,7 @@
6500
6550
  }
6501
6551
  zip64 = zip64 || false;
6502
6552
  return {
6503
- reader,
6553
+ maximumCompressedSize,
6504
6554
  resolvedOptions: {
6505
6555
  dataDescriptor,
6506
6556
  zip64,
@@ -6514,6 +6564,78 @@
6514
6564
  };
6515
6565
  }
6516
6566
 
6567
+ async function getEntriesSize(writerOptions, entries, writeOrderGuaranteed, comment) {
6568
+ const zipWriter = { options: writerOptions, config: getConfiguration() };
6569
+ if (writerOptions[OPTION_SIGN_CENTRAL_DIRECTORY]) {
6570
+ throw new Error(ERR_UNDETERMINED_SIZE);
6571
+ }
6572
+ const commentLength = getLength(comment);
6573
+ if (commentLength > MAX_16_BITS) {
6574
+ throw new Error(ERR_INVALID_COMMENT);
6575
+ }
6576
+ const usdz = writerOptions[OPTION_USDZ];
6577
+ const files = new Map();
6578
+ let layoutDependsOnWriteOrder = Boolean(usdz);
6579
+ let offset = 0;
6580
+ for (const entry of entries) {
6581
+ let { name } = entry;
6582
+ const { size } = entry;
6583
+ const options = Object.assign({}, entry.options);
6584
+ name = name.trim();
6585
+ if (getOptionValue(zipWriter, options, PROPERTY_NAME_DIRECTORY) && !name.endsWith(DIRECTORY_SIGNATURE)) {
6586
+ name += DIRECTORY_SIGNATURE;
6587
+ }
6588
+ const attributesInfo = resolveAttributes(zipWriter, name, options);
6589
+ ({ name } = attributesInfo);
6590
+ const { resolvedOptions: metadata } = resolveMetadata(zipWriter, name, options);
6591
+ if (metadata.level != 0 && metadata.compressionMethod === UNDEFINED_VALUE &&
6592
+ !metadata.passThrough && !(await supportsDeflate(zipWriter.config))) {
6593
+ metadata.level = 0;
6594
+ }
6595
+ const hasContent = !getOptionValue(zipWriter, options, PROPERTY_NAME_DIRECTORY);
6596
+ if (hasContent && size === UNDEFINED_VALUE) {
6597
+ throw new Error(ERR_UNDETERMINED_SIZE);
6598
+ }
6599
+ const { maximumCompressedSize, resolvedOptions: sizes } = resolveEntrySizes(zipWriter, hasContent, size, metadata, options);
6600
+ if (hasContent && !metadata.passThrough && isCompressed(sizes.compressionMethod, sizes.level)) {
6601
+ throw new Error(ERR_UNDETERMINED_SIZE);
6602
+ }
6603
+ const entryOptions = Object.assign({}, options, attributesInfo.resolvedOptions, metadata, sizes);
6604
+ const headerInfo = getHeaderInfo(entryOptions);
6605
+ const dataDescriptorInfo = getDataDescriptorInfo(entryOptions);
6606
+ const entryInfo = {
6607
+ headerInfo,
6608
+ metadataSize: getLength(headerInfo.localHeaderArray, dataDescriptorInfo.dataDescriptorArray)
6609
+ };
6610
+ if (usdz) {
6611
+ appendExtraFieldUSDZ(entryInfo, offset);
6612
+ }
6613
+ const compressedSize = hasContent ? maximumCompressedSize : 0;
6614
+ if (offset >= MAX_32_BITS) {
6615
+ layoutDependsOnWriteOrder = true;
6616
+ }
6617
+ files.set(name, Object.assign({}, entryOptions, headerInfo, {
6618
+ offset,
6619
+ diskNumberStart: 0,
6620
+ compressedSize
6621
+ }));
6622
+ offset += entryInfo.metadataSize + compressedSize;
6623
+ }
6624
+ if (layoutDependsOnWriteOrder && !writeOrderGuaranteed) {
6625
+ throw new Error(ERR_UNDETERMINED_SIZE);
6626
+ }
6627
+ const directoryDataLength = createDirectoryRecords(files);
6628
+ let zip64 = getOptionValue(zipWriter, writerOptions, PROPERTY_NAME_ZIP64);
6629
+ if (offset >= MAX_32_BITS || directoryDataLength >= MAX_32_BITS || files.size >= MAX_16_BITS) {
6630
+ if (zip64 === false) {
6631
+ throw new Error(ERR_UNSUPPORTED_FORMAT);
6632
+ } else {
6633
+ zip64 = true;
6634
+ }
6635
+ }
6636
+ return offset + directoryDataLength + commentLength + (zip64 ? ZIP64_END_OF_CENTRAL_DIR_TOTAL_LENGTH : END_OF_CENTRAL_DIR_LENGTH);
6637
+ }
6638
+
6517
6639
  async function getFileEntry(zipWriter, name, reader, entryInfo, options) {
6518
6640
  const {
6519
6641
  files,
@@ -6885,9 +7007,7 @@
6885
7007
  crc32
6886
7008
  } = options;
6887
7009
  let { version, compressionMethod } = options;
6888
- const compressed = !directory && (compressionMethod === UNDEFINED_VALUE
6889
- ? (level === UNDEFINED_VALUE || level > 0)
6890
- : compressionMethod !== COMPRESSION_METHOD_STORE);
7010
+ const compressed = !directory && isCompressed(compressionMethod, level);
6891
7011
  let rawLocalExtraFieldZip64;
6892
7012
  const uncompressedFile = passThrough || !compressed;
6893
7013
  const zip64ExtraFieldComplete = zip64 && (options.bufferedWrite || !dataDescriptor || ((!zip64UncompressedSize && !zip64CompressedSize) || uncompressedFile));
@@ -7574,6 +7694,16 @@
7574
7694
  return result === UNDEFINED_VALUE ? defaultValue : result;
7575
7695
  }
7576
7696
 
7697
+ function getAliasedOptionValue(zipWriter, options, name, deprecatedName, defaultValue) {
7698
+ const value = getAliasedValue(options, name, deprecatedName);
7699
+ const result = value === UNDEFINED_VALUE ? getAliasedValue(zipWriter.options, name, deprecatedName) : value;
7700
+ return result === UNDEFINED_VALUE ? defaultValue : result;
7701
+ }
7702
+
7703
+ function getAliasedValue(options, name, deprecatedName) {
7704
+ return options[name] === UNDEFINED_VALUE ? options[deprecatedName] : options[name];
7705
+ }
7706
+
7577
7707
  function getNumberOptionValue(zipWriter, options, name, defaultValue) {
7578
7708
  return toNumber(getOptionValue(zipWriter, options, name, defaultValue));
7579
7709
  }
@@ -7586,6 +7716,12 @@
7586
7716
  return uncompressedSize + (5 * (Math.floor(uncompressedSize / 16383) + 1));
7587
7717
  }
7588
7718
 
7719
+ function isCompressed(compressionMethod, level) {
7720
+ return compressionMethod === UNDEFINED_VALUE
7721
+ ? (level === UNDEFINED_VALUE || level > 0)
7722
+ : compressionMethod !== COMPRESSION_METHOD_STORE;
7723
+ }
7724
+
7589
7725
  function setUint8(view, offset, value) {
7590
7726
  view.setUint8(offset, value);
7591
7727
  }
@@ -8234,7 +8370,10 @@
8234
8370
 
8235
8371
  const ERR_ENTRY_EXISTS = "Entry filename already exists";
8236
8372
  const ERR_READABLE_CONSUMED = "Readable stream already consumed";
8373
+ const ERR_INVALID_PASS_THROUGH = "Invalid passThrough option (use readerOptions.passThrough or set uncompressedSize for each entry)";
8237
8374
  const ERR_ABORT_EXPORT = "zipjs-abort-export";
8375
+ const ERR_ABORTED = "The operation was aborted";
8376
+ const ABORT_ERROR_NAME = "AbortError";
8238
8377
  const INFOZIP_EXTRA_FIELD_TYPE = "infozip";
8239
8378
  const INTERPRETED_EXTRA_FIELD_TYPES = new Set([
8240
8379
  EXTRAFIELD_TYPE_ZIP64,
@@ -8269,6 +8408,7 @@
8269
8408
  parent,
8270
8409
  children: [],
8271
8410
  uncompressedSize: params.uncompressedSize || 0,
8411
+ undeterminedSize: params.undeterminedSize || params.uncompressedSize === UNDEFINED_VALUE,
8272
8412
  passThrough: params.passThrough
8273
8413
  });
8274
8414
  if (parent || !fs.root) {
@@ -8336,16 +8476,17 @@
8336
8476
 
8337
8477
  async getData(writer, options = {}) {
8338
8478
  const zipEntry = this;
8339
- if (!writer || (writer.constructor == zipEntry.Writer && zipEntry.data)) {
8479
+ if (!writer || (writer.constructor == zipEntry.Writer && zipEntry.data && keepsContentType(writer, zipEntry.data))) {
8340
8480
  return zipEntry.data;
8341
8481
  } else {
8342
8482
  const reader = zipEntry.reader = createReader(zipEntry.Reader, zipEntry.data, options);
8343
- const uncompressedSize = zipEntry.data ? zipEntry.data.uncompressedSize : reader.size;
8344
- await Promise.all([initStream(reader), initStream(writer, uncompressedSize)]);
8345
- const { readable } = reader;
8483
+ const dataSize = zipEntry.uncompressedSize || reader.size;
8484
+ await Promise.all([initStream(reader), initStream(writer, dataSize)]);
8346
8485
  const { signal } = options;
8486
+ const readable = createProgressReadable(zipEntry, reader, options, signal);
8487
+ const preventClose = !ownsWritable(writer) && Boolean(options.preventClose);
8347
8488
  zipEntry.uncompressedSize = reader.size;
8348
- await toCompatibleReadable(readable).pipeTo(toCompatibleWritable(writer.writable), { signal });
8489
+ await toCompatibleReadable(readable).pipeTo(toCompatibleWritable(writer.writable), { signal, preventClose, preventAbort: preventClose });
8349
8490
  return writer.getData ? writer.getData() : writer.writable;
8350
8491
  }
8351
8492
  }
@@ -8476,7 +8617,7 @@
8476
8617
  Reader: TextReader,
8477
8618
  Writer: TextWriter,
8478
8619
  options,
8479
- uncompressedSize: text.length
8620
+ uncompressedSize: getTextSize(text)
8480
8621
  });
8481
8622
  }
8482
8623
 
@@ -8605,10 +8746,16 @@
8605
8746
  }
8606
8747
 
8607
8748
  async importZip(reader, options = {}) {
8608
- await initStream(reader);
8609
- const zipReader = new ZipReader(reader, options);
8749
+ let zipReader;
8750
+ if (reader && typeof reader.getEntries == FUNCTION_TYPE) {
8751
+ zipReader = reader;
8752
+ options = Object.assign({}, zipReader.options, options);
8753
+ } else {
8754
+ await initStream(reader);
8755
+ zipReader = new ZipReader(reader, options);
8756
+ }
8610
8757
  const importedEntries = [];
8611
- const entries = await zipReader.getEntries();
8758
+ const entries = await zipReader.getEntries(options);
8612
8759
  for (const entry of entries) {
8613
8760
  let parent = this;
8614
8761
  try {
@@ -8630,7 +8777,7 @@
8630
8777
  importedEntries.push(addChild(parent, name, {
8631
8778
  data: entry,
8632
8779
  Reader: getZipBlobReader(Object.assign({}, options)),
8633
- uncompressedSize: entry.uncompressedSize,
8780
+ uncompressedSize: options.passThrough ? entry.compressedSize : entry.uncompressedSize,
8634
8781
  passThrough: options.passThrough
8635
8782
  }));
8636
8783
  } else {
@@ -8672,11 +8819,25 @@
8672
8819
  }
8673
8820
  const [readers] = await Promise.all([initReaders(zipEntry, options.readerOptions), initStream(writer)]);
8674
8821
  const zipWriter = new ZipWriter(writer, options);
8675
- await exportZip(zipWriter, zipEntry, getTotalSize([zipEntry], "uncompressedSize"), options, readers);
8676
- await zipWriter.close();
8822
+ await exportZip(zipWriter, zipEntry, getTotalSize([zipEntry], getUncompressedSize), options, readers);
8823
+ await zipWriter.close(options.globalComment);
8677
8824
  return writer.getData ? writer.getData() : writer.writable;
8678
8825
  }
8679
8826
 
8827
+ getExportedSize(options = {}) {
8828
+ const zipEntry = this;
8829
+ options = Object.assign({}, options);
8830
+ if (options.bufferedWrite === UNDEFINED_VALUE) {
8831
+ options.bufferedWrite = true;
8832
+ }
8833
+ const writeOrderGuaranteed = !options.bufferedWrite ||
8834
+ (options.keepOrder !== false && zipEntry.children.every(child => !child.children.length));
8835
+ return getEntriesSize(options, Array.from(zipEntry.getChildren({ recursive: true }), child => {
8836
+ const { name, entryOptions } = getChildEntryOptions(child, zipEntry, options);
8837
+ return { name, size: child.directory ? 0 : getDeterminedSize(child, isPassThrough(child, options)), options: entryOptions };
8838
+ }), writeOrderGuaranteed, options.globalComment);
8839
+ }
8840
+
8680
8841
  getChildByName(name) {
8681
8842
  const children = this.children;
8682
8843
  for (let childIndex = 0; childIndex < children.length; childIndex++) {
@@ -8687,6 +8848,10 @@
8687
8848
  }
8688
8849
  }
8689
8850
 
8851
+ getChildren(options = {}) {
8852
+ return collectChildren(this, options.recursive);
8853
+ }
8854
+
8690
8855
  isPasswordProtected() {
8691
8856
  const children = this.children;
8692
8857
  for (let childIndex = 0; childIndex < children.length; childIndex++) {
@@ -8778,6 +8943,10 @@
8778
8943
  return this.root.getChildByName(name);
8779
8944
  }
8780
8945
 
8946
+ getChildren(options) {
8947
+ return this.root.getChildren(options);
8948
+ }
8949
+
8781
8950
  addDirectory(name, options) {
8782
8951
  return this.root.addDirectory(name, options);
8783
8952
  }
@@ -8876,6 +9045,10 @@
8876
9045
  return this.root.exportZip(writer, options);
8877
9046
  }
8878
9047
 
9048
+ getExportedSize(options) {
9049
+ return this.root.getExportedSize(options);
9050
+ }
9051
+
8879
9052
  isPasswordProtected() {
8880
9053
  return this.root.isPasswordProtected();
8881
9054
  }
@@ -8887,12 +9060,12 @@
8887
9060
 
8888
9061
  const fs = { FS, ZipDirectoryEntry, ZipFileEntry };
8889
9062
 
8890
- function getTotalSize(entries, propertyName) {
9063
+ function getTotalSize(entries, getEntrySize) {
8891
9064
  let size = 0;
8892
9065
  const pendingEntries = Array.from(entries);
8893
9066
  while (pendingEntries.length) {
8894
9067
  const entry = pendingEntries.pop();
8895
- size += entry[propertyName] || 0;
9068
+ size += getEntrySize(entry) || 0;
8896
9069
  for (const child of entry.children) {
8897
9070
  pendingEntries.push(child);
8898
9071
  }
@@ -8900,6 +9073,15 @@
8900
9073
  return size;
8901
9074
  }
8902
9075
 
9076
+ function getUncompressedSize(entry) {
9077
+ return entry.uncompressedSize;
9078
+ }
9079
+
9080
+ function getExtractedSize(entry, passThrough) {
9081
+ const { data } = entry;
9082
+ return passThrough && data instanceof Entry ? data.compressedSize : entry.uncompressedSize;
9083
+ }
9084
+
8903
9085
  function getReadableReader(readable) {
8904
9086
  let consumed;
8905
9087
  return function () {
@@ -8922,10 +9104,17 @@
8922
9104
 
8923
9105
  async init() {
8924
9106
  const zipBlobReader = this;
8925
- zipBlobReader.size = zipBlobReader.entry.uncompressedSize;
8926
- const data = await zipBlobReader.entry.getData(new BlobWriter(), Object.assign({}, options, zipBlobReader.options));
9107
+ const readerOptions = Object.assign({}, options, zipBlobReader.options);
9108
+ const { checkOverlappingEntry, checkOverlappingEntryOnly } = readerOptions;
9109
+ const data = await zipBlobReader.entry.getData(new BlobWriter(), Object.assign(readerOptions, {
9110
+ checkPasswordOnly: false,
9111
+ checkOverlappingEntry: checkOverlappingEntryOnly || checkOverlappingEntry,
9112
+ checkOverlappingEntryOnly: false,
9113
+ preventClose: false
9114
+ }));
8927
9115
  zipBlobReader.data = data;
8928
9116
  zipBlobReader.blobReader = new BlobReader(data);
9117
+ zipBlobReader.size = data.size;
8929
9118
  super.init();
8930
9119
  }
8931
9120
 
@@ -8939,6 +9128,30 @@
8939
9128
  return Reader.prototype ? new Reader(data, options) : Reader(data, options);
8940
9129
  }
8941
9130
 
9131
+ function keepsContentType(writer, data) {
9132
+ const { contentType } = writer;
9133
+ if (contentType === UNDEFINED_VALUE) {
9134
+ return true;
9135
+ } else if (writer.constructor == BlobWriter) {
9136
+ return data.type == contentType;
9137
+ } else if (writer.constructor == Data64URIWriter) {
9138
+ return data.startsWith(writer.data);
9139
+ } else {
9140
+ return true;
9141
+ }
9142
+ }
9143
+
9144
+ function createProgressReadable(zipEntry, reader, options, signal) {
9145
+ const { onstart, onprogress, onend } = options;
9146
+ const { readable } = reader;
9147
+ const coreReaderReportsProgress = zipEntry.data instanceof Entry;
9148
+ if (coreReaderReportsProgress || (!onstart && !onprogress && !onend)) {
9149
+ return readable;
9150
+ } else {
9151
+ return toCompatibleReadable(readable).pipeThrough(new ProgressWatcherStream({ onstart, onprogress, onend, size: reader.size }), { signal });
9152
+ }
9153
+ }
9154
+
8942
9155
  async function initReaders(entry, options) {
8943
9156
  const fileEntries = [];
8944
9157
  const pendingEntries = [entry];
@@ -8971,6 +9184,7 @@
8971
9184
  }
8972
9185
  if (reader.size !== UNDEFINED_VALUE) {
8973
9186
  child.uncompressedSize = reader.size;
9187
+ child.undeterminedSize = false;
8974
9188
  }
8975
9189
  }));
8976
9190
  return readers;
@@ -9020,6 +9234,90 @@
9020
9234
  return error;
9021
9235
  }
9022
9236
 
9237
+ function getChildEntryOptions(child, selectedEntry, options) {
9238
+ const name = options.relativePath ? child.getRelativeName(selectedEntry) : child.getFullname();
9239
+ const childOptions = child.options || {};
9240
+ let zipEntryMetadata = {};
9241
+ let passThroughOptions = {};
9242
+ if (child.data instanceof Entry) {
9243
+ const {
9244
+ externalFileAttributes,
9245
+ versionMadeBy,
9246
+ comment,
9247
+ lastModDate,
9248
+ creationDate,
9249
+ lastAccessDate,
9250
+ uncompressedSize,
9251
+ encrypted,
9252
+ zipCrypto,
9253
+ crc32,
9254
+ compressionMethod,
9255
+ extraFieldAES,
9256
+ internalFileAttributes,
9257
+ extraField,
9258
+ uid,
9259
+ gid
9260
+ } = child.data;
9261
+ zipEntryMetadata = {
9262
+ externalFileAttributes,
9263
+ versionMadeBy,
9264
+ comment,
9265
+ lastModDate,
9266
+ creationDate,
9267
+ lastAccessDate,
9268
+ internalFileAttributes
9269
+ };
9270
+ const userExtraField = getUserExtraField(extraField);
9271
+ if (userExtraField) {
9272
+ zipEntryMetadata.extraField = userExtraField;
9273
+ }
9274
+ if (uid !== UNDEFINED_VALUE || gid !== UNDEFINED_VALUE) {
9275
+ Object.assign(zipEntryMetadata, {
9276
+ uid,
9277
+ gid,
9278
+ unixExtraFieldType: INFOZIP_EXTRA_FIELD_TYPE
9279
+ });
9280
+ }
9281
+ if (isPassThrough(child, options)) {
9282
+ let level, encryptionStrength;
9283
+ if (compressionMethod === 0) {
9284
+ level = 0;
9285
+ }
9286
+ if (extraFieldAES) {
9287
+ encryptionStrength = extraFieldAES.strength;
9288
+ }
9289
+ passThroughOptions = {
9290
+ passThrough: true,
9291
+ encrypted,
9292
+ zipCrypto,
9293
+ crc32,
9294
+ uncompressedSize,
9295
+ level,
9296
+ encryptionStrength,
9297
+ compressionMethod
9298
+ };
9299
+ }
9300
+ }
9301
+ const entryOptions = Object.assign({}, zipEntryMetadata, options, passThroughOptions, childOptions, { directory: child.directory });
9302
+ if (!child.directory && entryOptions.passThrough && entryOptions.uncompressedSize === UNDEFINED_VALUE) {
9303
+ throw new Error(ERR_INVALID_PASS_THROUGH);
9304
+ }
9305
+ return { name, entryOptions };
9306
+ }
9307
+
9308
+ function getDeterminedSize(child, passThrough) {
9309
+ const { reader } = child;
9310
+ if (reader && reader.size !== UNDEFINED_VALUE) {
9311
+ return reader.size;
9312
+ }
9313
+ return child.undeterminedSize ? UNDEFINED_VALUE : getExtractedSize(child, passThrough);
9314
+ }
9315
+
9316
+ function isPassThrough(child, options) {
9317
+ const { readerOptions } = options;
9318
+ return Boolean(!child.directory && (child.passThrough || (readerOptions && readerOptions.passThrough)));
9319
+ }
9320
+
9023
9321
  function getUserExtraField(extraField) {
9024
9322
  if (extraField) {
9025
9323
  const userExtraField = new Map();
@@ -9035,104 +9333,53 @@
9035
9333
  }
9036
9334
 
9037
9335
  async function exportZip(zipWriter, entry, totalSize, options, readers) {
9336
+ const { onstart, onprogress, onend, onentryprogress } = options;
9038
9337
  const selectedEntry = entry;
9039
- const entryOffsets = new Map();
9040
- await process(zipWriter, entry);
9041
-
9042
- async function process(zipWriter, entry) {
9043
- await exportChild();
9044
-
9045
- async function exportChild() {
9046
- if (options.bufferedWrite) {
9047
- const results = await Promise.allSettled(entry.children.map(processChild));
9048
- const errorResult = results.find(result => result.status == "rejected");
9049
- if (errorResult) {
9050
- throw errorResult.reason;
9051
- }
9052
- } else {
9053
- for (const child of entry.children) {
9054
- await processChild(child);
9055
- }
9056
- }
9338
+ const totalEntries = getTotalSize(entry.children, () => 1);
9339
+ let writtenSize = 0;
9340
+ let writtenEntries = 0;
9341
+ if (onstart) {
9342
+ await callHandler(onstart, totalSize);
9343
+ }
9344
+ if (options.bufferedWrite) {
9345
+ await processChildren(entry);
9346
+ } else {
9347
+ for (const child of entry.getChildren({ recursive: true })) {
9348
+ await addChild(child);
9057
9349
  }
9350
+ }
9351
+ if (onend) {
9352
+ await callHandler(onend, writtenSize);
9353
+ }
9058
9354
 
9059
- async function processChild(child) {
9060
- const name = options.relativePath ? child.getRelativeName(selectedEntry) : child.getFullname();
9061
- const childOptions = child.options || {};
9062
- let zipEntryOptions = {};
9063
- if (child.data instanceof Entry) {
9064
- const {
9065
- externalFileAttributes,
9066
- versionMadeBy,
9067
- comment,
9068
- lastModDate,
9069
- creationDate,
9070
- lastAccessDate,
9071
- uncompressedSize,
9072
- encrypted,
9073
- zipCrypto,
9074
- crc32,
9075
- compressionMethod,
9076
- extraFieldAES,
9077
- internalFileAttributes,
9078
- extraField,
9079
- uid,
9080
- gid
9081
- } = child.data;
9082
- zipEntryOptions = {
9083
- externalFileAttributes,
9084
- versionMadeBy,
9085
- comment,
9086
- lastModDate,
9087
- creationDate,
9088
- lastAccessDate,
9089
- internalFileAttributes
9090
- };
9091
- const userExtraField = getUserExtraField(extraField);
9092
- if (userExtraField) {
9093
- zipEntryOptions.extraField = userExtraField;
9094
- }
9095
- if (uid !== UNDEFINED_VALUE || gid !== UNDEFINED_VALUE) {
9096
- Object.assign(zipEntryOptions, {
9097
- uid,
9098
- gid,
9099
- unixExtraFieldType: options.unixExtraFieldType || INFOZIP_EXTRA_FIELD_TYPE
9100
- });
9101
- }
9102
- if (child.passThrough) {
9103
- let level, encryptionStrength;
9104
- if (compressionMethod === 0) {
9105
- level = 0;
9106
- }
9107
- if (extraFieldAES) {
9108
- encryptionStrength = extraFieldAES.strength;
9109
- }
9110
- zipEntryOptions = Object.assign(zipEntryOptions, {
9111
- passThrough: true,
9112
- encrypted,
9113
- zipCrypto,
9114
- crc32,
9115
- uncompressedSize,
9116
- level,
9117
- encryptionStrength,
9118
- compressionMethod
9119
- });
9355
+ async function processChildren(entry) {
9356
+ const results = await Promise.allSettled(entry.children.map(async child => {
9357
+ await addChild(child);
9358
+ await processChildren(child);
9359
+ }));
9360
+ const errorResult = results.find(result => result.status == "rejected");
9361
+ if (errorResult) {
9362
+ throw errorResult.reason;
9363
+ }
9364
+ }
9365
+
9366
+ async function addChild(child) {
9367
+ const { name, entryOptions } = getChildEntryOptions(child, selectedEntry, options);
9368
+ let entryWrittenSize = 0;
9369
+ const entryMetadata = await zipWriter.add(name, readers.get(child), Object.assign(entryOptions, {
9370
+ onstart: UNDEFINED_VALUE,
9371
+ onend: UNDEFINED_VALUE,
9372
+ onprogress: async indexProgress => {
9373
+ writtenSize += indexProgress - entryWrittenSize;
9374
+ entryWrittenSize = indexProgress;
9375
+ if (onprogress) {
9376
+ await callHandler(onprogress, writtenSize, totalSize);
9120
9377
  }
9121
9378
  }
9122
- await zipWriter.add(name, readers.get(child), Object.assign({}, options, zipEntryOptions, childOptions, {
9123
- directory: child.directory,
9124
- onprogress: async indexProgress => {
9125
- if (options.onprogress) {
9126
- entryOffsets.set(name, indexProgress);
9127
- try {
9128
- await options.onprogress(Array.from(entryOffsets.values()).reduce((previousValue, currentValue) => previousValue + currentValue), totalSize);
9129
- } catch {
9130
- // ignored
9131
- }
9132
- }
9133
- }
9134
- }));
9135
- await process(zipWriter, child);
9379
+ }));
9380
+ writtenEntries++;
9381
+ if (onentryprogress) {
9382
+ await callHandler(onentryprogress, writtenEntries, totalEntries, entryMetadata);
9136
9383
  }
9137
9384
  }
9138
9385
  }
@@ -9161,7 +9408,7 @@
9161
9408
  })
9162
9409
  );
9163
9410
  } else if (handle.kind == "directory") {
9164
- const directoryEntry = parentEntry.addDirectory(handle.name);
9411
+ const directoryEntry = parentEntry.addDirectory(handle.name, options);
9165
9412
  addedEntries.push(directoryEntry);
9166
9413
  for await (const childHandle of handle.values()) {
9167
9414
  await addFile(directoryEntry, childHandle, addedEntries, entryName);
@@ -9183,14 +9430,29 @@
9183
9430
  }
9184
9431
 
9185
9432
  async function exportFileSystemHandle(zipEntry, directoryHandle, options) {
9186
- const totalSize = getTotalSize([zipEntry], "uncompressedSize");
9187
- const writtenSizes = new Map();
9433
+ const { onstart, onprogress, onend } = options;
9188
9434
  const abortController = new AbortController();
9189
9435
  const { signal } = abortController;
9190
9436
  const releaseSignal = forwardAbort(options.signal, abortController);
9437
+ const getDataOptions = Object.assign({}, options, options.readerOptions, {
9438
+ signal,
9439
+ onstart: UNDEFINED_VALUE,
9440
+ onprogress: UNDEFINED_VALUE,
9441
+ onend: UNDEFINED_VALUE,
9442
+ preventClose: false
9443
+ });
9444
+ const totalSize = getTotalSize([zipEntry], entry => getExtractedSize(entry, getDataOptions.passThrough));
9191
9445
  const exportedEntryNames = [];
9446
+ let exportAborted = false;
9447
+ let writtenSize = 0;
9192
9448
  try {
9449
+ if (onstart) {
9450
+ await callHandler(onstart, totalSize);
9451
+ }
9193
9452
  await exportChildren(zipEntry, directoryHandle);
9453
+ if (onend) {
9454
+ await callHandler(onend, writtenSize);
9455
+ }
9194
9456
  } catch (error) {
9195
9457
  try {
9196
9458
  error.exportedEntryNames = exportedEntryNames;
@@ -9203,6 +9465,25 @@
9203
9465
  }
9204
9466
  return directoryHandle;
9205
9467
 
9468
+ function createProgressWritable(writable) {
9469
+ const writer = writable.getWriter();
9470
+ return new WritableStream({
9471
+ async write(chunk) {
9472
+ await writer.write(chunk);
9473
+ writtenSize += chunk.length;
9474
+ if (onprogress) {
9475
+ await callHandler(onprogress, writtenSize, totalSize);
9476
+ }
9477
+ },
9478
+ close() {
9479
+ return writer.close();
9480
+ },
9481
+ abort(reason) {
9482
+ return writer.abort(reason);
9483
+ }
9484
+ });
9485
+ }
9486
+
9206
9487
  async function exportChildren(entry, parentHandle) {
9207
9488
  if (options.concurrent) {
9208
9489
  const results = await Promise.allSettled(entry.children.map(child => exportChild(child, parentHandle)));
@@ -9221,10 +9502,10 @@
9221
9502
 
9222
9503
  async function exportChild(child, parentHandle) {
9223
9504
  if (signal.aborted) {
9224
- if (isExportAborted(signal.reason)) {
9505
+ if (exportAborted || isExportAborted(signal.reason)) {
9225
9506
  return;
9226
9507
  }
9227
- throw signal.reason;
9508
+ throw signal.reason === UNDEFINED_VALUE ? new DOMException(ERR_ABORTED, ABORT_ERROR_NAME) : signal.reason;
9228
9509
  }
9229
9510
  try {
9230
9511
  if (child.directory) {
@@ -9233,22 +9514,15 @@
9233
9514
  } else {
9234
9515
  const fileHandle = await parentHandle.getFileHandle(child.name, { create: true });
9235
9516
  const writable = await fileHandle.createWritable();
9236
- await child.getData({ writable }, Object.assign({}, options, {
9237
- signal,
9238
- onprogress: async progress => {
9239
- if (options.onprogress) {
9240
- writtenSizes.set(child.id, progress);
9241
- try {
9242
- await options.onprogress(Array.from(writtenSizes.values()).reduce((previousValue, currentValue) => previousValue + currentValue, 0), totalSize);
9243
- } catch {
9244
- // ignored
9245
- }
9246
- }
9247
- }
9248
- }));
9517
+ try {
9518
+ await child.getData({ writable: createProgressWritable(writable) }, getDataOptions);
9519
+ } catch (error) {
9520
+ throw exportAborted ? new Error(ERR_ABORT_EXPORT) : error;
9521
+ }
9249
9522
  exportedEntryNames.push(child.getRelativeName(zipEntry));
9250
9523
  }
9251
9524
  } catch (error) {
9525
+ exportAborted = true;
9252
9526
  abortController.abort(new Error(ERR_ABORT_EXPORT));
9253
9527
  try {
9254
9528
  if (error.entryName === UNDEFINED_VALUE) {
@@ -9320,6 +9594,21 @@
9320
9594
  fs.root = new ZipDirectoryEntry(fs);
9321
9595
  }
9322
9596
 
9597
+ function collectChildren(directory, recursive) {
9598
+ const children = [];
9599
+ const pendingDirectories = [directory];
9600
+ let directoryIndex = 0;
9601
+ while (directoryIndex < pendingDirectories.length) {
9602
+ for (const child of pendingDirectories[directoryIndex++].children) {
9603
+ children.push(child);
9604
+ if (recursive) {
9605
+ pendingDirectories.push(child);
9606
+ }
9607
+ }
9608
+ }
9609
+ return children;
9610
+ }
9611
+
9323
9612
  function registerEntries(fs, entry) {
9324
9613
  const pendingEntries = [entry];
9325
9614
  while (pendingEntries.length) {
@@ -9438,6 +9727,7 @@
9438
9727
  exports.BlobWriter = BlobWriter;
9439
9728
  exports.Data64URIReader = Data64URIReader;
9440
9729
  exports.Data64URIWriter = Data64URIWriter;
9730
+ exports.ERR_ABORTED = ERR_ABORTED;
9441
9731
  exports.ERR_AMBIGUOUS_ARCHIVE = ERR_AMBIGUOUS_ARCHIVE;
9442
9732
  exports.ERR_BAD_FORMAT = ERR_BAD_FORMAT;
9443
9733
  exports.ERR_CENTRAL_DIRECTORY_NOT_FOUND = ERR_CENTRAL_DIRECTORY_NOT_FOUND;
@@ -9469,6 +9759,7 @@
9469
9759
  exports.ERR_INVALID_MSDOS_DATA = ERR_INVALID_MSDOS_DATA;
9470
9760
  exports.ERR_INVALID_PASSWORD = ERR_INVALID_PASSWORD;
9471
9761
  exports.ERR_INVALID_PASSWORD_TYPE = ERR_INVALID_PASSWORD_TYPE;
9762
+ exports.ERR_INVALID_PASS_THROUGH = ERR_INVALID_PASS_THROUGH;
9472
9763
  exports.ERR_INVALID_SIGNATURE = ERR_INVALID_SIGNATURE;
9473
9764
  exports.ERR_INVALID_SIGNATURE_DATA = ERR_INVALID_SIGNATURE_DATA;
9474
9765
  exports.ERR_INVALID_STRICTNESS = ERR_INVALID_STRICTNESS;
@@ -9486,11 +9777,13 @@
9486
9777
  exports.ERR_SPLIT_ZIP_FILE = ERR_SPLIT_ZIP_FILE;
9487
9778
  exports.ERR_UNDEFINED_READER = ERR_UNDEFINED_READER;
9488
9779
  exports.ERR_UNDEFINED_UNCOMPRESSED_SIZE = ERR_UNDEFINED_UNCOMPRESSED_SIZE;
9780
+ exports.ERR_UNDETERMINED_SIZE = ERR_UNDETERMINED_SIZE;
9489
9781
  exports.ERR_UNSAFE_FILENAME = ERR_UNSAFE_FILENAME;
9490
9782
  exports.ERR_UNSUPPORTED_COMPRESSION = ERR_UNSUPPORTED_COMPRESSION$1;
9491
9783
  exports.ERR_UNSUPPORTED_CONTEXT = ERR_UNSUPPORTED_CONTEXT;
9492
9784
  exports.ERR_UNSUPPORTED_CRYPTO_API = ERR_UNSUPPORTED_CRYPTO_API;
9493
9785
  exports.ERR_UNSUPPORTED_ENCRYPTION = ERR_UNSUPPORTED_ENCRYPTION;
9786
+ exports.ERR_UNSUPPORTED_ENCRYPTION_PASS_THROUGH = ERR_UNSUPPORTED_ENCRYPTION_PASS_THROUGH;
9494
9787
  exports.ERR_UNSUPPORTED_ENCRYPTION_USDZ = ERR_UNSUPPORTED_ENCRYPTION_USDZ;
9495
9788
  exports.ERR_UNSUPPORTED_FORMAT = ERR_UNSUPPORTED_FORMAT;
9496
9789
  exports.ERR_WORKER_STARTUP_TIMEOUT = ERR_WORKER_STARTUP_TIMEOUT;