@zip.js/zip.js 2.8.51 → 2.8.52

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.cjs CHANGED
@@ -84,6 +84,8 @@ const FILE_ATTR_MSDOS_SYSTEM_MASK = 0x04;
84
84
  const FILE_ATTR_MSDOS_ARCHIVE_MASK = 0x20;
85
85
  const FILE_ATTR_UNIX_TYPE_MASK = 0o170000;
86
86
  const FILE_ATTR_UNIX_TYPE_DIR = 0o040000;
87
+ const FILE_ATTR_UNIX_TYPE_SYMLINK = 0o120000;
88
+ const FILE_ATTR_UNIX_TYPE_FILE = 0o100000;
87
89
  const FILE_ATTR_UNIX_EXECUTABLE_MASK = 0o111;
88
90
  const FILE_ATTR_UNIX_DEFAULT_MASK = 0o644;
89
91
  const FILE_ATTR_UNIX_SETUID_MASK = 0o4000;
@@ -1775,8 +1777,6 @@ function getInt32(number) {
1775
1777
  */
1776
1778
 
1777
1779
 
1778
- const HTTP_HEADER_CONTENT_TYPE = "Content-Type";
1779
-
1780
1780
  function toCompatibleReadable(readable) {
1781
1781
  if (readable instanceof ReadableStream) {
1782
1782
  return readable;
@@ -1799,12 +1799,9 @@ function toCompatibleReadable(readable) {
1799
1799
 
1800
1800
  function streamToBlob(readable, contentType) {
1801
1801
  readable = toCompatibleReadable(readable);
1802
+ const blobOptions = contentType ? { type: contentType } : {};
1802
1803
  if (responseSupportsGlobalReadable()) {
1803
- const options = {};
1804
- if (contentType) {
1805
- options.headers = [[HTTP_HEADER_CONTENT_TYPE, contentType]];
1806
- }
1807
- return new Response(readable, options).blob();
1804
+ return new Response(readable).blob().then(blob => contentType ? new Blob([blob], blobOptions) : blob);
1808
1805
  }
1809
1806
  const chunks = [];
1810
1807
  return readable
@@ -1813,7 +1810,7 @@ function streamToBlob(readable, contentType) {
1813
1810
  chunks.push(chunk);
1814
1811
  }
1815
1812
  }))
1816
- .then(() => new Blob(chunks, contentType ? { type: contentType } : {}));
1813
+ .then(() => new Blob(chunks, blobOptions));
1817
1814
  }
1818
1815
 
1819
1816
  function responseSupportsGlobalReadable() {
@@ -3348,8 +3345,10 @@ class Reader extends Stream {
3348
3345
  async pull(controller) {
3349
3346
  const dataSize = size === UNDEFINED_VALUE ? chunkSize : Math.min(chunkSize, size - chunkOffset);
3350
3347
  const data = await readUint8Array(reader, offset + chunkOffset, dataSize);
3351
- controller.enqueue(data);
3352
- if ((chunkOffset + chunkSize > size) || (size === UNDEFINED_VALUE && !data.length && dataSize)) {
3348
+ if (data.length) {
3349
+ controller.enqueue(data);
3350
+ }
3351
+ if ((chunkOffset + chunkSize >= size) || (size === UNDEFINED_VALUE && !data.length && dataSize)) {
3353
3352
  controller.close();
3354
3353
  } else {
3355
3354
  chunkOffset += chunkSize;
@@ -3427,6 +3426,7 @@ class Data64URIWriter extends Writer {
3427
3426
  constructor(contentType) {
3428
3427
  super();
3429
3428
  Object.assign(this, {
3429
+ contentType,
3430
3430
  data: "data:" + (contentType || "") + ";base64,",
3431
3431
  pending: []
3432
3432
  });
@@ -3528,6 +3528,7 @@ class BlobWriter extends Stream {
3528
3528
  return transformStream.writable;
3529
3529
  }
3530
3530
  });
3531
+ writer.contentType = contentType;
3531
3532
  writer.blob = streamToBlob(transformStream.readable, contentType);
3532
3533
  writer.blob.catch(() => { });
3533
3534
  }
@@ -3544,6 +3545,26 @@ class TextReader extends BlobReader {
3544
3545
  }
3545
3546
  }
3546
3547
 
3548
+ function getTextSize(text) {
3549
+ let size = 0;
3550
+ for (let indexCharacter = 0; indexCharacter < text.length; indexCharacter++) {
3551
+ const characterCode = text.charCodeAt(indexCharacter);
3552
+ if (characterCode < 0x80) {
3553
+ size += 1;
3554
+ } else if (characterCode < 0x800) {
3555
+ size += 2;
3556
+ } else if (characterCode < 0xd800 || characterCode >= 0xe000) {
3557
+ size += 3;
3558
+ } else if (characterCode < 0xdc00 && (text.charCodeAt(indexCharacter + 1) & 0xfc00) == 0xdc00) {
3559
+ size += 4;
3560
+ indexCharacter++;
3561
+ } else {
3562
+ size += 3;
3563
+ }
3564
+ }
3565
+ return size;
3566
+ }
3567
+
3547
3568
  class TextWriter extends BlobWriter {
3548
3569
 
3549
3570
  constructor(encoding) {
@@ -4207,6 +4228,10 @@ class GenericWriter {
4207
4228
  }
4208
4229
  }
4209
4230
 
4231
+ function ownsWritable(writer) {
4232
+ return Boolean(writer && writer.getData);
4233
+ }
4234
+
4210
4235
  function isHttpFamily(url) {
4211
4236
  const { baseURI } = getConfiguration();
4212
4237
  const { protocol } = new URL(url, baseURI);
@@ -4351,6 +4376,8 @@ const PROPERTY_NAME_CREATION_DATE = "creationDate";
4351
4376
  const PROPERTY_NAME_RAW_CREATION_DATE = "rawCreationDate";
4352
4377
  const PROPERTY_NAME_INTERNAL_FILE_ATTRIBUTES = "internalFileAttributes";
4353
4378
  const PROPERTY_NAME_EXTERNAL_FILE_ATTRIBUTES = "externalFileAttributes";
4379
+ const PROPERTY_NAME_DEPRECATED_INTERNAL_FILE_ATTRIBUTES = "internalFileAttribute";
4380
+ const PROPERTY_NAME_DEPRECATED_EXTERNAL_FILE_ATTRIBUTES = "externalFileAttribute";
4354
4381
  const PROPERTY_NAME_MSDOS_ATTRIBUTES_RAW = "msdosAttributesRaw";
4355
4382
  const PROPERTY_NAME_MSDOS_ATTRIBUTES = "msdosAttributes";
4356
4383
  const PROPERTY_NAME_MS_DOS_COMPATIBLE = "msDosCompatible";
@@ -4361,6 +4388,7 @@ const PROPERTY_NAME_VERSION_MADE_BY = "versionMadeBy";
4361
4388
  const PROPERTY_NAME_ZIPCRYPTO = "zipCrypto";
4362
4389
  const PROPERTY_NAME_DIRECTORY = "directory";
4363
4390
  const PROPERTY_NAME_EXECUTABLE = "executable";
4391
+ const PROPERTY_NAME_SYMLINK = "symlink";
4364
4392
  const PROPERTY_NAME_COMPRESSION_METHOD = "compressionMethod";
4365
4393
  const PROPERTY_NAME_SIGNATURE = "signature";
4366
4394
  const PROPERTY_NAME_CRC32 = "crc32";
@@ -4404,6 +4432,8 @@ const PROPERTY_NAMES = [
4404
4432
  PROPERTY_NAME_DISK_NUMBER_START,
4405
4433
  PROPERTY_NAME_INTERNAL_FILE_ATTRIBUTES,
4406
4434
  PROPERTY_NAME_EXTERNAL_FILE_ATTRIBUTES,
4435
+ PROPERTY_NAME_DEPRECATED_INTERNAL_FILE_ATTRIBUTES,
4436
+ PROPERTY_NAME_DEPRECATED_EXTERNAL_FILE_ATTRIBUTES,
4407
4437
  PROPERTY_NAME_MSDOS_ATTRIBUTES_RAW,
4408
4438
  PROPERTY_NAME_MSDOS_ATTRIBUTES,
4409
4439
  PROPERTY_NAME_MS_DOS_COMPATIBLE,
@@ -4414,6 +4444,7 @@ const PROPERTY_NAMES = [
4414
4444
  PROPERTY_NAME_ZIPCRYPTO,
4415
4445
  PROPERTY_NAME_DIRECTORY,
4416
4446
  PROPERTY_NAME_EXECUTABLE,
4447
+ PROPERTY_NAME_SYMLINK,
4417
4448
  PROPERTY_NAME_COMPRESSION_METHOD,
4418
4449
  PROPERTY_NAME_SIGNATURE,
4419
4450
  PROPERTY_NAME_CRC32,
@@ -4876,15 +4907,18 @@ class ZipReader {
4876
4907
  const setuid = Boolean(fileEntry.unixMode & FILE_ATTR_UNIX_SETUID_MASK);
4877
4908
  const setgid = Boolean(fileEntry.unixMode & FILE_ATTR_UNIX_SETGID_MASK);
4878
4909
  const sticky = Boolean(fileEntry.unixMode & FILE_ATTR_UNIX_STICKY_MASK);
4879
- const executable = (fileEntry.unixMode !== UNDEFINED_VALUE)
4910
+ const unixType = fileEntry.unixMode === UNDEFINED_VALUE ? unixExternalUpper : fileEntry.unixMode;
4911
+ const symlink = (unixType & FILE_ATTR_UNIX_TYPE_MASK) == FILE_ATTR_UNIX_TYPE_SYMLINK;
4912
+ const executable = !symlink && ((fileEntry.unixMode !== UNDEFINED_VALUE)
4880
4913
  ? ((fileEntry.unixMode & FILE_ATTR_UNIX_EXECUTABLE_MASK) != 0)
4881
- : (unixCompatible && ((unixExternalUpper & FILE_ATTR_UNIX_EXECUTABLE_MASK) != 0));
4914
+ : (unixCompatible && ((unixExternalUpper & FILE_ATTR_UNIX_EXECUTABLE_MASK) != 0)));
4882
4915
  const modeIsDir = fileEntry.unixMode !== UNDEFINED_VALUE && ((fileEntry.unixMode & FILE_ATTR_UNIX_TYPE_MASK) == FILE_ATTR_UNIX_TYPE_DIR);
4883
4916
  const upperIsDir = ((unixExternalUpper & FILE_ATTR_UNIX_TYPE_MASK) == FILE_ATTR_UNIX_TYPE_DIR);
4884
4917
  Object.assign(fileEntry, {
4885
4918
  setuid,
4886
4919
  setgid,
4887
4920
  sticky,
4921
+ symlink,
4888
4922
  unixExternalUpper,
4889
4923
  internalFileAttribute: fileEntry.internalFileAttributes,
4890
4924
  externalFileAttribute: fileEntry.externalFileAttributes,
@@ -4950,6 +4984,10 @@ class ZipReader {
4950
4984
  }
4951
4985
 
4952
4986
  async close() {
4987
+ const { reader } = this;
4988
+ if (!reader.readUint8Array && reader.readable && !reader.readable.locked) {
4989
+ await reader.readable.cancel();
4990
+ }
4953
4991
  }
4954
4992
  }
4955
4993
 
@@ -5174,7 +5212,7 @@ let ZipEntry$1 = class ZipEntry {
5174
5212
  throw error;
5175
5213
  }
5176
5214
  } finally {
5177
- const preventClose = getOptionValue$1(zipEntry, options, OPTION_PREVENT_CLOSE);
5215
+ const preventClose = !ownsWritable(writer) && getOptionValue$1(zipEntry, options, OPTION_PREVENT_CLOSE);
5178
5216
  if (!preventClose && writable && !writable.locked) {
5179
5217
  const writableWriter = writable.getWriter();
5180
5218
  if (abortError) {
@@ -5418,8 +5456,8 @@ function readExtraFieldUnixDates(extraField, directory) {
5418
5456
  return;
5419
5457
  }
5420
5458
  const extraFieldView = getDataView(extraField.data);
5421
- const lastAccessDate = new Date(getUint32(extraFieldView, 0) * 1000);
5422
- const lastModDate = new Date(getUint32(extraFieldView, 4) * 1000);
5459
+ const lastAccessDate = new Date((getUint32(extraFieldView, 0) | 0) * 1000);
5460
+ const lastModDate = new Date((getUint32(extraFieldView, 4) | 0) * 1000);
5423
5461
  const extraFieldData = { lastAccessDate, lastModDate };
5424
5462
  if (extraField.data.length >= 12) {
5425
5463
  extraFieldData.uid = getUint16(extraFieldView, 8);
@@ -5850,6 +5888,7 @@ const ERR_INVALID_ENTRY_NAME = "File entry name exceeds 64KB";
5850
5888
  const ERR_INVALID_VERSION = "Version exceeds 65535";
5851
5889
  const ERR_INVALID_ENCRYPTION_STRENGTH = "The strength must equal 1, 2, or 3";
5852
5890
  const ERR_UNSUPPORTED_ENCRYPTION_USDZ = "Encryption is not supported in USDZ files";
5891
+ const ERR_UNSUPPORTED_ENCRYPTION_PASS_THROUGH = "Encryption is not supported when the 'passThrough' option is set";
5853
5892
  const ERR_INVALID_EXTRAFIELD_TYPE = "Extra field type exceeds 65535";
5854
5893
  const ERR_INVALID_EXTRAFIELD_DATA = "Extra field data exceeds 64KB";
5855
5894
  const ERR_UNSUPPORTED_COMPRESSION = "Compression method not supported";
@@ -5859,6 +5898,7 @@ const MIN_NTFS_TIME = BigInt(0);
5859
5898
  const MAX_NTFS_TIME = BigInt("0x7fffffffffffffff");
5860
5899
  const ERR_UNSUPPORTED_FORMAT = "Zip64 is not supported (set the 'zip64' option to 'true')";
5861
5900
  const ERR_UNDEFINED_UNCOMPRESSED_SIZE = "Undefined uncompressed size";
5901
+ const ERR_UNDETERMINED_SIZE = "Undetermined size";
5862
5902
  const ERR_UNDEFINED_READER = "Undefined reader";
5863
5903
  const ERR_ZIP_NOT_EMPTY = "Zip file not empty";
5864
5904
  const ERR_INVALID_UID = "Invalid uid (must be integer 0..2^32-1)";
@@ -6066,7 +6106,7 @@ class ZipWriter {
6066
6106
  await Promise.allSettled(Array.from(pendingAddFileCalls));
6067
6107
  }
6068
6108
  await closeFile(zipWriter, comment, options);
6069
- const preventClose = getOptionValue(zipWriter, options, OPTION_PREVENT_CLOSE);
6109
+ const preventClose = !ownsWritable(writer) && getOptionValue(zipWriter, options, OPTION_PREVENT_CLOSE);
6070
6110
  if (!preventClose) {
6071
6111
  await writable.getWriter().close();
6072
6112
  }
@@ -6225,7 +6265,7 @@ function resolveAttributes(zipWriter, name, options) {
6225
6265
  if (versionMadeBy > MAX_16_BITS) {
6226
6266
  throw new Error(ERR_INVALID_VERSION);
6227
6267
  }
6228
- let externalFileAttributes = getOptionValue(zipWriter, options, PROPERTY_NAME_EXTERNAL_FILE_ATTRIBUTES);
6268
+ let externalFileAttributes = getAliasedOptionValue(zipWriter, options, PROPERTY_NAME_EXTERNAL_FILE_ATTRIBUTES, PROPERTY_NAME_DEPRECATED_EXTERNAL_FILE_ATTRIBUTES);
6229
6269
  const externalFileAttributesProvided = externalFileAttributes !== UNDEFINED_VALUE;
6230
6270
  if (!externalFileAttributesProvided) {
6231
6271
  externalFileAttributes = 0;
@@ -6273,7 +6313,9 @@ function resolveAttributes(zipWriter, name, options) {
6273
6313
  }
6274
6314
  if (!externalFileAttributesProvided || unixModeProvided) {
6275
6315
  if (directory) {
6276
- unixMode |= FILE_ATTR_UNIX_TYPE_DIR;
6316
+ unixMode = (unixMode & ~FILE_ATTR_UNIX_TYPE_MASK) | FILE_ATTR_UNIX_TYPE_DIR;
6317
+ } else if (!(unixMode & FILE_ATTR_UNIX_TYPE_MASK)) {
6318
+ unixMode |= FILE_ATTR_UNIX_TYPE_FILE;
6277
6319
  }
6278
6320
  externalFileAttributes = ((unixMode & MAX_16_BITS) << 16) | (externalFileAttributes & MAX_16_BITS);
6279
6321
  }
@@ -6326,15 +6368,12 @@ function resolveMetadata(zipWriter, name, options) {
6326
6368
  const lastModDate = getOptionValue(zipWriter, options, PROPERTY_NAME_LAST_MODIFICATION_DATE, new Date());
6327
6369
  const lastAccessDate = getOptionValue(zipWriter, options, PROPERTY_NAME_LAST_ACCESS_DATE);
6328
6370
  const creationDate = getOptionValue(zipWriter, options, PROPERTY_NAME_CREATION_DATE);
6329
- const internalFileAttributes = getOptionValue(zipWriter, options, PROPERTY_NAME_INTERNAL_FILE_ATTRIBUTES, 0);
6371
+ const internalFileAttributes = getAliasedOptionValue(zipWriter, options, PROPERTY_NAME_INTERNAL_FILE_ATTRIBUTES, PROPERTY_NAME_DEPRECATED_INTERNAL_FILE_ATTRIBUTES, 0);
6330
6372
  const passThrough = getOptionValue(zipWriter, options, OPTION_PASS_THROUGH);
6331
- let password, rawPassword;
6332
- if (!passThrough) {
6333
- password = getOptionValue(zipWriter, options, OPTION_PASSWORD);
6334
- rawPassword = getOptionValue(zipWriter, options, OPTION_RAW_PASSWORD);
6335
- if ((password && typeof password != STRING_TYPE) || (rawPassword && !(rawPassword instanceof Uint8Array))) {
6336
- throw new Error(ERR_INVALID_PASSWORD_TYPE);
6337
- }
6373
+ const password = getOptionValue(zipWriter, options, OPTION_PASSWORD);
6374
+ const rawPassword = getOptionValue(zipWriter, options, OPTION_RAW_PASSWORD);
6375
+ if ((password && typeof password != STRING_TYPE) || (rawPassword && !(rawPassword instanceof Uint8Array))) {
6376
+ throw new Error(ERR_INVALID_PASSWORD_TYPE);
6338
6377
  }
6339
6378
  const encryptionStrength = getNumberOptionValue(zipWriter, options, OPTION_ENCRYPTION_STRENGTH, 3);
6340
6379
  const zipCrypto = getOptionValue(zipWriter, options, PROPERTY_NAME_ZIPCRYPTO);
@@ -6447,14 +6486,24 @@ function serializeExtraField(extraField) {
6447
6486
  }
6448
6487
 
6449
6488
  async function resolveSizes(zipWriter, reader, { resolvedOptions: metadata }, options) {
6489
+ if (metadata.passThrough && !reader && !getOptionValue(zipWriter, options, PROPERTY_NAME_DIRECTORY)) {
6490
+ throw new Error(ERR_UNDEFINED_READER);
6491
+ }
6492
+ let contentSize;
6493
+ if (reader) {
6494
+ reader = new GenericReader(reader);
6495
+ await initStream(reader);
6496
+ ({ size: contentSize } = reader);
6497
+ }
6498
+ return Object.assign({ reader }, resolveEntrySizes(zipWriter, Boolean(reader), contentSize, metadata, options));
6499
+ }
6500
+
6501
+ function resolveEntrySizes(zipWriter, hasContent, contentSize, metadata, options) {
6450
6502
  const { passThrough, zipCrypto, password, rawPassword, encryptionStrength } = metadata;
6451
6503
  let { dataDescriptor, zip64, level, compressionMethod } = metadata;
6452
6504
  let maximumCompressedSize = 0;
6453
6505
  let uncompressedSize = 0;
6454
- if (passThrough) {
6455
- if (!reader) {
6456
- throw new Error(ERR_UNDEFINED_READER);
6457
- }
6506
+ if (passThrough && hasContent) {
6458
6507
  uncompressedSize = options[PROPERTY_NAME_UNCOMPRESSED_SIZE];
6459
6508
  if (uncompressedSize === UNDEFINED_VALUE) {
6460
6509
  throw new Error(ERR_UNDEFINED_UNCOMPRESSED_SIZE);
@@ -6462,29 +6511,30 @@ async function resolveSizes(zipWriter, reader, { resolvedOptions: metadata }, op
6462
6511
  }
6463
6512
  const zip64Enabled = zip64 === true;
6464
6513
  const encrypted = getOptionValue(zipWriter, options, PROPERTY_NAME_ENCRYPTED);
6465
- const encryptedEntry = Boolean(reader) && (Boolean((password && getLength(password)) || (rawPassword && getLength(rawPassword))) || (passThrough && encrypted));
6466
- if (!reader) {
6514
+ if (hasContent && passThrough && !encrypted && getLength(password, rawPassword)) {
6515
+ throw new Error(ERR_UNSUPPORTED_ENCRYPTION_PASS_THROUGH);
6516
+ }
6517
+ const encryptedEntry = hasContent && (Boolean((password && getLength(password)) || (rawPassword && getLength(rawPassword))) || (passThrough && encrypted));
6518
+ if (!hasContent) {
6467
6519
  level = 0;
6468
6520
  compressionMethod = COMPRESSION_METHOD_STORE;
6469
6521
  }
6470
6522
  const encryptionOverhead = encryptedEntry ? (zipCrypto ? 12 : 16 + encryptionStrength * 4) : 0;
6471
- if (reader) {
6472
- reader = new GenericReader(reader);
6473
- await initStream(reader);
6523
+ if (hasContent) {
6474
6524
  if (!passThrough) {
6475
- if (reader.size === UNDEFINED_VALUE) {
6525
+ if (contentSize === UNDEFINED_VALUE) {
6476
6526
  dataDescriptor = true;
6477
6527
  if (zip64 || zip64 === UNDEFINED_VALUE) {
6478
6528
  zip64 = true;
6479
6529
  uncompressedSize = maximumCompressedSize = MAX_32_BITS + 1;
6480
6530
  }
6481
6531
  } else {
6482
- options.uncompressedSize = uncompressedSize = reader.size;
6483
- maximumCompressedSize = getMaximumCompressedSize(uncompressedSize) + encryptionOverhead;
6532
+ options.uncompressedSize = uncompressedSize = contentSize;
6533
+ maximumCompressedSize = (isCompressed(compressionMethod, level) ? getMaximumCompressedSize(uncompressedSize) : uncompressedSize) + encryptionOverhead;
6484
6534
  }
6485
6535
  } else {
6486
6536
  options.uncompressedSize = uncompressedSize;
6487
- maximumCompressedSize = getMaximumCompressedSize(uncompressedSize) + encryptionOverhead;
6537
+ maximumCompressedSize = contentSize === UNDEFINED_VALUE ? getMaximumCompressedSize(uncompressedSize) + encryptionOverhead : contentSize;
6488
6538
  }
6489
6539
  }
6490
6540
  const zip64UncompressedSize = zip64Enabled || uncompressedSize >= MAX_32_BITS;
@@ -6498,7 +6548,7 @@ async function resolveSizes(zipWriter, reader, { resolvedOptions: metadata }, op
6498
6548
  }
6499
6549
  zip64 = zip64 || false;
6500
6550
  return {
6501
- reader,
6551
+ maximumCompressedSize,
6502
6552
  resolvedOptions: {
6503
6553
  dataDescriptor,
6504
6554
  zip64,
@@ -6512,6 +6562,78 @@ async function resolveSizes(zipWriter, reader, { resolvedOptions: metadata }, op
6512
6562
  };
6513
6563
  }
6514
6564
 
6565
+ async function getEntriesSize(writerOptions, entries, writeOrderGuaranteed, comment) {
6566
+ const zipWriter = { options: writerOptions, config: getConfiguration() };
6567
+ if (writerOptions[OPTION_SIGN_CENTRAL_DIRECTORY]) {
6568
+ throw new Error(ERR_UNDETERMINED_SIZE);
6569
+ }
6570
+ const commentLength = getLength(comment);
6571
+ if (commentLength > MAX_16_BITS) {
6572
+ throw new Error(ERR_INVALID_COMMENT);
6573
+ }
6574
+ const usdz = writerOptions[OPTION_USDZ];
6575
+ const files = new Map();
6576
+ let layoutDependsOnWriteOrder = Boolean(usdz);
6577
+ let offset = 0;
6578
+ for (const entry of entries) {
6579
+ let { name } = entry;
6580
+ const { size } = entry;
6581
+ const options = Object.assign({}, entry.options);
6582
+ name = name.trim();
6583
+ if (getOptionValue(zipWriter, options, PROPERTY_NAME_DIRECTORY) && !name.endsWith(DIRECTORY_SIGNATURE)) {
6584
+ name += DIRECTORY_SIGNATURE;
6585
+ }
6586
+ const attributesInfo = resolveAttributes(zipWriter, name, options);
6587
+ ({ name } = attributesInfo);
6588
+ const { resolvedOptions: metadata } = resolveMetadata(zipWriter, name, options);
6589
+ if (metadata.level != 0 && metadata.compressionMethod === UNDEFINED_VALUE &&
6590
+ !metadata.passThrough && !(await supportsDeflate(zipWriter.config))) {
6591
+ metadata.level = 0;
6592
+ }
6593
+ const hasContent = !getOptionValue(zipWriter, options, PROPERTY_NAME_DIRECTORY);
6594
+ if (hasContent && size === UNDEFINED_VALUE) {
6595
+ throw new Error(ERR_UNDETERMINED_SIZE);
6596
+ }
6597
+ const { maximumCompressedSize, resolvedOptions: sizes } = resolveEntrySizes(zipWriter, hasContent, size, metadata, options);
6598
+ if (hasContent && !metadata.passThrough && isCompressed(sizes.compressionMethod, sizes.level)) {
6599
+ throw new Error(ERR_UNDETERMINED_SIZE);
6600
+ }
6601
+ const entryOptions = Object.assign({}, options, attributesInfo.resolvedOptions, metadata, sizes);
6602
+ const headerInfo = getHeaderInfo(entryOptions);
6603
+ const dataDescriptorInfo = getDataDescriptorInfo(entryOptions);
6604
+ const entryInfo = {
6605
+ headerInfo,
6606
+ metadataSize: getLength(headerInfo.localHeaderArray, dataDescriptorInfo.dataDescriptorArray)
6607
+ };
6608
+ if (usdz) {
6609
+ appendExtraFieldUSDZ(entryInfo, offset);
6610
+ }
6611
+ const compressedSize = hasContent ? maximumCompressedSize : 0;
6612
+ if (offset >= MAX_32_BITS) {
6613
+ layoutDependsOnWriteOrder = true;
6614
+ }
6615
+ files.set(name, Object.assign({}, entryOptions, headerInfo, {
6616
+ offset,
6617
+ diskNumberStart: 0,
6618
+ compressedSize
6619
+ }));
6620
+ offset += entryInfo.metadataSize + compressedSize;
6621
+ }
6622
+ if (layoutDependsOnWriteOrder && !writeOrderGuaranteed) {
6623
+ throw new Error(ERR_UNDETERMINED_SIZE);
6624
+ }
6625
+ const directoryDataLength = createDirectoryRecords(files);
6626
+ let zip64 = getOptionValue(zipWriter, writerOptions, PROPERTY_NAME_ZIP64);
6627
+ if (offset >= MAX_32_BITS || directoryDataLength >= MAX_32_BITS || files.size >= MAX_16_BITS) {
6628
+ if (zip64 === false) {
6629
+ throw new Error(ERR_UNSUPPORTED_FORMAT);
6630
+ } else {
6631
+ zip64 = true;
6632
+ }
6633
+ }
6634
+ return offset + directoryDataLength + commentLength + (zip64 ? ZIP64_END_OF_CENTRAL_DIR_TOTAL_LENGTH : END_OF_CENTRAL_DIR_LENGTH);
6635
+ }
6636
+
6515
6637
  async function getFileEntry(zipWriter, name, reader, entryInfo, options) {
6516
6638
  const {
6517
6639
  files,
@@ -6883,9 +7005,7 @@ function getHeaderInfo(options) {
6883
7005
  crc32
6884
7006
  } = options;
6885
7007
  let { version, compressionMethod } = options;
6886
- const compressed = !directory && (compressionMethod === UNDEFINED_VALUE
6887
- ? (level === UNDEFINED_VALUE || level > 0)
6888
- : compressionMethod !== COMPRESSION_METHOD_STORE);
7008
+ const compressed = !directory && isCompressed(compressionMethod, level);
6889
7009
  let rawLocalExtraFieldZip64;
6890
7010
  const uncompressedFile = passThrough || !compressed;
6891
7011
  const zip64ExtraFieldComplete = zip64 && (options.bufferedWrite || !dataDescriptor || ((!zip64UncompressedSize && !zip64CompressedSize) || uncompressedFile));
@@ -7572,6 +7692,16 @@ function getOptionValue(zipWriter, options, name, defaultValue) {
7572
7692
  return result === UNDEFINED_VALUE ? defaultValue : result;
7573
7693
  }
7574
7694
 
7695
+ function getAliasedOptionValue(zipWriter, options, name, deprecatedName, defaultValue) {
7696
+ const value = getAliasedValue(options, name, deprecatedName);
7697
+ const result = value === UNDEFINED_VALUE ? getAliasedValue(zipWriter.options, name, deprecatedName) : value;
7698
+ return result === UNDEFINED_VALUE ? defaultValue : result;
7699
+ }
7700
+
7701
+ function getAliasedValue(options, name, deprecatedName) {
7702
+ return options[name] === UNDEFINED_VALUE ? options[deprecatedName] : options[name];
7703
+ }
7704
+
7575
7705
  function getNumberOptionValue(zipWriter, options, name, defaultValue) {
7576
7706
  return toNumber(getOptionValue(zipWriter, options, name, defaultValue));
7577
7707
  }
@@ -7584,6 +7714,12 @@ function getMaximumCompressedSize(uncompressedSize) {
7584
7714
  return uncompressedSize + (5 * (Math.floor(uncompressedSize / 16383) + 1));
7585
7715
  }
7586
7716
 
7717
+ function isCompressed(compressionMethod, level) {
7718
+ return compressionMethod === UNDEFINED_VALUE
7719
+ ? (level === UNDEFINED_VALUE || level > 0)
7720
+ : compressionMethod !== COMPRESSION_METHOD_STORE;
7721
+ }
7722
+
7587
7723
  function setUint8(view, offset, value) {
7588
7724
  view.setUint8(offset, value);
7589
7725
  }
@@ -8597,6 +8733,7 @@ U(setDefaultConfiguration);
8597
8733
 
8598
8734
  const ERR_ENTRY_EXISTS = "Entry filename already exists";
8599
8735
  const ERR_READABLE_CONSUMED = "Readable stream already consumed";
8736
+ const ERR_INVALID_PASS_THROUGH = "Invalid passThrough option (use readerOptions.passThrough or set uncompressedSize for each entry)";
8600
8737
  const ERR_ABORT_EXPORT = "zipjs-abort-export";
8601
8738
  const ERR_ABORTED = "The operation was aborted";
8602
8739
  const ABORT_ERROR_NAME = "AbortError";
@@ -8634,6 +8771,7 @@ class ZipEntry {
8634
8771
  parent,
8635
8772
  children: [],
8636
8773
  uncompressedSize: params.uncompressedSize || 0,
8774
+ undeterminedSize: params.undeterminedSize || params.uncompressedSize === UNDEFINED_VALUE,
8637
8775
  passThrough: params.passThrough
8638
8776
  });
8639
8777
  if (parent || !fs.root) {
@@ -8701,16 +8839,17 @@ class ZipFileEntry extends ZipEntry {
8701
8839
 
8702
8840
  async getData(writer, options = {}) {
8703
8841
  const zipEntry = this;
8704
- if (!writer || (writer.constructor == zipEntry.Writer && zipEntry.data)) {
8842
+ if (!writer || (writer.constructor == zipEntry.Writer && zipEntry.data && keepsContentType(writer, zipEntry.data))) {
8705
8843
  return zipEntry.data;
8706
8844
  } else {
8707
8845
  const reader = zipEntry.reader = createReader(zipEntry.Reader, zipEntry.data, options);
8708
- const uncompressedSize = zipEntry.data ? zipEntry.data.uncompressedSize : reader.size;
8709
- await Promise.all([initStream(reader), initStream(writer, uncompressedSize)]);
8710
- const { readable } = reader;
8846
+ const dataSize = zipEntry.uncompressedSize || reader.size;
8847
+ await Promise.all([initStream(reader), initStream(writer, dataSize)]);
8711
8848
  const { signal } = options;
8849
+ const readable = createProgressReadable(zipEntry, reader, options, signal);
8850
+ const preventClose = !ownsWritable(writer) && Boolean(options.preventClose);
8712
8851
  zipEntry.uncompressedSize = reader.size;
8713
- await toCompatibleReadable(readable).pipeTo(toCompatibleWritable(writer.writable), { signal });
8852
+ await toCompatibleReadable(readable).pipeTo(toCompatibleWritable(writer.writable), { signal, preventClose, preventAbort: preventClose });
8714
8853
  return writer.getData ? writer.getData() : writer.writable;
8715
8854
  }
8716
8855
  }
@@ -8841,7 +8980,7 @@ class ZipDirectoryEntry extends ZipEntry {
8841
8980
  Reader: TextReader,
8842
8981
  Writer: TextWriter,
8843
8982
  options,
8844
- uncompressedSize: text.length
8983
+ uncompressedSize: getTextSize(text)
8845
8984
  });
8846
8985
  }
8847
8986
 
@@ -8970,10 +9109,16 @@ class ZipDirectoryEntry extends ZipEntry {
8970
9109
  }
8971
9110
 
8972
9111
  async importZip(reader, options = {}) {
8973
- await initStream(reader);
8974
- const zipReader = new ZipReader(reader, options);
9112
+ let zipReader;
9113
+ if (reader && typeof reader.getEntries == FUNCTION_TYPE) {
9114
+ zipReader = reader;
9115
+ options = Object.assign({}, zipReader.options, options);
9116
+ } else {
9117
+ await initStream(reader);
9118
+ zipReader = new ZipReader(reader, options);
9119
+ }
8975
9120
  const importedEntries = [];
8976
- const entries = await zipReader.getEntries();
9121
+ const entries = await zipReader.getEntries(options);
8977
9122
  for (const entry of entries) {
8978
9123
  let parent = this;
8979
9124
  try {
@@ -8995,7 +9140,7 @@ class ZipDirectoryEntry extends ZipEntry {
8995
9140
  importedEntries.push(addChild(parent, name, {
8996
9141
  data: entry,
8997
9142
  Reader: getZipBlobReader(Object.assign({}, options)),
8998
- uncompressedSize: entry.uncompressedSize,
9143
+ uncompressedSize: options.passThrough ? entry.compressedSize : entry.uncompressedSize,
8999
9144
  passThrough: options.passThrough
9000
9145
  }));
9001
9146
  } else {
@@ -9037,11 +9182,25 @@ class ZipDirectoryEntry extends ZipEntry {
9037
9182
  }
9038
9183
  const [readers] = await Promise.all([initReaders(zipEntry, options.readerOptions), initStream(writer)]);
9039
9184
  const zipWriter = new ZipWriter(writer, options);
9040
- await exportZip(zipWriter, zipEntry, getTotalSize([zipEntry], "uncompressedSize"), options, readers);
9041
- await zipWriter.close();
9185
+ await exportZip(zipWriter, zipEntry, getTotalSize([zipEntry], getUncompressedSize), options, readers);
9186
+ await zipWriter.close(options.globalComment);
9042
9187
  return writer.getData ? writer.getData() : writer.writable;
9043
9188
  }
9044
9189
 
9190
+ getExportedSize(options = {}) {
9191
+ const zipEntry = this;
9192
+ options = Object.assign({}, options);
9193
+ if (options.bufferedWrite === UNDEFINED_VALUE) {
9194
+ options.bufferedWrite = true;
9195
+ }
9196
+ const writeOrderGuaranteed = !options.bufferedWrite ||
9197
+ (options.keepOrder !== false && zipEntry.children.every(child => !child.children.length));
9198
+ return getEntriesSize(options, Array.from(zipEntry.getChildren({ recursive: true }), child => {
9199
+ const { name, entryOptions } = getChildEntryOptions(child, zipEntry, options);
9200
+ return { name, size: child.directory ? 0 : getDeterminedSize(child, isPassThrough(child, options)), options: entryOptions };
9201
+ }), writeOrderGuaranteed, options.globalComment);
9202
+ }
9203
+
9045
9204
  getChildByName(name) {
9046
9205
  const children = this.children;
9047
9206
  for (let childIndex = 0; childIndex < children.length; childIndex++) {
@@ -9249,6 +9408,10 @@ class FS {
9249
9408
  return this.root.exportZip(writer, options);
9250
9409
  }
9251
9410
 
9411
+ getExportedSize(options) {
9412
+ return this.root.getExportedSize(options);
9413
+ }
9414
+
9252
9415
  isPasswordProtected() {
9253
9416
  return this.root.isPasswordProtected();
9254
9417
  }
@@ -9260,12 +9423,12 @@ class FS {
9260
9423
 
9261
9424
  const fs = { FS, ZipDirectoryEntry, ZipFileEntry };
9262
9425
 
9263
- function getTotalSize(entries, propertyName) {
9426
+ function getTotalSize(entries, getEntrySize) {
9264
9427
  let size = 0;
9265
9428
  const pendingEntries = Array.from(entries);
9266
9429
  while (pendingEntries.length) {
9267
9430
  const entry = pendingEntries.pop();
9268
- size += entry[propertyName] || 0;
9431
+ size += getEntrySize(entry) || 0;
9269
9432
  for (const child of entry.children) {
9270
9433
  pendingEntries.push(child);
9271
9434
  }
@@ -9273,6 +9436,15 @@ function getTotalSize(entries, propertyName) {
9273
9436
  return size;
9274
9437
  }
9275
9438
 
9439
+ function getUncompressedSize(entry) {
9440
+ return entry.uncompressedSize;
9441
+ }
9442
+
9443
+ function getExtractedSize(entry, passThrough) {
9444
+ const { data } = entry;
9445
+ return passThrough && data instanceof Entry ? data.compressedSize : entry.uncompressedSize;
9446
+ }
9447
+
9276
9448
  function getReadableReader(readable) {
9277
9449
  let consumed;
9278
9450
  return function () {
@@ -9295,10 +9467,17 @@ function getZipBlobReader(options) {
9295
9467
 
9296
9468
  async init() {
9297
9469
  const zipBlobReader = this;
9298
- zipBlobReader.size = zipBlobReader.entry.uncompressedSize;
9299
- const data = await zipBlobReader.entry.getData(new BlobWriter(), Object.assign({}, options, zipBlobReader.options));
9470
+ const readerOptions = Object.assign({}, options, zipBlobReader.options);
9471
+ const { checkOverlappingEntry, checkOverlappingEntryOnly } = readerOptions;
9472
+ const data = await zipBlobReader.entry.getData(new BlobWriter(), Object.assign(readerOptions, {
9473
+ checkPasswordOnly: false,
9474
+ checkOverlappingEntry: checkOverlappingEntryOnly || checkOverlappingEntry,
9475
+ checkOverlappingEntryOnly: false,
9476
+ preventClose: false
9477
+ }));
9300
9478
  zipBlobReader.data = data;
9301
9479
  zipBlobReader.blobReader = new BlobReader(data);
9480
+ zipBlobReader.size = data.size;
9302
9481
  super.init();
9303
9482
  }
9304
9483
 
@@ -9312,6 +9491,30 @@ function createReader(Reader, data, options) {
9312
9491
  return Reader.prototype ? new Reader(data, options) : Reader(data, options);
9313
9492
  }
9314
9493
 
9494
+ function keepsContentType(writer, data) {
9495
+ const { contentType } = writer;
9496
+ if (contentType === UNDEFINED_VALUE) {
9497
+ return true;
9498
+ } else if (writer.constructor == BlobWriter) {
9499
+ return data.type == contentType;
9500
+ } else if (writer.constructor == Data64URIWriter) {
9501
+ return data.startsWith(writer.data);
9502
+ } else {
9503
+ return true;
9504
+ }
9505
+ }
9506
+
9507
+ function createProgressReadable(zipEntry, reader, options, signal) {
9508
+ const { onstart, onprogress, onend } = options;
9509
+ const { readable } = reader;
9510
+ const coreReaderReportsProgress = zipEntry.data instanceof Entry;
9511
+ if (coreReaderReportsProgress || (!onstart && !onprogress && !onend)) {
9512
+ return readable;
9513
+ } else {
9514
+ return toCompatibleReadable(readable).pipeThrough(new ProgressWatcherStream({ onstart, onprogress, onend, size: reader.size }), { signal });
9515
+ }
9516
+ }
9517
+
9315
9518
  async function initReaders(entry, options) {
9316
9519
  const fileEntries = [];
9317
9520
  const pendingEntries = [entry];
@@ -9344,6 +9547,7 @@ async function initReaders(entry, options) {
9344
9547
  }
9345
9548
  if (reader.size !== UNDEFINED_VALUE) {
9346
9549
  child.uncompressedSize = reader.size;
9550
+ child.undeterminedSize = false;
9347
9551
  }
9348
9552
  }));
9349
9553
  return readers;
@@ -9393,6 +9597,90 @@ function aggregateEntryErrors(errors) {
9393
9597
  return error;
9394
9598
  }
9395
9599
 
9600
+ function getChildEntryOptions(child, selectedEntry, options) {
9601
+ const name = options.relativePath ? child.getRelativeName(selectedEntry) : child.getFullname();
9602
+ const childOptions = child.options || {};
9603
+ let zipEntryMetadata = {};
9604
+ let passThroughOptions = {};
9605
+ if (child.data instanceof Entry) {
9606
+ const {
9607
+ externalFileAttributes,
9608
+ versionMadeBy,
9609
+ comment,
9610
+ lastModDate,
9611
+ creationDate,
9612
+ lastAccessDate,
9613
+ uncompressedSize,
9614
+ encrypted,
9615
+ zipCrypto,
9616
+ crc32,
9617
+ compressionMethod,
9618
+ extraFieldAES,
9619
+ internalFileAttributes,
9620
+ extraField,
9621
+ uid,
9622
+ gid
9623
+ } = child.data;
9624
+ zipEntryMetadata = {
9625
+ externalFileAttributes,
9626
+ versionMadeBy,
9627
+ comment,
9628
+ lastModDate,
9629
+ creationDate,
9630
+ lastAccessDate,
9631
+ internalFileAttributes
9632
+ };
9633
+ const userExtraField = getUserExtraField(extraField);
9634
+ if (userExtraField) {
9635
+ zipEntryMetadata.extraField = userExtraField;
9636
+ }
9637
+ if (uid !== UNDEFINED_VALUE || gid !== UNDEFINED_VALUE) {
9638
+ Object.assign(zipEntryMetadata, {
9639
+ uid,
9640
+ gid,
9641
+ unixExtraFieldType: INFOZIP_EXTRA_FIELD_TYPE
9642
+ });
9643
+ }
9644
+ if (isPassThrough(child, options)) {
9645
+ let level, encryptionStrength;
9646
+ if (compressionMethod === 0) {
9647
+ level = 0;
9648
+ }
9649
+ if (extraFieldAES) {
9650
+ encryptionStrength = extraFieldAES.strength;
9651
+ }
9652
+ passThroughOptions = {
9653
+ passThrough: true,
9654
+ encrypted,
9655
+ zipCrypto,
9656
+ crc32,
9657
+ uncompressedSize,
9658
+ level,
9659
+ encryptionStrength,
9660
+ compressionMethod
9661
+ };
9662
+ }
9663
+ }
9664
+ const entryOptions = Object.assign({}, zipEntryMetadata, options, passThroughOptions, childOptions, { directory: child.directory });
9665
+ if (!child.directory && entryOptions.passThrough && entryOptions.uncompressedSize === UNDEFINED_VALUE) {
9666
+ throw new Error(ERR_INVALID_PASS_THROUGH);
9667
+ }
9668
+ return { name, entryOptions };
9669
+ }
9670
+
9671
+ function getDeterminedSize(child, passThrough) {
9672
+ const { reader } = child;
9673
+ if (reader && reader.size !== UNDEFINED_VALUE) {
9674
+ return reader.size;
9675
+ }
9676
+ return child.undeterminedSize ? UNDEFINED_VALUE : getExtractedSize(child, passThrough);
9677
+ }
9678
+
9679
+ function isPassThrough(child, options) {
9680
+ const { readerOptions } = options;
9681
+ return Boolean(!child.directory && (child.passThrough || (readerOptions && readerOptions.passThrough)));
9682
+ }
9683
+
9396
9684
  function getUserExtraField(extraField) {
9397
9685
  if (extraField) {
9398
9686
  const userExtraField = new Map();
@@ -9408,8 +9696,14 @@ function getUserExtraField(extraField) {
9408
9696
  }
9409
9697
 
9410
9698
  async function exportZip(zipWriter, entry, totalSize, options, readers) {
9699
+ const { onstart, onprogress, onend, onentryprogress } = options;
9411
9700
  const selectedEntry = entry;
9412
- const entryOffsets = new Map();
9701
+ const totalEntries = getTotalSize(entry.children, () => 1);
9702
+ let writtenSize = 0;
9703
+ let writtenEntries = 0;
9704
+ if (onstart) {
9705
+ await callHandler(onstart, totalSize);
9706
+ }
9413
9707
  if (options.bufferedWrite) {
9414
9708
  await processChildren(entry);
9415
9709
  } else {
@@ -9417,6 +9711,9 @@ async function exportZip(zipWriter, entry, totalSize, options, readers) {
9417
9711
  await addChild(child);
9418
9712
  }
9419
9713
  }
9714
+ if (onend) {
9715
+ await callHandler(onend, writtenSize);
9716
+ }
9420
9717
 
9421
9718
  async function processChildren(entry) {
9422
9719
  const results = await Promise.allSettled(entry.children.map(async child => {
@@ -9430,81 +9727,23 @@ async function exportZip(zipWriter, entry, totalSize, options, readers) {
9430
9727
  }
9431
9728
 
9432
9729
  async function addChild(child) {
9433
- const name = options.relativePath ? child.getRelativeName(selectedEntry) : child.getFullname();
9434
- const childOptions = child.options || {};
9435
- let zipEntryOptions = {};
9436
- if (child.data instanceof Entry) {
9437
- const {
9438
- externalFileAttributes,
9439
- versionMadeBy,
9440
- comment,
9441
- lastModDate,
9442
- creationDate,
9443
- lastAccessDate,
9444
- uncompressedSize,
9445
- encrypted,
9446
- zipCrypto,
9447
- crc32,
9448
- compressionMethod,
9449
- extraFieldAES,
9450
- internalFileAttributes,
9451
- extraField,
9452
- uid,
9453
- gid
9454
- } = child.data;
9455
- zipEntryOptions = {
9456
- externalFileAttributes,
9457
- versionMadeBy,
9458
- comment,
9459
- lastModDate,
9460
- creationDate,
9461
- lastAccessDate,
9462
- internalFileAttributes
9463
- };
9464
- const userExtraField = getUserExtraField(extraField);
9465
- if (userExtraField) {
9466
- zipEntryOptions.extraField = userExtraField;
9467
- }
9468
- if (uid !== UNDEFINED_VALUE || gid !== UNDEFINED_VALUE) {
9469
- Object.assign(zipEntryOptions, {
9470
- uid,
9471
- gid,
9472
- unixExtraFieldType: options.unixExtraFieldType || INFOZIP_EXTRA_FIELD_TYPE
9473
- });
9474
- }
9475
- if (child.passThrough) {
9476
- let level, encryptionStrength;
9477
- if (compressionMethod === 0) {
9478
- level = 0;
9479
- }
9480
- if (extraFieldAES) {
9481
- encryptionStrength = extraFieldAES.strength;
9482
- }
9483
- zipEntryOptions = Object.assign(zipEntryOptions, {
9484
- passThrough: true,
9485
- encrypted,
9486
- zipCrypto,
9487
- crc32,
9488
- uncompressedSize,
9489
- level,
9490
- encryptionStrength,
9491
- compressionMethod
9492
- });
9493
- }
9494
- }
9495
- await zipWriter.add(name, readers.get(child), Object.assign({}, options, zipEntryOptions, childOptions, {
9496
- directory: child.directory,
9730
+ const { name, entryOptions } = getChildEntryOptions(child, selectedEntry, options);
9731
+ let entryWrittenSize = 0;
9732
+ const entryMetadata = await zipWriter.add(name, readers.get(child), Object.assign(entryOptions, {
9733
+ onstart: UNDEFINED_VALUE,
9734
+ onend: UNDEFINED_VALUE,
9497
9735
  onprogress: async indexProgress => {
9498
- if (options.onprogress) {
9499
- entryOffsets.set(name, indexProgress);
9500
- try {
9501
- await options.onprogress(Array.from(entryOffsets.values()).reduce((previousValue, currentValue) => previousValue + currentValue), totalSize);
9502
- } catch {
9503
- // ignored
9504
- }
9736
+ writtenSize += indexProgress - entryWrittenSize;
9737
+ entryWrittenSize = indexProgress;
9738
+ if (onprogress) {
9739
+ await callHandler(onprogress, writtenSize, totalSize);
9505
9740
  }
9506
9741
  }
9507
9742
  }));
9743
+ writtenEntries++;
9744
+ if (onentryprogress) {
9745
+ await callHandler(onentryprogress, writtenEntries, totalEntries, entryMetadata);
9746
+ }
9508
9747
  }
9509
9748
  }
9510
9749
 
@@ -9532,7 +9771,7 @@ function addFileSystemHandle(zipEntry, handle, options) {
9532
9771
  })
9533
9772
  );
9534
9773
  } else if (handle.kind == "directory") {
9535
- const directoryEntry = parentEntry.addDirectory(handle.name);
9774
+ const directoryEntry = parentEntry.addDirectory(handle.name, options);
9536
9775
  addedEntries.push(directoryEntry);
9537
9776
  for await (const childHandle of handle.values()) {
9538
9777
  await addFile(directoryEntry, childHandle, addedEntries, entryName);
@@ -9554,15 +9793,29 @@ function addFileSystemHandle(zipEntry, handle, options) {
9554
9793
  }
9555
9794
 
9556
9795
  async function exportFileSystemHandle(zipEntry, directoryHandle, options) {
9557
- const totalSize = getTotalSize([zipEntry], "uncompressedSize");
9558
- const writtenSizes = new Map();
9796
+ const { onstart, onprogress, onend } = options;
9559
9797
  const abortController = new AbortController();
9560
9798
  const { signal } = abortController;
9561
9799
  const releaseSignal = forwardAbort(options.signal, abortController);
9800
+ const getDataOptions = Object.assign({}, options, options.readerOptions, {
9801
+ signal,
9802
+ onstart: UNDEFINED_VALUE,
9803
+ onprogress: UNDEFINED_VALUE,
9804
+ onend: UNDEFINED_VALUE,
9805
+ preventClose: false
9806
+ });
9807
+ const totalSize = getTotalSize([zipEntry], entry => getExtractedSize(entry, getDataOptions.passThrough));
9562
9808
  const exportedEntryNames = [];
9563
9809
  let exportAborted = false;
9810
+ let writtenSize = 0;
9564
9811
  try {
9812
+ if (onstart) {
9813
+ await callHandler(onstart, totalSize);
9814
+ }
9565
9815
  await exportChildren(zipEntry, directoryHandle);
9816
+ if (onend) {
9817
+ await callHandler(onend, writtenSize);
9818
+ }
9566
9819
  } catch (error) {
9567
9820
  try {
9568
9821
  error.exportedEntryNames = exportedEntryNames;
@@ -9575,6 +9828,25 @@ async function exportFileSystemHandle(zipEntry, directoryHandle, options) {
9575
9828
  }
9576
9829
  return directoryHandle;
9577
9830
 
9831
+ function createProgressWritable(writable) {
9832
+ const writer = writable.getWriter();
9833
+ return new WritableStream({
9834
+ async write(chunk) {
9835
+ await writer.write(chunk);
9836
+ writtenSize += chunk.length;
9837
+ if (onprogress) {
9838
+ await callHandler(onprogress, writtenSize, totalSize);
9839
+ }
9840
+ },
9841
+ close() {
9842
+ return writer.close();
9843
+ },
9844
+ abort(reason) {
9845
+ return writer.abort(reason);
9846
+ }
9847
+ });
9848
+ }
9849
+
9578
9850
  async function exportChildren(entry, parentHandle) {
9579
9851
  if (options.concurrent) {
9580
9852
  const results = await Promise.allSettled(entry.children.map(child => exportChild(child, parentHandle)));
@@ -9606,19 +9878,7 @@ async function exportFileSystemHandle(zipEntry, directoryHandle, options) {
9606
9878
  const fileHandle = await parentHandle.getFileHandle(child.name, { create: true });
9607
9879
  const writable = await fileHandle.createWritable();
9608
9880
  try {
9609
- await child.getData({ writable }, Object.assign({}, options, {
9610
- signal,
9611
- onprogress: async progress => {
9612
- if (options.onprogress) {
9613
- writtenSizes.set(child.id, progress);
9614
- try {
9615
- await options.onprogress(Array.from(writtenSizes.values()).reduce((previousValue, currentValue) => previousValue + currentValue, 0), totalSize);
9616
- } catch {
9617
- // ignored
9618
- }
9619
- }
9620
- }
9621
- }));
9881
+ await child.getData({ writable: createProgressWritable(writable) }, getDataOptions);
9622
9882
  } catch (error) {
9623
9883
  throw exportAborted ? new Error(ERR_ABORT_EXPORT) : error;
9624
9884
  }
@@ -9862,6 +10122,7 @@ exports.ERR_INVALID_MSDOS_ATTRIBUTES = ERR_INVALID_MSDOS_ATTRIBUTES;
9862
10122
  exports.ERR_INVALID_MSDOS_DATA = ERR_INVALID_MSDOS_DATA;
9863
10123
  exports.ERR_INVALID_PASSWORD = ERR_INVALID_PASSWORD;
9864
10124
  exports.ERR_INVALID_PASSWORD_TYPE = ERR_INVALID_PASSWORD_TYPE;
10125
+ exports.ERR_INVALID_PASS_THROUGH = ERR_INVALID_PASS_THROUGH;
9865
10126
  exports.ERR_INVALID_SIGNATURE = ERR_INVALID_SIGNATURE;
9866
10127
  exports.ERR_INVALID_SIGNATURE_DATA = ERR_INVALID_SIGNATURE_DATA;
9867
10128
  exports.ERR_INVALID_STRICTNESS = ERR_INVALID_STRICTNESS;
@@ -9879,11 +10140,13 @@ exports.ERR_RESERVED_COMPRESSION_METHOD = ERR_RESERVED_COMPRESSION_METHOD;
9879
10140
  exports.ERR_SPLIT_ZIP_FILE = ERR_SPLIT_ZIP_FILE;
9880
10141
  exports.ERR_UNDEFINED_READER = ERR_UNDEFINED_READER;
9881
10142
  exports.ERR_UNDEFINED_UNCOMPRESSED_SIZE = ERR_UNDEFINED_UNCOMPRESSED_SIZE;
10143
+ exports.ERR_UNDETERMINED_SIZE = ERR_UNDETERMINED_SIZE;
9882
10144
  exports.ERR_UNSAFE_FILENAME = ERR_UNSAFE_FILENAME;
9883
10145
  exports.ERR_UNSUPPORTED_COMPRESSION = ERR_UNSUPPORTED_COMPRESSION$1;
9884
10146
  exports.ERR_UNSUPPORTED_CONTEXT = ERR_UNSUPPORTED_CONTEXT;
9885
10147
  exports.ERR_UNSUPPORTED_CRYPTO_API = ERR_UNSUPPORTED_CRYPTO_API;
9886
10148
  exports.ERR_UNSUPPORTED_ENCRYPTION = ERR_UNSUPPORTED_ENCRYPTION;
10149
+ exports.ERR_UNSUPPORTED_ENCRYPTION_PASS_THROUGH = ERR_UNSUPPORTED_ENCRYPTION_PASS_THROUGH;
9887
10150
  exports.ERR_UNSUPPORTED_ENCRYPTION_USDZ = ERR_UNSUPPORTED_ENCRYPTION_USDZ;
9888
10151
  exports.ERR_UNSUPPORTED_FORMAT = ERR_UNSUPPORTED_FORMAT;
9889
10152
  exports.ERR_WORKER_STARTUP_TIMEOUT = ERR_WORKER_STARTUP_TIMEOUT;