@zip.js/zip.js 2.8.51 → 2.8.53

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.
Files changed (41) hide show
  1. package/README.md +8 -3
  2. package/deno.json +1 -1
  3. package/dist/zip-core-external.js +241 -95
  4. package/dist/zip-core-external.min.js +1 -1
  5. package/dist/zip-core.js +243 -94
  6. package/dist/zip-core.min.js +1 -1
  7. package/dist/zip-fs-core-external.js +564 -199
  8. package/dist/zip-fs-core-external.min.js +1 -1
  9. package/dist/zip-fs-core.js +551 -194
  10. package/dist/zip-fs-core.min.js +1 -1
  11. package/dist/zip-fs-external.js +564 -199
  12. package/dist/zip-fs-external.min.js +1 -1
  13. package/dist/zip-fs-native.js +567 -198
  14. package/dist/zip-fs-native.min.js +1 -1
  15. package/dist/zip-fs.js +567 -198
  16. package/dist/zip-fs.min.js +1 -1
  17. package/dist/zip-legacy.js +243 -94
  18. package/dist/zip-legacy.min.js +1 -1
  19. package/dist/zip-native.js +243 -94
  20. package/dist/zip-native.min.js +1 -1
  21. package/dist/zip.js +243 -94
  22. package/dist/zip.min.js +1 -1
  23. package/eslint.config.mjs +1 -1
  24. package/index-native.cjs +567 -198
  25. package/index-native.min.js +1 -1
  26. package/index.cjs +567 -198
  27. package/index.d.cts +551 -45
  28. package/index.d.ts +551 -45
  29. package/index.min.js +1 -1
  30. package/lib/core/codec-worker-web.js +13 -4
  31. package/lib/core/codec-worker.js +2 -0
  32. package/lib/core/constants.js +9 -0
  33. package/lib/core/io.js +43 -4
  34. package/lib/core/options.js +2 -0
  35. package/lib/core/util/compatible-streams.js +3 -8
  36. package/lib/core/zip-entry.js +16 -0
  37. package/lib/core/zip-fs.js +236 -107
  38. package/lib/core/zip-reader.js +106 -40
  39. package/lib/core/zip-writer.js +171 -41
  40. package/lib/zip-core-writer.js +3 -0
  41. package/package.json +9 -7
@@ -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;
@@ -100,6 +102,9 @@
100
102
  const VERSION_ZIP64 = 0x2D;
101
103
  const VERSION_AES = 0x33;
102
104
 
105
+ const VERSION_MADE_BY_MSDOS = 0x0014;
106
+ const VERSION_MADE_BY_UNIX = 0x0300;
107
+
103
108
  const DIRECTORY_SIGNATURE = "/";
104
109
 
105
110
  const HEADER_SIZE = 30;
@@ -1781,8 +1786,6 @@
1781
1786
  */
1782
1787
 
1783
1788
 
1784
- const HTTP_HEADER_CONTENT_TYPE = "Content-Type";
1785
-
1786
1789
  function toCompatibleReadable(readable) {
1787
1790
  if (readable instanceof ReadableStream) {
1788
1791
  return readable;
@@ -1805,12 +1808,9 @@
1805
1808
 
1806
1809
  function streamToBlob(readable, contentType) {
1807
1810
  readable = toCompatibleReadable(readable);
1811
+ const blobOptions = contentType ? { type: contentType } : {};
1808
1812
  if (responseSupportsGlobalReadable()) {
1809
- const options = {};
1810
- if (contentType) {
1811
- options.headers = [[HTTP_HEADER_CONTENT_TYPE, contentType]];
1812
- }
1813
- return new Response(readable, options).blob();
1813
+ return new Response(readable).blob().then(blob => contentType ? new Blob([blob], blobOptions) : blob);
1814
1814
  }
1815
1815
  const chunks = [];
1816
1816
  return readable
@@ -1819,7 +1819,7 @@
1819
1819
  chunks.push(chunk);
1820
1820
  }
1821
1821
  }))
1822
- .then(() => new Blob(chunks, contentType ? { type: contentType } : {}));
1822
+ .then(() => new Blob(chunks, blobOptions));
1823
1823
  }
1824
1824
 
1825
1825
  function responseSupportsGlobalReadable() {
@@ -2761,6 +2761,7 @@
2761
2761
  worker,
2762
2762
  workerAlive: false,
2763
2763
  terminated: false,
2764
+ startupError: null,
2764
2765
  interface: {
2765
2766
  run: async () => {
2766
2767
  try {
@@ -2788,6 +2789,13 @@
2788
2789
  }
2789
2790
 
2790
2791
  async function runWebWorker(workerData, config) {
2792
+ if (!workerData.worker) {
2793
+ const { startupError } = workerData;
2794
+ workerData.startupError = null;
2795
+ const error = startupError || new Error(ERR_WORKER_STARTUP_TIMEOUT);
2796
+ error.workerStartupFailed = true;
2797
+ throw error;
2798
+ }
2791
2799
  let resolveResult, rejectResult;
2792
2800
  const result = new Promise((resolve, reject) => {
2793
2801
  resolveResult = resolve;
@@ -3001,11 +3009,12 @@
3001
3009
  if (!workerAlive) {
3002
3010
  workerData.worker = null;
3003
3011
  }
3012
+ let error = event.error || new Error(event.message || ERROR_EVENT_TYPE);
3013
+ if (!workerAlive) {
3014
+ error = Object.assign(new Error(error.message || ERROR_EVENT_TYPE), { workerStartupFailed: true });
3015
+ workerData.startupError = error;
3016
+ }
3004
3017
  if (rejectResult) {
3005
- let error = event.error || new Error(event.message || ERROR_EVENT_TYPE);
3006
- if (!workerAlive) {
3007
- error = Object.assign(new Error(error.message || ERROR_EVENT_TYPE), { workerStartupFailed: true });
3008
- }
3009
3018
  rejectResult(error);
3010
3019
  if (writer) {
3011
3020
  writer.releaseLock();
@@ -3350,8 +3359,10 @@
3350
3359
  async pull(controller) {
3351
3360
  const dataSize = size === UNDEFINED_VALUE ? chunkSize : Math.min(chunkSize, size - chunkOffset);
3352
3361
  const data = await readUint8Array(reader, offset + chunkOffset, dataSize);
3353
- controller.enqueue(data);
3354
- if ((chunkOffset + chunkSize > size) || (size === UNDEFINED_VALUE && !data.length && dataSize)) {
3362
+ if (data.length) {
3363
+ controller.enqueue(data);
3364
+ }
3365
+ if ((chunkOffset + chunkSize >= size) || (size === UNDEFINED_VALUE && !data.length && dataSize)) {
3355
3366
  controller.close();
3356
3367
  } else {
3357
3368
  chunkOffset += chunkSize;
@@ -3429,6 +3440,7 @@
3429
3440
  constructor(contentType) {
3430
3441
  super();
3431
3442
  Object.assign(this, {
3443
+ contentType,
3432
3444
  data: "data:" + (contentType || "") + ";base64,",
3433
3445
  pending: []
3434
3446
  });
@@ -3530,6 +3542,7 @@
3530
3542
  return transformStream.writable;
3531
3543
  }
3532
3544
  });
3545
+ writer.contentType = contentType;
3533
3546
  writer.blob = streamToBlob(transformStream.readable, contentType);
3534
3547
  writer.blob.catch(() => { });
3535
3548
  }
@@ -3546,6 +3559,26 @@
3546
3559
  }
3547
3560
  }
3548
3561
 
3562
+ function getTextSize(text) {
3563
+ let size = 0;
3564
+ for (let indexCharacter = 0; indexCharacter < text.length; indexCharacter++) {
3565
+ const characterCode = text.charCodeAt(indexCharacter);
3566
+ if (characterCode < 0x80) {
3567
+ size += 1;
3568
+ } else if (characterCode < 0x800) {
3569
+ size += 2;
3570
+ } else if (characterCode < 0xd800 || characterCode >= 0xe000) {
3571
+ size += 3;
3572
+ } else if (characterCode < 0xdc00 && (text.charCodeAt(indexCharacter + 1) & 0xfc00) == 0xdc00) {
3573
+ size += 4;
3574
+ indexCharacter++;
3575
+ } else {
3576
+ size += 3;
3577
+ }
3578
+ }
3579
+ return size;
3580
+ }
3581
+
3549
3582
  class TextWriter extends BlobWriter {
3550
3583
 
3551
3584
  constructor(encoding) {
@@ -4030,9 +4063,8 @@
4030
4063
 
4031
4064
  async init() {
4032
4065
  const reader = this;
4033
- const { readers } = reader;
4034
4066
  reader.lastDiskNumber = 0;
4035
- await Promise.all(readers.map(diskReader => initStream(diskReader)));
4067
+ const readers = reader.readers = await Promise.all(reader.readers.map(initDiskReader));
4036
4068
  reader.diskOffsets = readers.map(diskReader => {
4037
4069
  const diskOffset = reader.size;
4038
4070
  reader.size += diskReader.size;
@@ -4209,6 +4241,10 @@
4209
4241
  }
4210
4242
  }
4211
4243
 
4244
+ function ownsWritable(writer) {
4245
+ return Boolean(writer && writer.getData);
4246
+ }
4247
+
4212
4248
  function isHttpFamily(url) {
4213
4249
  const { baseURI } = getConfiguration();
4214
4250
  const { protocol } = new URL(url, baseURI);
@@ -4223,6 +4259,16 @@
4223
4259
  }
4224
4260
  }
4225
4261
 
4262
+ async function initDiskReader(diskReader) {
4263
+ diskReader = new GenericReader(diskReader);
4264
+ await initStream(diskReader);
4265
+ if (diskReader.size === UNDEFINED_VALUE || !diskReader.readUint8Array) {
4266
+ diskReader = new BlobReader(await streamToBlob(diskReader.readable));
4267
+ await initStream(diskReader);
4268
+ }
4269
+ return diskReader;
4270
+ }
4271
+
4226
4272
  function readUint8Array(reader, offset, size) {
4227
4273
  return reader.readUint8Array(offset, size);
4228
4274
  }
@@ -4353,6 +4399,8 @@
4353
4399
  const PROPERTY_NAME_RAW_CREATION_DATE = "rawCreationDate";
4354
4400
  const PROPERTY_NAME_INTERNAL_FILE_ATTRIBUTES = "internalFileAttributes";
4355
4401
  const PROPERTY_NAME_EXTERNAL_FILE_ATTRIBUTES = "externalFileAttributes";
4402
+ const PROPERTY_NAME_DEPRECATED_INTERNAL_FILE_ATTRIBUTES = "internalFileAttribute";
4403
+ const PROPERTY_NAME_DEPRECATED_EXTERNAL_FILE_ATTRIBUTES = "externalFileAttribute";
4356
4404
  const PROPERTY_NAME_MSDOS_ATTRIBUTES_RAW = "msdosAttributesRaw";
4357
4405
  const PROPERTY_NAME_MSDOS_ATTRIBUTES = "msdosAttributes";
4358
4406
  const PROPERTY_NAME_MS_DOS_COMPATIBLE = "msDosCompatible";
@@ -4363,6 +4411,7 @@
4363
4411
  const PROPERTY_NAME_ZIPCRYPTO = "zipCrypto";
4364
4412
  const PROPERTY_NAME_DIRECTORY = "directory";
4365
4413
  const PROPERTY_NAME_EXECUTABLE = "executable";
4414
+ const PROPERTY_NAME_SYMLINK = "symlink";
4366
4415
  const PROPERTY_NAME_COMPRESSION_METHOD = "compressionMethod";
4367
4416
  const PROPERTY_NAME_SIGNATURE = "signature";
4368
4417
  const PROPERTY_NAME_CRC32 = "crc32";
@@ -4378,6 +4427,10 @@
4378
4427
  const PROPERTY_NAME_SETGID = "setgid";
4379
4428
  const PROPERTY_NAME_STICKY = "sticky";
4380
4429
  const PROPERTY_NAME_BITFLAG = "bitFlag";
4430
+ const PROPERTY_NAME_RAW_BITFLAG = "rawBitFlag";
4431
+ const PROPERTY_NAME_FILENAME_LENGTH = "filenameLength";
4432
+ const PROPERTY_NAME_EXTRA_FIELD_LENGTH = "extraFieldLength";
4433
+ const PROPERTY_NAME_UNIX_EXTERNAL_UPPER = "unixExternalUpper";
4381
4434
  const PROPERTY_NAME_FILENAME_UTF8 = "filenameUTF8";
4382
4435
  const PROPERTY_NAME_COMMENT_UTF8 = "commentUTF8";
4383
4436
  const PROPERTY_NAME_RAW_EXTRA_FIELD = "rawExtraField";
@@ -4406,6 +4459,8 @@
4406
4459
  PROPERTY_NAME_DISK_NUMBER_START,
4407
4460
  PROPERTY_NAME_INTERNAL_FILE_ATTRIBUTES,
4408
4461
  PROPERTY_NAME_EXTERNAL_FILE_ATTRIBUTES,
4462
+ PROPERTY_NAME_DEPRECATED_INTERNAL_FILE_ATTRIBUTES,
4463
+ PROPERTY_NAME_DEPRECATED_EXTERNAL_FILE_ATTRIBUTES,
4409
4464
  PROPERTY_NAME_MSDOS_ATTRIBUTES_RAW,
4410
4465
  PROPERTY_NAME_MSDOS_ATTRIBUTES,
4411
4466
  PROPERTY_NAME_MS_DOS_COMPATIBLE,
@@ -4416,6 +4471,7 @@
4416
4471
  PROPERTY_NAME_ZIPCRYPTO,
4417
4472
  PROPERTY_NAME_DIRECTORY,
4418
4473
  PROPERTY_NAME_EXECUTABLE,
4474
+ PROPERTY_NAME_SYMLINK,
4419
4475
  PROPERTY_NAME_COMPRESSION_METHOD,
4420
4476
  PROPERTY_NAME_SIGNATURE,
4421
4477
  PROPERTY_NAME_CRC32,
@@ -4427,10 +4483,14 @@
4427
4483
  PROPERTY_NAME_UID,
4428
4484
  PROPERTY_NAME_GID,
4429
4485
  PROPERTY_NAME_UNIX_MODE,
4486
+ PROPERTY_NAME_UNIX_EXTERNAL_UPPER,
4430
4487
  PROPERTY_NAME_SETUID,
4431
4488
  PROPERTY_NAME_SETGID,
4432
4489
  PROPERTY_NAME_STICKY,
4433
4490
  PROPERTY_NAME_BITFLAG,
4491
+ PROPERTY_NAME_RAW_BITFLAG,
4492
+ PROPERTY_NAME_FILENAME_LENGTH,
4493
+ PROPERTY_NAME_EXTRA_FIELD_LENGTH,
4434
4494
  PROPERTY_NAME_FILENAME_UTF8,
4435
4495
  PROPERTY_NAME_COMMENT_UTF8,
4436
4496
  PROPERTY_NAME_RAW_EXTRA_FIELD,
@@ -4492,6 +4552,7 @@
4492
4552
  const OPTION_CHECK_OVERLAPPING_ENTRY_ONLY = "checkOverlappingEntryOnly";
4493
4553
  const OPTION_CHECK_OVERLAPPING_ENTRY = "checkOverlappingEntry";
4494
4554
  const OPTION_CHECK_AMBIGUITY = "checkAmbiguity";
4555
+ const OPTION_CHECK_LOCAL_DIRECTORY = "checkLocalDirectory";
4495
4556
  const OPTION_CHECK_SIGNATURE = "checkSignature";
4496
4557
  const OPTION_CHECK_CRC32 = "checkCrc32";
4497
4558
  const OPTION_CHECK_AUTHENTICATION_CODE = "checkAuthenticationCode";
@@ -4623,7 +4684,7 @@
4623
4684
  if (reader.size < END_OF_CENTRAL_DIR_LENGTH) {
4624
4685
  throw new Error(ERR_BAD_FORMAT);
4625
4686
  }
4626
- const strictness = getStrictness(getOptionValue$1(zipReader, options, OPTION_STRICTNESS), getOptionValue$1(zipReader, options, OPTION_CHECK_AMBIGUITY));
4687
+ const strictness = getStrictness(options, zipReader.options);
4627
4688
  const checkAmbiguity = strictness == STRICTNESS_STRICT;
4628
4689
  const rejectAmbiguousEndOfDirectory = strictness != STRICTNESS_TOLERANT;
4629
4690
  const maxAppendedDataSize = getMaxAppendedDataSize(getOptionValue$1(zipReader, options, OPTION_MAX_APPENDED_DATA_SIZE), strictness);
@@ -4845,6 +4906,7 @@
4845
4906
  index: indexFile,
4846
4907
  versionMadeBy,
4847
4908
  msDosCompatible,
4909
+ zip64: false,
4848
4910
  compressedSize: 0,
4849
4911
  uncompressedSize: 0,
4850
4912
  commentLength,
@@ -4878,15 +4940,18 @@
4878
4940
  const setuid = Boolean(fileEntry.unixMode & FILE_ATTR_UNIX_SETUID_MASK);
4879
4941
  const setgid = Boolean(fileEntry.unixMode & FILE_ATTR_UNIX_SETGID_MASK);
4880
4942
  const sticky = Boolean(fileEntry.unixMode & FILE_ATTR_UNIX_STICKY_MASK);
4881
- const executable = (fileEntry.unixMode !== UNDEFINED_VALUE)
4943
+ const unixType = fileEntry.unixMode === UNDEFINED_VALUE ? unixExternalUpper : fileEntry.unixMode;
4944
+ const symlink = (unixType & FILE_ATTR_UNIX_TYPE_MASK) == FILE_ATTR_UNIX_TYPE_SYMLINK;
4945
+ const executable = !symlink && ((fileEntry.unixMode !== UNDEFINED_VALUE)
4882
4946
  ? ((fileEntry.unixMode & FILE_ATTR_UNIX_EXECUTABLE_MASK) != 0)
4883
- : (unixCompatible && ((unixExternalUpper & FILE_ATTR_UNIX_EXECUTABLE_MASK) != 0));
4947
+ : (unixCompatible && ((unixExternalUpper & FILE_ATTR_UNIX_EXECUTABLE_MASK) != 0)));
4884
4948
  const modeIsDir = fileEntry.unixMode !== UNDEFINED_VALUE && ((fileEntry.unixMode & FILE_ATTR_UNIX_TYPE_MASK) == FILE_ATTR_UNIX_TYPE_DIR);
4885
4949
  const upperIsDir = ((unixExternalUpper & FILE_ATTR_UNIX_TYPE_MASK) == FILE_ATTR_UNIX_TYPE_DIR);
4886
4950
  Object.assign(fileEntry, {
4887
4951
  setuid,
4888
4952
  setgid,
4889
4953
  sticky,
4954
+ symlink,
4890
4955
  unixExternalUpper,
4891
4956
  internalFileAttribute: fileEntry.internalFileAttributes,
4892
4957
  externalFileAttribute: fileEntry.externalFileAttributes,
@@ -4952,6 +5017,10 @@
4952
5017
  }
4953
5018
 
4954
5019
  async close() {
5020
+ const { reader } = this;
5021
+ if (!reader.readUint8Array && reader.readable && !reader.readable.locked) {
5022
+ await reader.readable.cancel();
5023
+ }
4955
5024
  }
4956
5025
  }
4957
5026
 
@@ -5048,9 +5117,12 @@
5048
5117
  extraFieldLength,
5049
5118
  filenameLength
5050
5119
  } = localDirectory;
5051
- const checkAmbiguity = getStrictness(getOptionValue$1(zipEntry, options, OPTION_STRICTNESS), getOptionValue$1(zipEntry, options, OPTION_CHECK_AMBIGUITY)) == STRICTNESS_STRICT;
5120
+ const checkLocalDirectoryOption = getOptionValue$1(zipEntry, options, OPTION_CHECK_LOCAL_DIRECTORY);
5121
+ const entryStrictness = getStrictness(options, zipEntry.options);
5122
+ const checkLocalDirectory = getCheckLocalDirectory(checkLocalDirectoryOption, entryStrictness);
5123
+ const checkLocalFilename = getCheckLocalFilename(checkLocalDirectoryOption, entryStrictness);
5052
5124
  let rawLocalFilename = EMPTY_UINT8_ARRAY;
5053
- if (checkAmbiguity && (filenameLength || extraFieldLength)) {
5125
+ if (checkLocalFilename && (filenameLength || extraFieldLength)) {
5054
5126
  const trailingDataArray = await readUint8Array(reader, localHeaderOffset + HEADER_SIZE, filenameLength + extraFieldLength);
5055
5127
  rawLocalFilename = trailingDataArray.subarray(0, filenameLength);
5056
5128
  localDirectory.rawExtraField = trailingDataArray.subarray(filenameLength);
@@ -5059,17 +5131,26 @@
5059
5131
  await readUint8Array(reader, localHeaderOffset + HEADER_SIZE + filenameLength, extraFieldLength) :
5060
5132
  EMPTY_UINT8_ARRAY;
5061
5133
  }
5134
+ if (checkLocalFilename) {
5135
+ localDirectory.rawFilename = rawLocalFilename;
5136
+ }
5062
5137
  readCommonFooter(zipEntry, localDirectory, dataView, 4, true);
5063
- if (checkAmbiguity) {
5064
- checkLocalDirectory(zipEntry, localDirectory, rawLocalFilename);
5138
+ if (checkLocalDirectory) {
5139
+ validateLocalDirectory(zipEntry, localDirectory, rawLocalFilename, checkLocalFilename);
5065
5140
  }
5066
- const { lastAccessDate, creationDate } = localDirectory;
5141
+ const { lastAccessDate, creationDate, uid, gid } = localDirectory;
5067
5142
  if (lastAccessDate) {
5068
5143
  fileEntry.lastAccessDate = lastAccessDate;
5069
5144
  }
5070
5145
  if (creationDate) {
5071
5146
  fileEntry.creationDate = creationDate;
5072
5147
  }
5148
+ if (uid !== UNDEFINED_VALUE && fileEntry.uid === UNDEFINED_VALUE) {
5149
+ fileEntry.uid = uid;
5150
+ }
5151
+ if (gid !== UNDEFINED_VALUE && fileEntry.gid === UNDEFINED_VALUE) {
5152
+ fileEntry.gid = gid;
5153
+ }
5073
5154
  const encrypted = zipEntry.encrypted && localDirectory.encrypted && !passThrough;
5074
5155
  const zipCrypto = encrypted && !extraFieldAES;
5075
5156
  if (!passThrough) {
@@ -5176,7 +5257,7 @@
5176
5257
  throw error;
5177
5258
  }
5178
5259
  } finally {
5179
- const preventClose = getOptionValue$1(zipEntry, options, OPTION_PREVENT_CLOSE);
5260
+ const preventClose = !ownsWritable(writer) && getOptionValue$1(zipEntry, options, OPTION_PREVENT_CLOSE);
5180
5261
  if (!preventClose && writable && !writable.locked) {
5181
5262
  const writableWriter = writable.getWriter();
5182
5263
  if (abortError) {
@@ -5305,10 +5386,12 @@
5305
5386
  directory.extraFieldNTFS = extraFieldNTFS;
5306
5387
  }
5307
5388
  const extraFieldUnix = extraField.get(EXTRAFIELD_TYPE_UNIX);
5389
+ let unixIdsRead;
5308
5390
  if (extraFieldUnix) {
5309
- readExtraFieldUnix(extraFieldUnix, directory, false);
5391
+ unixIdsRead = readExtraFieldUnix(extraFieldUnix, directory, false);
5310
5392
  directory.extraFieldUnix = extraFieldUnix;
5311
- } else {
5393
+ }
5394
+ if (!unixIdsRead) {
5312
5395
  const extraFieldInfoZip = extraField.get(EXTRAFIELD_TYPE_INFOZIP);
5313
5396
  if (extraFieldInfoZip) {
5314
5397
  readExtraFieldUnix(extraFieldInfoZip, directory, true);
@@ -5411,7 +5494,7 @@
5411
5494
  const creationDate = getDateNTFS(rawCreationDate);
5412
5495
  const extraFieldData = { lastModDate, lastAccessDate, creationDate };
5413
5496
  Object.assign(extraFieldNTFS, extraFieldData);
5414
- Object.assign(directory, extraFieldData);
5497
+ Object.assign(directory, extraFieldData, { rawLastAccessDate, rawCreationDate });
5415
5498
  }
5416
5499
  }
5417
5500
 
@@ -5420,8 +5503,8 @@
5420
5503
  return;
5421
5504
  }
5422
5505
  const extraFieldView = getDataView(extraField.data);
5423
- const lastAccessDate = new Date(getUint32(extraFieldView, 0) * 1000);
5424
- const lastModDate = new Date(getUint32(extraFieldView, 4) * 1000);
5506
+ const lastAccessDate = new Date((getUint32(extraFieldView, 0) | 0) * 1000);
5507
+ const lastModDate = new Date((getUint32(extraFieldView, 4) | 0) * 1000);
5425
5508
  const extraFieldData = { lastAccessDate, lastModDate };
5426
5509
  if (extraField.data.length >= 12) {
5427
5510
  extraFieldData.uid = getUint16(extraFieldView, 8);
@@ -5455,6 +5538,7 @@
5455
5538
  if (gid !== UNDEFINED_VALUE) {
5456
5539
  directory.gid = gid;
5457
5540
  }
5541
+ return uid !== UNDEFINED_VALUE || gid !== UNDEFINED_VALUE;
5458
5542
  } catch {
5459
5543
  // ignored
5460
5544
  }
@@ -5527,26 +5611,25 @@
5527
5611
  }
5528
5612
  if (dataDescriptorLength) {
5529
5613
  const dataDescriptorArray = await readUint8Array(reader, dataOffset + compressedSize, dataDescriptorLength + DATA_DESCRIPTOR_RECORD_SIGNATURE_LENGTH);
5530
- const dataDescriptorSignature = dataDescriptorArray.length == dataDescriptorLength + DATA_DESCRIPTOR_RECORD_SIGNATURE_LENGTH &&
5531
- getUint32(getDataView(dataDescriptorArray), 0) == DATA_DESCRIPTOR_RECORD_SIGNATURE;
5532
- if (dataDescriptorSignature) {
5533
- const readCrc32 = getUint32(getDataView(dataDescriptorArray), 4);
5534
- let readCompressedSize;
5535
- let readUncompressedSize;
5536
- if (extraFieldZip64) {
5537
- readCompressedSize = getBigUint64(getDataView(dataDescriptorArray), 8);
5538
- readUncompressedSize = getBigUint64(getDataView(dataDescriptorArray), 16);
5539
- } else {
5540
- readCompressedSize = getUint32(getDataView(dataDescriptorArray), 8);
5541
- readUncompressedSize = getUint32(getDataView(dataDescriptorArray), 12);
5542
- }
5543
- const matchCrc32 = (fileEntry.encrypted && !fileEntry.zipCrypto) || readCrc32 == crc32;
5614
+ const dataDescriptorView = getDataView(dataDescriptorArray);
5615
+ let signature = dataDescriptorArray.length == dataDescriptorLength + DATA_DESCRIPTOR_RECORD_SIGNATURE_LENGTH &&
5616
+ getUint32(dataDescriptorView, 0) == DATA_DESCRIPTOR_RECORD_SIGNATURE;
5617
+ if (signature) {
5618
+ const signedDataDescriptor = readDataDescriptor(dataDescriptorView, DATA_DESCRIPTOR_RECORD_SIGNATURE_LENGTH, extraFieldZip64);
5619
+ const matchCrc32 = (fileEntry.encrypted && !fileEntry.zipCrypto) || signedDataDescriptor.crc32 == crc32;
5544
5620
  if (matchCrc32 &&
5545
- readCompressedSize == compressedSize &&
5546
- readUncompressedSize == uncompressedSize) {
5621
+ signedDataDescriptor.compressedSize == compressedSize &&
5622
+ signedDataDescriptor.uncompressedSize == uncompressedSize) {
5547
5623
  dataDescriptorLength += DATA_DESCRIPTOR_RECORD_SIGNATURE_LENGTH;
5624
+ } else {
5625
+ signature = false;
5548
5626
  }
5549
5627
  }
5628
+ if (dataDescriptorArray.length >= dataDescriptorLength) {
5629
+ const localDataDescriptor = readDataDescriptor(dataDescriptorView, signature ? DATA_DESCRIPTOR_RECORD_SIGNATURE_LENGTH : 0, extraFieldZip64);
5630
+ localDataDescriptor.signature = signature;
5631
+ fileEntry.localDirectory.dataDescriptor = localDataDescriptor;
5632
+ }
5550
5633
  }
5551
5634
  const range = {
5552
5635
  start: offset,
@@ -5563,6 +5646,20 @@
5563
5646
  readRanges.set(index, range);
5564
5647
  }
5565
5648
 
5649
+ function readDataDescriptor(dataDescriptorView, offset, extraFieldZip64) {
5650
+ const crc32 = getUint32(dataDescriptorView, offset);
5651
+ let compressedSize;
5652
+ let uncompressedSize;
5653
+ if (extraFieldZip64) {
5654
+ compressedSize = getBigUint64(dataDescriptorView, offset + 4);
5655
+ uncompressedSize = getBigUint64(dataDescriptorView, offset + 12);
5656
+ } else {
5657
+ compressedSize = getUint32(dataDescriptorView, offset + 4);
5658
+ uncompressedSize = getUint32(dataDescriptorView, offset + 8);
5659
+ }
5660
+ return { crc32, compressedSize, uncompressedSize };
5661
+ }
5662
+
5566
5663
  function getDiskOffset$1(reader, diskNumber) {
5567
5664
  return reader.getDiskOffset ? reader.getDiskOffset(diskNumber) : 0;
5568
5665
  }
@@ -5571,14 +5668,40 @@
5571
5668
  return value === STRICTNESS_STRICT || value === STRICTNESS_BALANCED || value === STRICTNESS_TOLERANT;
5572
5669
  }
5573
5670
 
5574
- function getStrictness(strictness, checkAmbiguity) {
5575
- if (strictness === UNDEFINED_VALUE) {
5576
- return checkAmbiguity ? STRICTNESS_STRICT : STRICTNESS_BALANCED;
5671
+ function getStrictness(options, inheritedOptions) {
5672
+ return resolveStrictness(options, resolveStrictness(inheritedOptions, STRICTNESS_BALANCED));
5673
+ }
5674
+
5675
+ function resolveStrictness(options, inheritedStrictness) {
5676
+ const strictness = options[OPTION_STRICTNESS];
5677
+ if (strictness !== UNDEFINED_VALUE) {
5678
+ if (!isStrictnessValue(strictness)) {
5679
+ throw new Error(ERR_INVALID_STRICTNESS);
5680
+ }
5681
+ return strictness;
5577
5682
  }
5578
- if (!isStrictnessValue(strictness)) {
5579
- throw new Error(ERR_INVALID_STRICTNESS);
5683
+ const checkAmbiguity = options[OPTION_CHECK_AMBIGUITY];
5684
+ if (checkAmbiguity === UNDEFINED_VALUE) {
5685
+ return inheritedStrictness;
5580
5686
  }
5581
- return strictness;
5687
+ if (checkAmbiguity) {
5688
+ return STRICTNESS_STRICT;
5689
+ }
5690
+ return inheritedStrictness == STRICTNESS_TOLERANT ? STRICTNESS_TOLERANT : STRICTNESS_BALANCED;
5691
+ }
5692
+
5693
+ function getCheckLocalDirectory(checkLocalDirectory, strictness) {
5694
+ if (checkLocalDirectory === UNDEFINED_VALUE) {
5695
+ return strictness != STRICTNESS_TOLERANT;
5696
+ }
5697
+ return Boolean(checkLocalDirectory);
5698
+ }
5699
+
5700
+ function getCheckLocalFilename(checkLocalFilename, strictness) {
5701
+ if (checkLocalFilename === UNDEFINED_VALUE) {
5702
+ return strictness == STRICTNESS_STRICT;
5703
+ }
5704
+ return Boolean(checkLocalFilename);
5582
5705
  }
5583
5706
 
5584
5707
  function getFilenameValidation(filenameValidation, strictness) {
@@ -5726,10 +5849,11 @@
5726
5849
  return UNDEFINED_VALUE;
5727
5850
  }
5728
5851
 
5729
- function checkLocalDirectory(zipEntry, localDirectory, rawLocalFilename) {
5852
+ function validateLocalDirectory(zipEntry, localDirectory, rawLocalFilename, checkLocalFilename) {
5730
5853
  const { rawFilename } = zipEntry;
5731
- if (rawLocalFilename.length != rawFilename.length ||
5732
- rawLocalFilename.some((byteValue, indexByte) => byteValue != rawFilename[indexByte])) {
5854
+ if (checkLocalFilename &&
5855
+ (rawLocalFilename.length != rawFilename.length ||
5856
+ rawLocalFilename.some((byteValue, indexByte) => byteValue != rawFilename[indexByte]))) {
5733
5857
  throwAmbiguousArchive("mismatched local file header (filename)");
5734
5858
  }
5735
5859
  if ((localDirectory.rawBitFlag & BITFLAG_AMBIGUITY_MASK) != (zipEntry.rawBitFlag & BITFLAG_AMBIGUITY_MASK)) {
@@ -5847,11 +5971,13 @@
5847
5971
 
5848
5972
  const ERR_DUPLICATED_NAME = "File already exists";
5849
5973
  const ERR_INVALID_COMMENT = "Zip file comment exceeds 64KB";
5974
+ const ERR_INVALID_COMMENT_TYPE = "Invalid zip file comment (must be a Uint8Array)";
5850
5975
  const ERR_INVALID_ENTRY_COMMENT = "File entry comment exceeds 64KB";
5851
5976
  const ERR_INVALID_ENTRY_NAME = "File entry name exceeds 64KB";
5852
5977
  const ERR_INVALID_VERSION = "Version exceeds 65535";
5853
5978
  const ERR_INVALID_ENCRYPTION_STRENGTH = "The strength must equal 1, 2, or 3";
5854
5979
  const ERR_UNSUPPORTED_ENCRYPTION_USDZ = "Encryption is not supported in USDZ files";
5980
+ const ERR_UNSUPPORTED_ENCRYPTION_PASS_THROUGH = "Encryption is not supported when the 'passThrough' option is set";
5855
5981
  const ERR_INVALID_EXTRAFIELD_TYPE = "Extra field type exceeds 65535";
5856
5982
  const ERR_INVALID_EXTRAFIELD_DATA = "Extra field data exceeds 64KB";
5857
5983
  const ERR_UNSUPPORTED_COMPRESSION = "Compression method not supported";
@@ -5861,6 +5987,7 @@
5861
5987
  const MAX_NTFS_TIME = BigInt("0x7fffffffffffffff");
5862
5988
  const ERR_UNSUPPORTED_FORMAT = "Zip64 is not supported (set the 'zip64' option to 'true')";
5863
5989
  const ERR_UNDEFINED_UNCOMPRESSED_SIZE = "Undefined uncompressed size";
5990
+ const ERR_UNDETERMINED_SIZE = "Undetermined size";
5864
5991
  const ERR_UNDEFINED_READER = "Undefined reader";
5865
5992
  const ERR_ZIP_NOT_EMPTY = "Zip file not empty";
5866
5993
  const ERR_INVALID_UID = "Invalid uid (must be integer 0..2^32-1)";
@@ -5913,6 +6040,10 @@
5913
6040
  }
5914
6041
  reader = new GenericReader(reader);
5915
6042
  await initStream(reader);
6043
+ if (reader.size === UNDEFINED_VALUE || !reader.readUint8Array) {
6044
+ reader = new BlobReader(await streamToBlob(reader.readable));
6045
+ await initStream(reader);
6046
+ }
5916
6047
  const { ZipReader } = await Promise.resolve().then(function () { return zipReader; });
5917
6048
  const zipReader$1 = new ZipReader(reader.readable);
5918
6049
  const entries = await zipReader$1.getEntries();
@@ -6061,6 +6192,9 @@
6061
6192
  const zipWriter = this;
6062
6193
  const { pendingAddFileCalls, writer } = this;
6063
6194
  const { writable } = writer;
6195
+ if (!(comment instanceof Uint8Array)) {
6196
+ throw new Error(ERR_INVALID_COMMENT_TYPE);
6197
+ }
6064
6198
  if (getLength(comment) > MAX_16_BITS) {
6065
6199
  throw new Error(ERR_INVALID_COMMENT);
6066
6200
  }
@@ -6068,7 +6202,7 @@
6068
6202
  await Promise.allSettled(Array.from(pendingAddFileCalls));
6069
6203
  }
6070
6204
  await closeFile(zipWriter, comment, options);
6071
- const preventClose = getOptionValue(zipWriter, options, OPTION_PREVENT_CLOSE);
6205
+ const preventClose = !ownsWritable(writer) && getOptionValue(zipWriter, options, OPTION_PREVENT_CLOSE);
6072
6206
  if (!preventClose) {
6073
6207
  await writable.getWriter().close();
6074
6208
  }
@@ -6157,8 +6291,6 @@
6157
6291
  const diskOffset = getDiskOffset(zipWriter.writer);
6158
6292
  const diskNumber = getDiskNumber(zipWriter.writer);
6159
6293
  options = Object.assign({}, options, attributesInfo.resolvedOptions, metadataInfo.resolvedOptions, sizesInfo.resolvedOptions, {
6160
- internalFileAttribute: metadataInfo.resolvedOptions.internalFileAttributes,
6161
- externalFileAttribute: attributesInfo.resolvedOptions.externalFileAttributes,
6162
6294
  signature: options[PROPERTY_NAME_SIGNATURE],
6163
6295
  crc32: options.crc32 === UNDEFINED_VALUE ? options[PROPERTY_NAME_SIGNATURE] : options.crc32,
6164
6296
  offset: zipWriter.offset - diskOffset,
@@ -6172,14 +6304,20 @@
6172
6304
  zipWriter.files.delete(name);
6173
6305
  throw error;
6174
6306
  }
6175
- Object.assign(fileEntry, { name, comment, extraField });
6307
+ Object.assign(fileEntry, {
6308
+ name,
6309
+ comment,
6310
+ extraField,
6311
+ [PROPERTY_NAME_DEPRECATED_INTERNAL_FILE_ATTRIBUTES]: fileEntry.internalFileAttributes,
6312
+ [PROPERTY_NAME_DEPRECATED_EXTERNAL_FILE_ATTRIBUTES]: fileEntry.externalFileAttributes
6313
+ });
6176
6314
  return new Entry(fileEntry);
6177
6315
  }
6178
6316
 
6179
6317
  function resolveAttributes(zipWriter, name, options) {
6180
6318
  name = name.trim();
6181
6319
  let msDosCompatible = getOptionValue(zipWriter, options, PROPERTY_NAME_MS_DOS_COMPATIBLE);
6182
- let versionMadeBy = getOptionValue(zipWriter, options, PROPERTY_NAME_VERSION_MADE_BY, msDosCompatible ? 20 : 768);
6320
+ let versionMadeBy = getOptionValue(zipWriter, options, PROPERTY_NAME_VERSION_MADE_BY, msDosCompatible ? VERSION_MADE_BY_MSDOS : VERSION_MADE_BY_UNIX);
6183
6321
  const executable = getOptionValue(zipWriter, options, PROPERTY_NAME_EXECUTABLE);
6184
6322
  const uid = getNumberOptionValue(zipWriter, options, PROPERTY_NAME_UID);
6185
6323
  const gid = getNumberOptionValue(zipWriter, options, PROPERTY_NAME_GID);
@@ -6213,7 +6351,7 @@
6213
6351
  const hasMsDosProvided = msdosAttributesRaw !== UNDEFINED_VALUE || msdosAttributes !== UNDEFINED_VALUE;
6214
6352
  if (hasUnixMetadata) {
6215
6353
  msDosCompatible = false;
6216
- versionMadeBy = (versionMadeBy & MAX_16_BITS) | (3 << 8);
6354
+ versionMadeBy = (versionMadeBy & MAX_8_BITS) | VERSION_MADE_BY_UNIX;
6217
6355
  } else if (hasMsDosProvided) {
6218
6356
  msDosCompatible = true;
6219
6357
  versionMadeBy = (versionMadeBy & MAX_8_BITS);
@@ -6227,7 +6365,7 @@
6227
6365
  if (versionMadeBy > MAX_16_BITS) {
6228
6366
  throw new Error(ERR_INVALID_VERSION);
6229
6367
  }
6230
- let externalFileAttributes = getOptionValue(zipWriter, options, PROPERTY_NAME_EXTERNAL_FILE_ATTRIBUTES);
6368
+ let externalFileAttributes = getAliasedOptionValue(zipWriter, options, PROPERTY_NAME_EXTERNAL_FILE_ATTRIBUTES, PROPERTY_NAME_DEPRECATED_EXTERNAL_FILE_ATTRIBUTES);
6231
6369
  const externalFileAttributesProvided = externalFileAttributes !== UNDEFINED_VALUE;
6232
6370
  if (!externalFileAttributesProvided) {
6233
6371
  externalFileAttributes = 0;
@@ -6253,11 +6391,10 @@
6253
6391
  externalFileAttributes = FILE_ATTR_UNIX_DEFAULT_MASK << 16;
6254
6392
  }
6255
6393
  }
6256
- let unixExternalUpper;
6257
6394
  if (!msDosCompatible) {
6258
6395
  const unixModeProvided = unixMode !== UNDEFINED_VALUE || Boolean(setuid || setgid || sticky);
6259
- unixExternalUpper = (externalFileAttributes >> 16) & MAX_16_BITS;
6260
- unixMode = unixMode === UNDEFINED_VALUE ? unixExternalUpper : (unixMode & MAX_16_BITS);
6396
+ const defaultUnixMode = (externalFileAttributes >> 16) & MAX_16_BITS;
6397
+ unixMode = unixMode === UNDEFINED_VALUE ? defaultUnixMode : (unixMode & MAX_16_BITS);
6261
6398
  if (setuid) {
6262
6399
  unixMode |= FILE_ATTR_UNIX_SETUID_MASK;
6263
6400
  } else {
@@ -6275,7 +6412,9 @@
6275
6412
  }
6276
6413
  if (!externalFileAttributesProvided || unixModeProvided) {
6277
6414
  if (directory) {
6278
- unixMode |= FILE_ATTR_UNIX_TYPE_DIR;
6415
+ unixMode = (unixMode & ~FILE_ATTR_UNIX_TYPE_MASK) | FILE_ATTR_UNIX_TYPE_DIR;
6416
+ } else if (!(unixMode & FILE_ATTR_UNIX_TYPE_MASK)) {
6417
+ unixMode |= FILE_ATTR_UNIX_TYPE_FILE;
6279
6418
  }
6280
6419
  externalFileAttributes = ((unixMode & MAX_16_BITS) << 16) | (externalFileAttributes & MAX_16_BITS);
6281
6420
  }
@@ -6284,17 +6423,20 @@
6284
6423
  if (hasMsDosProvided) {
6285
6424
  externalFileAttributes = (externalFileAttributes & MAX_32_BITS) | (msdosAttributesRaw & MAX_8_BITS);
6286
6425
  }
6426
+ const unixExternalUpper = (externalFileAttributes >> 16) & MAX_16_BITS;
6427
+ const symlink = unixMode !== UNDEFINED_VALUE && ((unixMode & FILE_ATTR_UNIX_TYPE_MASK) == FILE_ATTR_UNIX_TYPE_SYMLINK);
6287
6428
  return {
6288
6429
  name,
6289
6430
  resolvedOptions: {
6290
6431
  versionMadeBy,
6291
- msDosCompatible,
6432
+ msDosCompatible: Boolean(msDosCompatible),
6292
6433
  externalFileAttributes,
6293
6434
  unixExternalUpper,
6294
6435
  uid,
6295
6436
  gid,
6296
6437
  unixMode,
6297
6438
  unixExtraFieldType,
6439
+ symlink,
6298
6440
  setuid,
6299
6441
  setgid,
6300
6442
  sticky,
@@ -6328,15 +6470,12 @@
6328
6470
  const lastModDate = getOptionValue(zipWriter, options, PROPERTY_NAME_LAST_MODIFICATION_DATE, new Date());
6329
6471
  const lastAccessDate = getOptionValue(zipWriter, options, PROPERTY_NAME_LAST_ACCESS_DATE);
6330
6472
  const creationDate = getOptionValue(zipWriter, options, PROPERTY_NAME_CREATION_DATE);
6331
- const internalFileAttributes = getOptionValue(zipWriter, options, PROPERTY_NAME_INTERNAL_FILE_ATTRIBUTES, 0);
6473
+ const internalFileAttributes = getAliasedOptionValue(zipWriter, options, PROPERTY_NAME_INTERNAL_FILE_ATTRIBUTES, PROPERTY_NAME_DEPRECATED_INTERNAL_FILE_ATTRIBUTES, 0);
6332
6474
  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
- }
6475
+ const password = getOptionValue(zipWriter, options, OPTION_PASSWORD);
6476
+ const rawPassword = getOptionValue(zipWriter, options, OPTION_RAW_PASSWORD);
6477
+ if ((password && typeof password != STRING_TYPE) || (rawPassword && !(rawPassword instanceof Uint8Array))) {
6478
+ throw new Error(ERR_INVALID_PASSWORD_TYPE);
6340
6479
  }
6341
6480
  const encryptionStrength = getNumberOptionValue(zipWriter, options, OPTION_ENCRYPTION_STRENGTH, 3);
6342
6481
  const zipCrypto = getOptionValue(zipWriter, options, PROPERTY_NAME_ZIPCRYPTO);
@@ -6449,14 +6588,24 @@
6449
6588
  }
6450
6589
 
6451
6590
  async function resolveSizes(zipWriter, reader, { resolvedOptions: metadata }, options) {
6591
+ if (metadata.passThrough && !reader && !getOptionValue(zipWriter, options, PROPERTY_NAME_DIRECTORY)) {
6592
+ throw new Error(ERR_UNDEFINED_READER);
6593
+ }
6594
+ let contentSize;
6595
+ if (reader) {
6596
+ reader = new GenericReader(reader);
6597
+ await initStream(reader);
6598
+ ({ size: contentSize } = reader);
6599
+ }
6600
+ return Object.assign({ reader }, resolveEntrySizes(zipWriter, Boolean(reader), contentSize, metadata, options));
6601
+ }
6602
+
6603
+ function resolveEntrySizes(zipWriter, hasContent, contentSize, metadata, options) {
6452
6604
  const { passThrough, zipCrypto, password, rawPassword, encryptionStrength } = metadata;
6453
6605
  let { dataDescriptor, zip64, level, compressionMethod } = metadata;
6454
6606
  let maximumCompressedSize = 0;
6455
6607
  let uncompressedSize = 0;
6456
- if (passThrough) {
6457
- if (!reader) {
6458
- throw new Error(ERR_UNDEFINED_READER);
6459
- }
6608
+ if (passThrough && hasContent) {
6460
6609
  uncompressedSize = options[PROPERTY_NAME_UNCOMPRESSED_SIZE];
6461
6610
  if (uncompressedSize === UNDEFINED_VALUE) {
6462
6611
  throw new Error(ERR_UNDEFINED_UNCOMPRESSED_SIZE);
@@ -6464,29 +6613,30 @@
6464
6613
  }
6465
6614
  const zip64Enabled = zip64 === true;
6466
6615
  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) {
6616
+ if (hasContent && passThrough && !encrypted && getLength(password, rawPassword)) {
6617
+ throw new Error(ERR_UNSUPPORTED_ENCRYPTION_PASS_THROUGH);
6618
+ }
6619
+ const encryptedEntry = hasContent && (Boolean((password && getLength(password)) || (rawPassword && getLength(rawPassword))) || (passThrough && encrypted));
6620
+ if (!hasContent) {
6469
6621
  level = 0;
6470
6622
  compressionMethod = COMPRESSION_METHOD_STORE;
6471
6623
  }
6472
6624
  const encryptionOverhead = encryptedEntry ? (zipCrypto ? 12 : 16 + encryptionStrength * 4) : 0;
6473
- if (reader) {
6474
- reader = new GenericReader(reader);
6475
- await initStream(reader);
6625
+ if (hasContent) {
6476
6626
  if (!passThrough) {
6477
- if (reader.size === UNDEFINED_VALUE) {
6627
+ if (contentSize === UNDEFINED_VALUE) {
6478
6628
  dataDescriptor = true;
6479
6629
  if (zip64 || zip64 === UNDEFINED_VALUE) {
6480
6630
  zip64 = true;
6481
6631
  uncompressedSize = maximumCompressedSize = MAX_32_BITS + 1;
6482
6632
  }
6483
6633
  } else {
6484
- options.uncompressedSize = uncompressedSize = reader.size;
6485
- maximumCompressedSize = getMaximumCompressedSize(uncompressedSize) + encryptionOverhead;
6634
+ options.uncompressedSize = uncompressedSize = contentSize;
6635
+ maximumCompressedSize = (isCompressed(compressionMethod, level) ? getMaximumCompressedSize(uncompressedSize) : uncompressedSize) + encryptionOverhead;
6486
6636
  }
6487
6637
  } else {
6488
6638
  options.uncompressedSize = uncompressedSize;
6489
- maximumCompressedSize = getMaximumCompressedSize(uncompressedSize) + encryptionOverhead;
6639
+ maximumCompressedSize = contentSize === UNDEFINED_VALUE ? getMaximumCompressedSize(uncompressedSize) + encryptionOverhead : contentSize;
6490
6640
  }
6491
6641
  }
6492
6642
  const zip64UncompressedSize = zip64Enabled || uncompressedSize >= MAX_32_BITS;
@@ -6500,7 +6650,7 @@
6500
6650
  }
6501
6651
  zip64 = zip64 || false;
6502
6652
  return {
6503
- reader,
6653
+ maximumCompressedSize,
6504
6654
  resolvedOptions: {
6505
6655
  dataDescriptor,
6506
6656
  zip64,
@@ -6514,6 +6664,81 @@
6514
6664
  };
6515
6665
  }
6516
6666
 
6667
+ async function getEntriesSize(writerOptions, entries, writeOrderGuaranteed, comment) {
6668
+ const zipWriter = { options: writerOptions, config: getConfiguration() };
6669
+ if (writerOptions[OPTION_SIGN_CENTRAL_DIRECTORY]) {
6670
+ throw new Error(ERR_UNDETERMINED_SIZE);
6671
+ }
6672
+ if (comment !== UNDEFINED_VALUE && !(comment instanceof Uint8Array)) {
6673
+ throw new Error(ERR_INVALID_COMMENT_TYPE);
6674
+ }
6675
+ const commentLength = getLength(comment);
6676
+ if (commentLength > MAX_16_BITS) {
6677
+ throw new Error(ERR_INVALID_COMMENT);
6678
+ }
6679
+ const usdz = writerOptions[OPTION_USDZ];
6680
+ const files = new Map();
6681
+ let layoutDependsOnWriteOrder = Boolean(usdz);
6682
+ let offset = 0;
6683
+ for (const entry of entries) {
6684
+ let { name } = entry;
6685
+ const { size } = entry;
6686
+ const options = Object.assign({}, entry.options);
6687
+ name = name.trim();
6688
+ if (getOptionValue(zipWriter, options, PROPERTY_NAME_DIRECTORY) && !name.endsWith(DIRECTORY_SIGNATURE)) {
6689
+ name += DIRECTORY_SIGNATURE;
6690
+ }
6691
+ const attributesInfo = resolveAttributes(zipWriter, name, options);
6692
+ ({ name } = attributesInfo);
6693
+ const { resolvedOptions: metadata } = resolveMetadata(zipWriter, name, options);
6694
+ if (metadata.level != 0 && metadata.compressionMethod === UNDEFINED_VALUE &&
6695
+ !metadata.passThrough && !(await supportsDeflate(zipWriter.config))) {
6696
+ metadata.level = 0;
6697
+ }
6698
+ const hasContent = !getOptionValue(zipWriter, options, PROPERTY_NAME_DIRECTORY);
6699
+ if (hasContent && size === UNDEFINED_VALUE) {
6700
+ throw new Error(ERR_UNDETERMINED_SIZE);
6701
+ }
6702
+ const { maximumCompressedSize, resolvedOptions: sizes } = resolveEntrySizes(zipWriter, hasContent, size, metadata, options);
6703
+ if (hasContent && !metadata.passThrough && isCompressed(sizes.compressionMethod, sizes.level)) {
6704
+ throw new Error(ERR_UNDETERMINED_SIZE);
6705
+ }
6706
+ const entryOptions = Object.assign({}, options, attributesInfo.resolvedOptions, metadata, sizes);
6707
+ const headerInfo = getHeaderInfo(entryOptions);
6708
+ const dataDescriptorInfo = getDataDescriptorInfo(entryOptions);
6709
+ const entryInfo = {
6710
+ headerInfo,
6711
+ metadataSize: getLength(headerInfo.localHeaderArray, dataDescriptorInfo.dataDescriptorArray)
6712
+ };
6713
+ if (usdz) {
6714
+ appendExtraFieldUSDZ(entryInfo, offset);
6715
+ }
6716
+ const compressedSize = hasContent ? maximumCompressedSize : 0;
6717
+ if (offset >= MAX_32_BITS) {
6718
+ layoutDependsOnWriteOrder = true;
6719
+ }
6720
+ files.set(name, Object.assign({}, entryOptions, headerInfo, {
6721
+ offset,
6722
+ diskNumberStart: 0,
6723
+ compressedSize
6724
+ }));
6725
+ offset += entryInfo.metadataSize + compressedSize;
6726
+ }
6727
+ if (layoutDependsOnWriteOrder && !writeOrderGuaranteed) {
6728
+ throw new Error(ERR_UNDETERMINED_SIZE);
6729
+ }
6730
+ const directoryDataLength = createDirectoryRecords(files);
6731
+ let zip64 = getOptionValue(zipWriter, writerOptions, PROPERTY_NAME_ZIP64);
6732
+ if (offset >= MAX_32_BITS || directoryDataLength >= MAX_32_BITS || files.size >= MAX_16_BITS) {
6733
+ if (zip64 === false) {
6734
+ throw new Error(ERR_UNSUPPORTED_FORMAT);
6735
+ } else {
6736
+ zip64 = true;
6737
+ }
6738
+ }
6739
+ return offset + directoryDataLength + commentLength + (zip64 ? ZIP64_END_OF_CENTRAL_DIR_TOTAL_LENGTH : END_OF_CENTRAL_DIR_LENGTH);
6740
+ }
6741
+
6517
6742
  async function getFileEntry(zipWriter, name, reader, entryInfo, options) {
6518
6743
  const {
6519
6744
  files,
@@ -6728,6 +6953,7 @@
6728
6953
  uid,
6729
6954
  gid,
6730
6955
  unixMode,
6956
+ symlink,
6731
6957
  setuid,
6732
6958
  setgid,
6733
6959
  sticky,
@@ -6764,6 +6990,7 @@
6764
6990
  uid,
6765
6991
  gid,
6766
6992
  unixMode,
6993
+ symlink: Boolean(symlink),
6767
6994
  setuid,
6768
6995
  setgid,
6769
6996
  sticky,
@@ -6844,8 +7071,8 @@
6844
7071
  rawLastModDate,
6845
7072
  creationDate,
6846
7073
  lastAccessDate,
6847
- encrypted,
6848
- zipCrypto,
7074
+ encrypted: Boolean(encrypted),
7075
+ zipCrypto: Boolean(zipCrypto),
6849
7076
  size: metadataSize + compressedSize,
6850
7077
  compressionMethod,
6851
7078
  version,
@@ -6885,9 +7112,7 @@
6885
7112
  crc32
6886
7113
  } = options;
6887
7114
  let { version, compressionMethod } = options;
6888
- const compressed = !directory && (compressionMethod === UNDEFINED_VALUE
6889
- ? (level === UNDEFINED_VALUE || level > 0)
6890
- : compressionMethod !== COMPRESSION_METHOD_STORE);
7115
+ const compressed = !directory && isCompressed(compressionMethod, level);
6891
7116
  let rawLocalExtraFieldZip64;
6892
7117
  const uncompressedFile = passThrough || !compressed;
6893
7118
  const zip64ExtraFieldComplete = zip64 && (options.bufferedWrite || !dataDescriptor || ((!zip64UncompressedSize && !zip64CompressedSize) || uncompressedFile));
@@ -7574,6 +7799,16 @@
7574
7799
  return result === UNDEFINED_VALUE ? defaultValue : result;
7575
7800
  }
7576
7801
 
7802
+ function getAliasedOptionValue(zipWriter, options, name, deprecatedName, defaultValue) {
7803
+ const value = getAliasedValue(options, name, deprecatedName);
7804
+ const result = value === UNDEFINED_VALUE ? getAliasedValue(zipWriter.options, name, deprecatedName) : value;
7805
+ return result === UNDEFINED_VALUE ? defaultValue : result;
7806
+ }
7807
+
7808
+ function getAliasedValue(options, name, deprecatedName) {
7809
+ return options[name] === UNDEFINED_VALUE ? options[deprecatedName] : options[name];
7810
+ }
7811
+
7577
7812
  function getNumberOptionValue(zipWriter, options, name, defaultValue) {
7578
7813
  return toNumber(getOptionValue(zipWriter, options, name, defaultValue));
7579
7814
  }
@@ -7586,6 +7821,12 @@
7586
7821
  return uncompressedSize + (5 * (Math.floor(uncompressedSize / 16383) + 1));
7587
7822
  }
7588
7823
 
7824
+ function isCompressed(compressionMethod, level) {
7825
+ return compressionMethod === UNDEFINED_VALUE
7826
+ ? (level === UNDEFINED_VALUE || level > 0)
7827
+ : compressionMethod !== COMPRESSION_METHOD_STORE;
7828
+ }
7829
+
7589
7830
  function setUint8(view, offset, value) {
7590
7831
  view.setUint8(offset, value);
7591
7832
  }
@@ -8234,6 +8475,7 @@
8234
8475
 
8235
8476
  const ERR_ENTRY_EXISTS = "Entry filename already exists";
8236
8477
  const ERR_READABLE_CONSUMED = "Readable stream already consumed";
8478
+ const ERR_INVALID_PASS_THROUGH = "Invalid passThrough option (use readerOptions.passThrough or set uncompressedSize for each entry)";
8237
8479
  const ERR_ABORT_EXPORT = "zipjs-abort-export";
8238
8480
  const ERR_ABORTED = "The operation was aborted";
8239
8481
  const ABORT_ERROR_NAME = "AbortError";
@@ -8271,6 +8513,7 @@
8271
8513
  parent,
8272
8514
  children: [],
8273
8515
  uncompressedSize: params.uncompressedSize || 0,
8516
+ undeterminedSize: params.undeterminedSize || params.uncompressedSize === UNDEFINED_VALUE,
8274
8517
  passThrough: params.passThrough
8275
8518
  });
8276
8519
  if (parent || !fs.root) {
@@ -8338,16 +8581,17 @@
8338
8581
 
8339
8582
  async getData(writer, options = {}) {
8340
8583
  const zipEntry = this;
8341
- if (!writer || (writer.constructor == zipEntry.Writer && zipEntry.data)) {
8584
+ if (!writer || (writer.constructor == zipEntry.Writer && zipEntry.data && keepsContentType(writer, zipEntry.data))) {
8342
8585
  return zipEntry.data;
8343
8586
  } else {
8344
8587
  const reader = zipEntry.reader = createReader(zipEntry.Reader, zipEntry.data, options);
8345
- const uncompressedSize = zipEntry.data ? zipEntry.data.uncompressedSize : reader.size;
8346
- await Promise.all([initStream(reader), initStream(writer, uncompressedSize)]);
8347
- const { readable } = reader;
8588
+ const dataSize = zipEntry.uncompressedSize || reader.size;
8589
+ await Promise.all([initStream(reader), initStream(writer, dataSize)]);
8348
8590
  const { signal } = options;
8591
+ const readable = createProgressReadable(zipEntry, reader, options, signal);
8592
+ const preventClose = !ownsWritable(writer) && Boolean(options.preventClose);
8349
8593
  zipEntry.uncompressedSize = reader.size;
8350
- await toCompatibleReadable(readable).pipeTo(toCompatibleWritable(writer.writable), { signal });
8594
+ await toCompatibleReadable(readable).pipeTo(toCompatibleWritable(writer.writable), { signal, preventClose, preventAbort: preventClose });
8351
8595
  return writer.getData ? writer.getData() : writer.writable;
8352
8596
  }
8353
8597
  }
@@ -8478,7 +8722,7 @@
8478
8722
  Reader: TextReader,
8479
8723
  Writer: TextWriter,
8480
8724
  options,
8481
- uncompressedSize: text.length
8725
+ uncompressedSize: getTextSize(text)
8482
8726
  });
8483
8727
  }
8484
8728
 
@@ -8607,10 +8851,16 @@
8607
8851
  }
8608
8852
 
8609
8853
  async importZip(reader, options = {}) {
8610
- await initStream(reader);
8611
- const zipReader = new ZipReader(reader, options);
8854
+ let zipReader;
8855
+ if (reader && typeof reader.getEntries == FUNCTION_TYPE) {
8856
+ zipReader = reader;
8857
+ options = Object.assign({}, zipReader.options, options);
8858
+ } else {
8859
+ await initStream(reader);
8860
+ zipReader = new ZipReader(reader, options);
8861
+ }
8612
8862
  const importedEntries = [];
8613
- const entries = await zipReader.getEntries();
8863
+ const entries = await zipReader.getEntries(options);
8614
8864
  for (const entry of entries) {
8615
8865
  let parent = this;
8616
8866
  try {
@@ -8632,7 +8882,7 @@
8632
8882
  importedEntries.push(addChild(parent, name, {
8633
8883
  data: entry,
8634
8884
  Reader: getZipBlobReader(Object.assign({}, options)),
8635
- uncompressedSize: entry.uncompressedSize,
8885
+ uncompressedSize: options.passThrough ? entry.compressedSize : entry.uncompressedSize,
8636
8886
  passThrough: options.passThrough
8637
8887
  }));
8638
8888
  } else {
@@ -8674,11 +8924,25 @@
8674
8924
  }
8675
8925
  const [readers] = await Promise.all([initReaders(zipEntry, options.readerOptions), initStream(writer)]);
8676
8926
  const zipWriter = new ZipWriter(writer, options);
8677
- await exportZip(zipWriter, zipEntry, getTotalSize([zipEntry], "uncompressedSize"), options, readers);
8678
- await zipWriter.close();
8927
+ await exportZip(zipWriter, zipEntry, getTotalSize([zipEntry], getUncompressedSize), options, readers);
8928
+ await zipWriter.close(options.globalComment);
8679
8929
  return writer.getData ? writer.getData() : writer.writable;
8680
8930
  }
8681
8931
 
8932
+ getExportedSize(options = {}) {
8933
+ const zipEntry = this;
8934
+ options = Object.assign({}, options);
8935
+ if (options.bufferedWrite === UNDEFINED_VALUE) {
8936
+ options.bufferedWrite = true;
8937
+ }
8938
+ const writeOrderGuaranteed = !options.bufferedWrite ||
8939
+ (options.keepOrder !== false && zipEntry.children.every(child => !child.children.length));
8940
+ return getEntriesSize(options, Array.from(zipEntry.getChildren({ recursive: true }), child => {
8941
+ const { name, entryOptions } = getChildEntryOptions(child, zipEntry, options);
8942
+ return { name, size: child.directory ? 0 : getDeterminedSize(child, isPassThrough(child, options)), options: entryOptions };
8943
+ }), writeOrderGuaranteed, options.globalComment);
8944
+ }
8945
+
8682
8946
  getChildByName(name) {
8683
8947
  const children = this.children;
8684
8948
  for (let childIndex = 0; childIndex < children.length; childIndex++) {
@@ -8886,6 +9150,10 @@
8886
9150
  return this.root.exportZip(writer, options);
8887
9151
  }
8888
9152
 
9153
+ getExportedSize(options) {
9154
+ return this.root.getExportedSize(options);
9155
+ }
9156
+
8889
9157
  isPasswordProtected() {
8890
9158
  return this.root.isPasswordProtected();
8891
9159
  }
@@ -8897,12 +9165,12 @@
8897
9165
 
8898
9166
  const fs = { FS, ZipDirectoryEntry, ZipFileEntry };
8899
9167
 
8900
- function getTotalSize(entries, propertyName) {
9168
+ function getTotalSize(entries, getEntrySize) {
8901
9169
  let size = 0;
8902
9170
  const pendingEntries = Array.from(entries);
8903
9171
  while (pendingEntries.length) {
8904
9172
  const entry = pendingEntries.pop();
8905
- size += entry[propertyName] || 0;
9173
+ size += getEntrySize(entry) || 0;
8906
9174
  for (const child of entry.children) {
8907
9175
  pendingEntries.push(child);
8908
9176
  }
@@ -8910,6 +9178,15 @@
8910
9178
  return size;
8911
9179
  }
8912
9180
 
9181
+ function getUncompressedSize(entry) {
9182
+ return entry.uncompressedSize;
9183
+ }
9184
+
9185
+ function getExtractedSize(entry, passThrough) {
9186
+ const { data } = entry;
9187
+ return passThrough && data instanceof Entry ? data.compressedSize : entry.uncompressedSize;
9188
+ }
9189
+
8913
9190
  function getReadableReader(readable) {
8914
9191
  let consumed;
8915
9192
  return function () {
@@ -8932,10 +9209,17 @@
8932
9209
 
8933
9210
  async init() {
8934
9211
  const zipBlobReader = this;
8935
- zipBlobReader.size = zipBlobReader.entry.uncompressedSize;
8936
- const data = await zipBlobReader.entry.getData(new BlobWriter(), Object.assign({}, options, zipBlobReader.options));
9212
+ const readerOptions = Object.assign({}, options, zipBlobReader.options);
9213
+ const { checkOverlappingEntry, checkOverlappingEntryOnly } = readerOptions;
9214
+ const data = await zipBlobReader.entry.getData(new BlobWriter(), Object.assign(readerOptions, {
9215
+ checkPasswordOnly: false,
9216
+ checkOverlappingEntry: checkOverlappingEntryOnly || checkOverlappingEntry,
9217
+ checkOverlappingEntryOnly: false,
9218
+ preventClose: false
9219
+ }));
8937
9220
  zipBlobReader.data = data;
8938
9221
  zipBlobReader.blobReader = new BlobReader(data);
9222
+ zipBlobReader.size = data.size;
8939
9223
  super.init();
8940
9224
  }
8941
9225
 
@@ -8949,6 +9233,30 @@
8949
9233
  return Reader.prototype ? new Reader(data, options) : Reader(data, options);
8950
9234
  }
8951
9235
 
9236
+ function keepsContentType(writer, data) {
9237
+ const { contentType } = writer;
9238
+ if (contentType === UNDEFINED_VALUE) {
9239
+ return true;
9240
+ } else if (writer.constructor == BlobWriter) {
9241
+ return data.type == contentType;
9242
+ } else if (writer.constructor == Data64URIWriter) {
9243
+ return data.startsWith(writer.data);
9244
+ } else {
9245
+ return true;
9246
+ }
9247
+ }
9248
+
9249
+ function createProgressReadable(zipEntry, reader, options, signal) {
9250
+ const { onstart, onprogress, onend } = options;
9251
+ const { readable } = reader;
9252
+ const coreReaderReportsProgress = zipEntry.data instanceof Entry;
9253
+ if (coreReaderReportsProgress || (!onstart && !onprogress && !onend)) {
9254
+ return readable;
9255
+ } else {
9256
+ return toCompatibleReadable(readable).pipeThrough(new ProgressWatcherStream({ onstart, onprogress, onend, size: reader.size }), { signal });
9257
+ }
9258
+ }
9259
+
8952
9260
  async function initReaders(entry, options) {
8953
9261
  const fileEntries = [];
8954
9262
  const pendingEntries = [entry];
@@ -8981,6 +9289,7 @@
8981
9289
  }
8982
9290
  if (reader.size !== UNDEFINED_VALUE) {
8983
9291
  child.uncompressedSize = reader.size;
9292
+ child.undeterminedSize = false;
8984
9293
  }
8985
9294
  }));
8986
9295
  return readers;
@@ -9030,6 +9339,90 @@
9030
9339
  return error;
9031
9340
  }
9032
9341
 
9342
+ function getChildEntryOptions(child, selectedEntry, options) {
9343
+ const name = options.relativePath ? child.getRelativeName(selectedEntry) : child.getFullname();
9344
+ const childOptions = child.options || {};
9345
+ let zipEntryMetadata = {};
9346
+ let passThroughOptions = {};
9347
+ if (child.data instanceof Entry) {
9348
+ const {
9349
+ externalFileAttributes,
9350
+ versionMadeBy,
9351
+ comment,
9352
+ lastModDate,
9353
+ creationDate,
9354
+ lastAccessDate,
9355
+ uncompressedSize,
9356
+ encrypted,
9357
+ zipCrypto,
9358
+ crc32,
9359
+ compressionMethod,
9360
+ extraFieldAES,
9361
+ internalFileAttributes,
9362
+ extraField,
9363
+ uid,
9364
+ gid
9365
+ } = child.data;
9366
+ zipEntryMetadata = {
9367
+ externalFileAttributes,
9368
+ versionMadeBy,
9369
+ comment,
9370
+ lastModDate,
9371
+ creationDate,
9372
+ lastAccessDate,
9373
+ internalFileAttributes
9374
+ };
9375
+ const userExtraField = getUserExtraField(extraField);
9376
+ if (userExtraField) {
9377
+ zipEntryMetadata.extraField = userExtraField;
9378
+ }
9379
+ if (uid !== UNDEFINED_VALUE || gid !== UNDEFINED_VALUE) {
9380
+ Object.assign(zipEntryMetadata, {
9381
+ uid,
9382
+ gid,
9383
+ unixExtraFieldType: INFOZIP_EXTRA_FIELD_TYPE
9384
+ });
9385
+ }
9386
+ if (isPassThrough(child, options)) {
9387
+ let level, encryptionStrength;
9388
+ if (compressionMethod === 0) {
9389
+ level = 0;
9390
+ }
9391
+ if (extraFieldAES) {
9392
+ encryptionStrength = extraFieldAES.strength;
9393
+ }
9394
+ passThroughOptions = {
9395
+ passThrough: true,
9396
+ encrypted,
9397
+ zipCrypto,
9398
+ crc32,
9399
+ uncompressedSize,
9400
+ level,
9401
+ encryptionStrength,
9402
+ compressionMethod
9403
+ };
9404
+ }
9405
+ }
9406
+ const entryOptions = Object.assign({}, zipEntryMetadata, options, passThroughOptions, childOptions, { directory: child.directory });
9407
+ if (!child.directory && entryOptions.passThrough && entryOptions.uncompressedSize === UNDEFINED_VALUE) {
9408
+ throw new Error(ERR_INVALID_PASS_THROUGH);
9409
+ }
9410
+ return { name, entryOptions };
9411
+ }
9412
+
9413
+ function getDeterminedSize(child, passThrough) {
9414
+ const { reader } = child;
9415
+ if (reader && reader.size !== UNDEFINED_VALUE) {
9416
+ return reader.size;
9417
+ }
9418
+ return child.undeterminedSize ? UNDEFINED_VALUE : getExtractedSize(child, passThrough);
9419
+ }
9420
+
9421
+ function isPassThrough(child, options) {
9422
+ const { readerOptions } = options;
9423
+ return Boolean(!child.directory && (child.passThrough || (readerOptions && readerOptions.passThrough)));
9424
+ }
9425
+
9033
9426
  function getUserExtraField(extraField) {
9034
9427
  if (extraField) {
9035
9428
  const userExtraField = new Map();
@@ -9045,8 +9438,14 @@
9045
9438
  }
9046
9439
 
9047
9440
  async function exportZip(zipWriter, entry, totalSize, options, readers) {
9441
+ const { onstart, onprogress, onend, onentryprogress } = options;
9048
9442
  const selectedEntry = entry;
9049
- const entryOffsets = new Map();
9443
+ const totalEntries = getTotalSize(entry.children, () => 1);
9444
+ let writtenSize = 0;
9445
+ let writtenEntries = 0;
9446
+ if (onstart) {
9447
+ await callHandler(onstart, totalSize);
9448
+ }
9050
9449
  if (options.bufferedWrite) {
9051
9450
  await processChildren(entry);
9052
9451
  } else {
@@ -9054,6 +9453,9 @@
9054
9453
  await addChild(child);
9055
9454
  }
9056
9455
  }
9456
+ if (onend) {
9457
+ await callHandler(onend, writtenSize);
9458
+ }
9057
9459
 
9058
9460
  async function processChildren(entry) {
9059
9461
  const results = await Promise.allSettled(entry.children.map(async child => {
@@ -9067,81 +9469,23 @@
9067
9469
  }
9068
9470
 
9069
9471
  async function addChild(child) {
9070
- const name = options.relativePath ? child.getRelativeName(selectedEntry) : child.getFullname();
9071
- const childOptions = child.options || {};
9072
- let zipEntryOptions = {};
9073
- if (child.data instanceof Entry) {
9074
- const {
9075
- externalFileAttributes,
9076
- versionMadeBy,
9077
- comment,
9078
- lastModDate,
9079
- creationDate,
9080
- lastAccessDate,
9081
- uncompressedSize,
9082
- encrypted,
9083
- zipCrypto,
9084
- crc32,
9085
- compressionMethod,
9086
- extraFieldAES,
9087
- internalFileAttributes,
9088
- extraField,
9089
- uid,
9090
- gid
9091
- } = child.data;
9092
- zipEntryOptions = {
9093
- externalFileAttributes,
9094
- versionMadeBy,
9095
- comment,
9096
- lastModDate,
9097
- creationDate,
9098
- lastAccessDate,
9099
- internalFileAttributes
9100
- };
9101
- const userExtraField = getUserExtraField(extraField);
9102
- if (userExtraField) {
9103
- zipEntryOptions.extraField = userExtraField;
9104
- }
9105
- if (uid !== UNDEFINED_VALUE || gid !== UNDEFINED_VALUE) {
9106
- Object.assign(zipEntryOptions, {
9107
- uid,
9108
- gid,
9109
- unixExtraFieldType: options.unixExtraFieldType || INFOZIP_EXTRA_FIELD_TYPE
9110
- });
9111
- }
9112
- if (child.passThrough) {
9113
- let level, encryptionStrength;
9114
- if (compressionMethod === 0) {
9115
- level = 0;
9116
- }
9117
- if (extraFieldAES) {
9118
- encryptionStrength = extraFieldAES.strength;
9119
- }
9120
- zipEntryOptions = Object.assign(zipEntryOptions, {
9121
- passThrough: true,
9122
- encrypted,
9123
- zipCrypto,
9124
- crc32,
9125
- uncompressedSize,
9126
- level,
9127
- encryptionStrength,
9128
- compressionMethod
9129
- });
9130
- }
9131
- }
9132
- await zipWriter.add(name, readers.get(child), Object.assign({}, options, zipEntryOptions, childOptions, {
9133
- directory: child.directory,
9472
+ const { name, entryOptions } = getChildEntryOptions(child, selectedEntry, options);
9473
+ let entryWrittenSize = 0;
9474
+ const entryMetadata = await zipWriter.add(name, readers.get(child), Object.assign(entryOptions, {
9475
+ onstart: UNDEFINED_VALUE,
9476
+ onend: UNDEFINED_VALUE,
9134
9477
  onprogress: async indexProgress => {
9135
- if (options.onprogress) {
9136
- entryOffsets.set(name, indexProgress);
9137
- try {
9138
- await options.onprogress(Array.from(entryOffsets.values()).reduce((previousValue, currentValue) => previousValue + currentValue), totalSize);
9139
- } catch {
9140
- // ignored
9141
- }
9478
+ writtenSize += indexProgress - entryWrittenSize;
9479
+ entryWrittenSize = indexProgress;
9480
+ if (onprogress) {
9481
+ await callHandler(onprogress, writtenSize, totalSize);
9142
9482
  }
9143
9483
  }
9144
9484
  }));
9485
+ writtenEntries++;
9486
+ if (onentryprogress) {
9487
+ await callHandler(onentryprogress, writtenEntries, totalEntries, entryMetadata);
9488
+ }
9145
9489
  }
9146
9490
  }
9147
9491
 
@@ -9169,7 +9513,7 @@
9169
9513
  })
9170
9514
  );
9171
9515
  } else if (handle.kind == "directory") {
9172
- const directoryEntry = parentEntry.addDirectory(handle.name);
9516
+ const directoryEntry = parentEntry.addDirectory(handle.name, options);
9173
9517
  addedEntries.push(directoryEntry);
9174
9518
  for await (const childHandle of handle.values()) {
9175
9519
  await addFile(directoryEntry, childHandle, addedEntries, entryName);
@@ -9191,15 +9535,29 @@
9191
9535
  }
9192
9536
 
9193
9537
  async function exportFileSystemHandle(zipEntry, directoryHandle, options) {
9194
- const totalSize = getTotalSize([zipEntry], "uncompressedSize");
9195
- const writtenSizes = new Map();
9538
+ const { onstart, onprogress, onend } = options;
9196
9539
  const abortController = new AbortController();
9197
9540
  const { signal } = abortController;
9198
9541
  const releaseSignal = forwardAbort(options.signal, abortController);
9542
+ const getDataOptions = Object.assign({}, options, options.readerOptions, {
9543
+ signal,
9544
+ onstart: UNDEFINED_VALUE,
9545
+ onprogress: UNDEFINED_VALUE,
9546
+ onend: UNDEFINED_VALUE,
9547
+ preventClose: false
9548
+ });
9549
+ const totalSize = getTotalSize([zipEntry], entry => getExtractedSize(entry, getDataOptions.passThrough));
9199
9550
  const exportedEntryNames = [];
9200
9551
  let exportAborted = false;
9552
+ let writtenSize = 0;
9201
9553
  try {
9554
+ if (onstart) {
9555
+ await callHandler(onstart, totalSize);
9556
+ }
9202
9557
  await exportChildren(zipEntry, directoryHandle);
9558
+ if (onend) {
9559
+ await callHandler(onend, writtenSize);
9560
+ }
9203
9561
  } catch (error) {
9204
9562
  try {
9205
9563
  error.exportedEntryNames = exportedEntryNames;
@@ -9212,6 +9570,25 @@
9212
9570
  }
9213
9571
  return directoryHandle;
9214
9572
 
9573
+ function createProgressWritable(writable) {
9574
+ const writer = writable.getWriter();
9575
+ return new WritableStream({
9576
+ async write(chunk) {
9577
+ await writer.write(chunk);
9578
+ writtenSize += chunk.length;
9579
+ if (onprogress) {
9580
+ await callHandler(onprogress, writtenSize, totalSize);
9581
+ }
9582
+ },
9583
+ close() {
9584
+ return writer.close();
9585
+ },
9586
+ abort(reason) {
9587
+ return writer.abort(reason);
9588
+ }
9589
+ });
9590
+ }
9591
+
9215
9592
  async function exportChildren(entry, parentHandle) {
9216
9593
  if (options.concurrent) {
9217
9594
  const results = await Promise.allSettled(entry.children.map(child => exportChild(child, parentHandle)));
@@ -9243,19 +9620,7 @@
9243
9620
  const fileHandle = await parentHandle.getFileHandle(child.name, { create: true });
9244
9621
  const writable = await fileHandle.createWritable();
9245
9622
  try {
9246
- await child.getData({ writable }, Object.assign({}, options, {
9247
- signal,
9248
- onprogress: async progress => {
9249
- if (options.onprogress) {
9250
- writtenSizes.set(child.id, progress);
9251
- try {
9252
- await options.onprogress(Array.from(writtenSizes.values()).reduce((previousValue, currentValue) => previousValue + currentValue, 0), totalSize);
9253
- } catch {
9254
- // ignored
9255
- }
9256
- }
9257
- }
9258
- }));
9623
+ await child.getData({ writable: createProgressWritable(writable) }, getDataOptions);
9259
9624
  } catch (error) {
9260
9625
  throw exportAborted ? new Error(ERR_ABORT_EXPORT) : error;
9261
9626
  }
@@ -9484,6 +9849,7 @@
9484
9849
  exports.ERR_INVALID_CODEC_DEFINITION = ERR_INVALID_CODEC_DEFINITION;
9485
9850
  exports.ERR_INVALID_CODEC_MODULE = ERR_INVALID_CODEC_MODULE;
9486
9851
  exports.ERR_INVALID_COMMENT = ERR_INVALID_COMMENT;
9852
+ exports.ERR_INVALID_COMMENT_TYPE = ERR_INVALID_COMMENT_TYPE;
9487
9853
  exports.ERR_INVALID_COMPRESSED_DATA = ERR_INVALID_COMPRESSED_DATA;
9488
9854
  exports.ERR_INVALID_CRC32 = ERR_INVALID_CRC32;
9489
9855
  exports.ERR_INVALID_ENCRYPTION_STRENGTH = ERR_INVALID_ENCRYPTION_STRENGTH;
@@ -9499,6 +9865,7 @@
9499
9865
  exports.ERR_INVALID_MSDOS_DATA = ERR_INVALID_MSDOS_DATA;
9500
9866
  exports.ERR_INVALID_PASSWORD = ERR_INVALID_PASSWORD;
9501
9867
  exports.ERR_INVALID_PASSWORD_TYPE = ERR_INVALID_PASSWORD_TYPE;
9868
+ exports.ERR_INVALID_PASS_THROUGH = ERR_INVALID_PASS_THROUGH;
9502
9869
  exports.ERR_INVALID_SIGNATURE = ERR_INVALID_SIGNATURE;
9503
9870
  exports.ERR_INVALID_SIGNATURE_DATA = ERR_INVALID_SIGNATURE_DATA;
9504
9871
  exports.ERR_INVALID_STRICTNESS = ERR_INVALID_STRICTNESS;
@@ -9516,11 +9883,13 @@
9516
9883
  exports.ERR_SPLIT_ZIP_FILE = ERR_SPLIT_ZIP_FILE;
9517
9884
  exports.ERR_UNDEFINED_READER = ERR_UNDEFINED_READER;
9518
9885
  exports.ERR_UNDEFINED_UNCOMPRESSED_SIZE = ERR_UNDEFINED_UNCOMPRESSED_SIZE;
9886
+ exports.ERR_UNDETERMINED_SIZE = ERR_UNDETERMINED_SIZE;
9519
9887
  exports.ERR_UNSAFE_FILENAME = ERR_UNSAFE_FILENAME;
9520
9888
  exports.ERR_UNSUPPORTED_COMPRESSION = ERR_UNSUPPORTED_COMPRESSION$1;
9521
9889
  exports.ERR_UNSUPPORTED_CONTEXT = ERR_UNSUPPORTED_CONTEXT;
9522
9890
  exports.ERR_UNSUPPORTED_CRYPTO_API = ERR_UNSUPPORTED_CRYPTO_API;
9523
9891
  exports.ERR_UNSUPPORTED_ENCRYPTION = ERR_UNSUPPORTED_ENCRYPTION;
9892
+ exports.ERR_UNSUPPORTED_ENCRYPTION_PASS_THROUGH = ERR_UNSUPPORTED_ENCRYPTION_PASS_THROUGH;
9524
9893
  exports.ERR_UNSUPPORTED_ENCRYPTION_USDZ = ERR_UNSUPPORTED_ENCRYPTION_USDZ;
9525
9894
  exports.ERR_UNSUPPORTED_FORMAT = ERR_UNSUPPORTED_FORMAT;
9526
9895
  exports.ERR_WORKER_STARTUP_TIMEOUT = ERR_WORKER_STARTUP_TIMEOUT;