@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
package/dist/zip-fs.js CHANGED
@@ -90,6 +90,8 @@
90
90
  const FILE_ATTR_MSDOS_ARCHIVE_MASK = 0x20;
91
91
  const FILE_ATTR_UNIX_TYPE_MASK = 0o170000;
92
92
  const FILE_ATTR_UNIX_TYPE_DIR = 0o040000;
93
+ const FILE_ATTR_UNIX_TYPE_SYMLINK = 0o120000;
94
+ const FILE_ATTR_UNIX_TYPE_FILE = 0o100000;
93
95
  const FILE_ATTR_UNIX_EXECUTABLE_MASK = 0o111;
94
96
  const FILE_ATTR_UNIX_DEFAULT_MASK = 0o644;
95
97
  const FILE_ATTR_UNIX_SETUID_MASK = 0o4000;
@@ -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() {
@@ -2765,6 +2765,7 @@
2765
2765
  worker,
2766
2766
  workerAlive: false,
2767
2767
  terminated: false,
2768
+ startupError: null,
2768
2769
  interface: {
2769
2770
  run: async () => {
2770
2771
  try {
@@ -2792,6 +2793,13 @@
2792
2793
  }
2793
2794
 
2794
2795
  async function runWebWorker(workerData, config) {
2796
+ if (!workerData.worker) {
2797
+ const { startupError } = workerData;
2798
+ workerData.startupError = null;
2799
+ const error = startupError || new Error(ERR_WORKER_STARTUP_TIMEOUT);
2800
+ error.workerStartupFailed = true;
2801
+ throw error;
2802
+ }
2795
2803
  let resolveResult, rejectResult;
2796
2804
  const result = new Promise((resolve, reject) => {
2797
2805
  resolveResult = resolve;
@@ -3005,11 +3013,12 @@
3005
3013
  if (!workerAlive) {
3006
3014
  workerData.worker = null;
3007
3015
  }
3016
+ let error = event.error || new Error(event.message || ERROR_EVENT_TYPE);
3017
+ if (!workerAlive) {
3018
+ error = Object.assign(new Error(error.message || ERROR_EVENT_TYPE), { workerStartupFailed: true });
3019
+ workerData.startupError = error;
3020
+ }
3008
3021
  if (rejectResult) {
3009
- let error = event.error || new Error(event.message || ERROR_EVENT_TYPE);
3010
- if (!workerAlive) {
3011
- error = Object.assign(new Error(error.message || ERROR_EVENT_TYPE), { workerStartupFailed: true });
3012
- }
3013
3022
  rejectResult(error);
3014
3023
  if (writer) {
3015
3024
  writer.releaseLock();
@@ -3354,8 +3363,10 @@
3354
3363
  async pull(controller) {
3355
3364
  const dataSize = size === UNDEFINED_VALUE ? chunkSize : Math.min(chunkSize, size - chunkOffset);
3356
3365
  const data = await readUint8Array(reader, offset + chunkOffset, dataSize);
3357
- controller.enqueue(data);
3358
- if ((chunkOffset + chunkSize > size) || (size === UNDEFINED_VALUE && !data.length && dataSize)) {
3366
+ if (data.length) {
3367
+ controller.enqueue(data);
3368
+ }
3369
+ if ((chunkOffset + chunkSize >= size) || (size === UNDEFINED_VALUE && !data.length && dataSize)) {
3359
3370
  controller.close();
3360
3371
  } else {
3361
3372
  chunkOffset += chunkSize;
@@ -3433,6 +3444,7 @@
3433
3444
  constructor(contentType) {
3434
3445
  super();
3435
3446
  Object.assign(this, {
3447
+ contentType,
3436
3448
  data: "data:" + (contentType || "") + ";base64,",
3437
3449
  pending: []
3438
3450
  });
@@ -3534,6 +3546,7 @@
3534
3546
  return transformStream.writable;
3535
3547
  }
3536
3548
  });
3549
+ writer.contentType = contentType;
3537
3550
  writer.blob = streamToBlob(transformStream.readable, contentType);
3538
3551
  writer.blob.catch(() => { });
3539
3552
  }
@@ -3550,6 +3563,26 @@
3550
3563
  }
3551
3564
  }
3552
3565
 
3566
+ function getTextSize(text) {
3567
+ let size = 0;
3568
+ for (let indexCharacter = 0; indexCharacter < text.length; indexCharacter++) {
3569
+ const characterCode = text.charCodeAt(indexCharacter);
3570
+ if (characterCode < 0x80) {
3571
+ size += 1;
3572
+ } else if (characterCode < 0x800) {
3573
+ size += 2;
3574
+ } else if (characterCode < 0xd800 || characterCode >= 0xe000) {
3575
+ size += 3;
3576
+ } else if (characterCode < 0xdc00 && (text.charCodeAt(indexCharacter + 1) & 0xfc00) == 0xdc00) {
3577
+ size += 4;
3578
+ indexCharacter++;
3579
+ } else {
3580
+ size += 3;
3581
+ }
3582
+ }
3583
+ return size;
3584
+ }
3585
+
3553
3586
  class TextWriter extends BlobWriter {
3554
3587
 
3555
3588
  constructor(encoding) {
@@ -4034,9 +4067,8 @@
4034
4067
 
4035
4068
  async init() {
4036
4069
  const reader = this;
4037
- const { readers } = reader;
4038
4070
  reader.lastDiskNumber = 0;
4039
- await Promise.all(readers.map(diskReader => initStream(diskReader)));
4071
+ const readers = reader.readers = await Promise.all(reader.readers.map(initDiskReader));
4040
4072
  reader.diskOffsets = readers.map(diskReader => {
4041
4073
  const diskOffset = reader.size;
4042
4074
  reader.size += diskReader.size;
@@ -4213,6 +4245,10 @@
4213
4245
  }
4214
4246
  }
4215
4247
 
4248
+ function ownsWritable(writer) {
4249
+ return Boolean(writer && writer.getData);
4250
+ }
4251
+
4216
4252
  function isHttpFamily(url) {
4217
4253
  const { baseURI } = getConfiguration();
4218
4254
  const { protocol } = new URL(url, baseURI);
@@ -4227,6 +4263,16 @@
4227
4263
  }
4228
4264
  }
4229
4265
 
4266
+ async function initDiskReader(diskReader) {
4267
+ diskReader = new GenericReader(diskReader);
4268
+ await initStream(diskReader);
4269
+ if (diskReader.size === UNDEFINED_VALUE || !diskReader.readUint8Array) {
4270
+ diskReader = new BlobReader(await streamToBlob(diskReader.readable));
4271
+ await initStream(diskReader);
4272
+ }
4273
+ return diskReader;
4274
+ }
4275
+
4230
4276
  function readUint8Array(reader, offset, size) {
4231
4277
  return reader.readUint8Array(offset, size);
4232
4278
  }
@@ -4357,6 +4403,8 @@
4357
4403
  const PROPERTY_NAME_RAW_CREATION_DATE = "rawCreationDate";
4358
4404
  const PROPERTY_NAME_INTERNAL_FILE_ATTRIBUTES = "internalFileAttributes";
4359
4405
  const PROPERTY_NAME_EXTERNAL_FILE_ATTRIBUTES = "externalFileAttributes";
4406
+ const PROPERTY_NAME_DEPRECATED_INTERNAL_FILE_ATTRIBUTES = "internalFileAttribute";
4407
+ const PROPERTY_NAME_DEPRECATED_EXTERNAL_FILE_ATTRIBUTES = "externalFileAttribute";
4360
4408
  const PROPERTY_NAME_MSDOS_ATTRIBUTES_RAW = "msdosAttributesRaw";
4361
4409
  const PROPERTY_NAME_MSDOS_ATTRIBUTES = "msdosAttributes";
4362
4410
  const PROPERTY_NAME_MS_DOS_COMPATIBLE = "msDosCompatible";
@@ -4367,6 +4415,7 @@
4367
4415
  const PROPERTY_NAME_ZIPCRYPTO = "zipCrypto";
4368
4416
  const PROPERTY_NAME_DIRECTORY = "directory";
4369
4417
  const PROPERTY_NAME_EXECUTABLE = "executable";
4418
+ const PROPERTY_NAME_SYMLINK = "symlink";
4370
4419
  const PROPERTY_NAME_COMPRESSION_METHOD = "compressionMethod";
4371
4420
  const PROPERTY_NAME_SIGNATURE = "signature";
4372
4421
  const PROPERTY_NAME_CRC32 = "crc32";
@@ -4382,6 +4431,10 @@
4382
4431
  const PROPERTY_NAME_SETGID = "setgid";
4383
4432
  const PROPERTY_NAME_STICKY = "sticky";
4384
4433
  const PROPERTY_NAME_BITFLAG = "bitFlag";
4434
+ const PROPERTY_NAME_RAW_BITFLAG = "rawBitFlag";
4435
+ const PROPERTY_NAME_FILENAME_LENGTH = "filenameLength";
4436
+ const PROPERTY_NAME_EXTRA_FIELD_LENGTH = "extraFieldLength";
4437
+ const PROPERTY_NAME_UNIX_EXTERNAL_UPPER = "unixExternalUpper";
4385
4438
  const PROPERTY_NAME_FILENAME_UTF8 = "filenameUTF8";
4386
4439
  const PROPERTY_NAME_COMMENT_UTF8 = "commentUTF8";
4387
4440
  const PROPERTY_NAME_RAW_EXTRA_FIELD = "rawExtraField";
@@ -4410,6 +4463,8 @@
4410
4463
  PROPERTY_NAME_DISK_NUMBER_START,
4411
4464
  PROPERTY_NAME_INTERNAL_FILE_ATTRIBUTES,
4412
4465
  PROPERTY_NAME_EXTERNAL_FILE_ATTRIBUTES,
4466
+ PROPERTY_NAME_DEPRECATED_INTERNAL_FILE_ATTRIBUTES,
4467
+ PROPERTY_NAME_DEPRECATED_EXTERNAL_FILE_ATTRIBUTES,
4413
4468
  PROPERTY_NAME_MSDOS_ATTRIBUTES_RAW,
4414
4469
  PROPERTY_NAME_MSDOS_ATTRIBUTES,
4415
4470
  PROPERTY_NAME_MS_DOS_COMPATIBLE,
@@ -4420,6 +4475,7 @@
4420
4475
  PROPERTY_NAME_ZIPCRYPTO,
4421
4476
  PROPERTY_NAME_DIRECTORY,
4422
4477
  PROPERTY_NAME_EXECUTABLE,
4478
+ PROPERTY_NAME_SYMLINK,
4423
4479
  PROPERTY_NAME_COMPRESSION_METHOD,
4424
4480
  PROPERTY_NAME_SIGNATURE,
4425
4481
  PROPERTY_NAME_CRC32,
@@ -4431,10 +4487,14 @@
4431
4487
  PROPERTY_NAME_UID,
4432
4488
  PROPERTY_NAME_GID,
4433
4489
  PROPERTY_NAME_UNIX_MODE,
4490
+ PROPERTY_NAME_UNIX_EXTERNAL_UPPER,
4434
4491
  PROPERTY_NAME_SETUID,
4435
4492
  PROPERTY_NAME_SETGID,
4436
4493
  PROPERTY_NAME_STICKY,
4437
4494
  PROPERTY_NAME_BITFLAG,
4495
+ PROPERTY_NAME_RAW_BITFLAG,
4496
+ PROPERTY_NAME_FILENAME_LENGTH,
4497
+ PROPERTY_NAME_EXTRA_FIELD_LENGTH,
4438
4498
  PROPERTY_NAME_FILENAME_UTF8,
4439
4499
  PROPERTY_NAME_COMMENT_UTF8,
4440
4500
  PROPERTY_NAME_RAW_EXTRA_FIELD,
@@ -4496,6 +4556,7 @@
4496
4556
  const OPTION_CHECK_OVERLAPPING_ENTRY_ONLY = "checkOverlappingEntryOnly";
4497
4557
  const OPTION_CHECK_OVERLAPPING_ENTRY = "checkOverlappingEntry";
4498
4558
  const OPTION_CHECK_AMBIGUITY = "checkAmbiguity";
4559
+ const OPTION_CHECK_LOCAL_DIRECTORY = "checkLocalDirectory";
4499
4560
  const OPTION_CHECK_SIGNATURE = "checkSignature";
4500
4561
  const OPTION_CHECK_CRC32 = "checkCrc32";
4501
4562
  const OPTION_CHECK_AUTHENTICATION_CODE = "checkAuthenticationCode";
@@ -4627,7 +4688,7 @@
4627
4688
  if (reader.size < END_OF_CENTRAL_DIR_LENGTH) {
4628
4689
  throw new Error(ERR_BAD_FORMAT);
4629
4690
  }
4630
- const strictness = getStrictness(getOptionValue$1(zipReader, options, OPTION_STRICTNESS), getOptionValue$1(zipReader, options, OPTION_CHECK_AMBIGUITY));
4691
+ const strictness = getStrictness(options, zipReader.options);
4631
4692
  const checkAmbiguity = strictness == STRICTNESS_STRICT;
4632
4693
  const rejectAmbiguousEndOfDirectory = strictness != STRICTNESS_TOLERANT;
4633
4694
  const maxAppendedDataSize = getMaxAppendedDataSize(getOptionValue$1(zipReader, options, OPTION_MAX_APPENDED_DATA_SIZE), strictness);
@@ -4849,6 +4910,7 @@
4849
4910
  index: indexFile,
4850
4911
  versionMadeBy,
4851
4912
  msDosCompatible,
4913
+ zip64: false,
4852
4914
  compressedSize: 0,
4853
4915
  uncompressedSize: 0,
4854
4916
  commentLength,
@@ -4882,15 +4944,18 @@
4882
4944
  const setuid = Boolean(fileEntry.unixMode & FILE_ATTR_UNIX_SETUID_MASK);
4883
4945
  const setgid = Boolean(fileEntry.unixMode & FILE_ATTR_UNIX_SETGID_MASK);
4884
4946
  const sticky = Boolean(fileEntry.unixMode & FILE_ATTR_UNIX_STICKY_MASK);
4885
- const executable = (fileEntry.unixMode !== UNDEFINED_VALUE)
4947
+ const unixType = fileEntry.unixMode === UNDEFINED_VALUE ? unixExternalUpper : fileEntry.unixMode;
4948
+ const symlink = (unixType & FILE_ATTR_UNIX_TYPE_MASK) == FILE_ATTR_UNIX_TYPE_SYMLINK;
4949
+ const executable = !symlink && ((fileEntry.unixMode !== UNDEFINED_VALUE)
4886
4950
  ? ((fileEntry.unixMode & FILE_ATTR_UNIX_EXECUTABLE_MASK) != 0)
4887
- : (unixCompatible && ((unixExternalUpper & FILE_ATTR_UNIX_EXECUTABLE_MASK) != 0));
4951
+ : (unixCompatible && ((unixExternalUpper & FILE_ATTR_UNIX_EXECUTABLE_MASK) != 0)));
4888
4952
  const modeIsDir = fileEntry.unixMode !== UNDEFINED_VALUE && ((fileEntry.unixMode & FILE_ATTR_UNIX_TYPE_MASK) == FILE_ATTR_UNIX_TYPE_DIR);
4889
4953
  const upperIsDir = ((unixExternalUpper & FILE_ATTR_UNIX_TYPE_MASK) == FILE_ATTR_UNIX_TYPE_DIR);
4890
4954
  Object.assign(fileEntry, {
4891
4955
  setuid,
4892
4956
  setgid,
4893
4957
  sticky,
4958
+ symlink,
4894
4959
  unixExternalUpper,
4895
4960
  internalFileAttribute: fileEntry.internalFileAttributes,
4896
4961
  externalFileAttribute: fileEntry.externalFileAttributes,
@@ -4956,6 +5021,10 @@
4956
5021
  }
4957
5022
 
4958
5023
  async close() {
5024
+ const { reader } = this;
5025
+ if (!reader.readUint8Array && reader.readable && !reader.readable.locked) {
5026
+ await reader.readable.cancel();
5027
+ }
4959
5028
  }
4960
5029
  }
4961
5030
 
@@ -5052,9 +5121,12 @@
5052
5121
  extraFieldLength,
5053
5122
  filenameLength
5054
5123
  } = localDirectory;
5055
- const checkAmbiguity = getStrictness(getOptionValue$1(zipEntry, options, OPTION_STRICTNESS), getOptionValue$1(zipEntry, options, OPTION_CHECK_AMBIGUITY)) == STRICTNESS_STRICT;
5124
+ const checkLocalDirectoryOption = getOptionValue$1(zipEntry, options, OPTION_CHECK_LOCAL_DIRECTORY);
5125
+ const entryStrictness = getStrictness(options, zipEntry.options);
5126
+ const checkLocalDirectory = getCheckLocalDirectory(checkLocalDirectoryOption, entryStrictness);
5127
+ const checkLocalFilename = getCheckLocalFilename(checkLocalDirectoryOption, entryStrictness);
5056
5128
  let rawLocalFilename = EMPTY_UINT8_ARRAY;
5057
- if (checkAmbiguity && (filenameLength || extraFieldLength)) {
5129
+ if (checkLocalFilename && (filenameLength || extraFieldLength)) {
5058
5130
  const trailingDataArray = await readUint8Array(reader, localHeaderOffset + HEADER_SIZE, filenameLength + extraFieldLength);
5059
5131
  rawLocalFilename = trailingDataArray.subarray(0, filenameLength);
5060
5132
  localDirectory.rawExtraField = trailingDataArray.subarray(filenameLength);
@@ -5063,17 +5135,26 @@
5063
5135
  await readUint8Array(reader, localHeaderOffset + HEADER_SIZE + filenameLength, extraFieldLength) :
5064
5136
  EMPTY_UINT8_ARRAY;
5065
5137
  }
5138
+ if (checkLocalFilename) {
5139
+ localDirectory.rawFilename = rawLocalFilename;
5140
+ }
5066
5141
  readCommonFooter(zipEntry, localDirectory, dataView, 4, true);
5067
- if (checkAmbiguity) {
5068
- checkLocalDirectory(zipEntry, localDirectory, rawLocalFilename);
5142
+ if (checkLocalDirectory) {
5143
+ validateLocalDirectory(zipEntry, localDirectory, rawLocalFilename, checkLocalFilename);
5069
5144
  }
5070
- const { lastAccessDate, creationDate } = localDirectory;
5145
+ const { lastAccessDate, creationDate, uid, gid } = localDirectory;
5071
5146
  if (lastAccessDate) {
5072
5147
  fileEntry.lastAccessDate = lastAccessDate;
5073
5148
  }
5074
5149
  if (creationDate) {
5075
5150
  fileEntry.creationDate = creationDate;
5076
5151
  }
5152
+ if (uid !== UNDEFINED_VALUE && fileEntry.uid === UNDEFINED_VALUE) {
5153
+ fileEntry.uid = uid;
5154
+ }
5155
+ if (gid !== UNDEFINED_VALUE && fileEntry.gid === UNDEFINED_VALUE) {
5156
+ fileEntry.gid = gid;
5157
+ }
5077
5158
  const encrypted = zipEntry.encrypted && localDirectory.encrypted && !passThrough;
5078
5159
  const zipCrypto = encrypted && !extraFieldAES;
5079
5160
  if (!passThrough) {
@@ -5180,7 +5261,7 @@
5180
5261
  throw error;
5181
5262
  }
5182
5263
  } finally {
5183
- const preventClose = getOptionValue$1(zipEntry, options, OPTION_PREVENT_CLOSE);
5264
+ const preventClose = !ownsWritable(writer) && getOptionValue$1(zipEntry, options, OPTION_PREVENT_CLOSE);
5184
5265
  if (!preventClose && writable && !writable.locked) {
5185
5266
  const writableWriter = writable.getWriter();
5186
5267
  if (abortError) {
@@ -5309,10 +5390,12 @@
5309
5390
  directory.extraFieldNTFS = extraFieldNTFS;
5310
5391
  }
5311
5392
  const extraFieldUnix = extraField.get(EXTRAFIELD_TYPE_UNIX);
5393
+ let unixIdsRead;
5312
5394
  if (extraFieldUnix) {
5313
- readExtraFieldUnix(extraFieldUnix, directory, false);
5395
+ unixIdsRead = readExtraFieldUnix(extraFieldUnix, directory, false);
5314
5396
  directory.extraFieldUnix = extraFieldUnix;
5315
- } else {
5397
+ }
5398
+ if (!unixIdsRead) {
5316
5399
  const extraFieldInfoZip = extraField.get(EXTRAFIELD_TYPE_INFOZIP);
5317
5400
  if (extraFieldInfoZip) {
5318
5401
  readExtraFieldUnix(extraFieldInfoZip, directory, true);
@@ -5415,7 +5498,7 @@
5415
5498
  const creationDate = getDateNTFS(rawCreationDate);
5416
5499
  const extraFieldData = { lastModDate, lastAccessDate, creationDate };
5417
5500
  Object.assign(extraFieldNTFS, extraFieldData);
5418
- Object.assign(directory, extraFieldData);
5501
+ Object.assign(directory, extraFieldData, { rawLastAccessDate, rawCreationDate });
5419
5502
  }
5420
5503
  }
5421
5504
 
@@ -5424,8 +5507,8 @@
5424
5507
  return;
5425
5508
  }
5426
5509
  const extraFieldView = getDataView(extraField.data);
5427
- const lastAccessDate = new Date(getUint32(extraFieldView, 0) * 1000);
5428
- const lastModDate = new Date(getUint32(extraFieldView, 4) * 1000);
5510
+ const lastAccessDate = new Date((getUint32(extraFieldView, 0) | 0) * 1000);
5511
+ const lastModDate = new Date((getUint32(extraFieldView, 4) | 0) * 1000);
5429
5512
  const extraFieldData = { lastAccessDate, lastModDate };
5430
5513
  if (extraField.data.length >= 12) {
5431
5514
  extraFieldData.uid = getUint16(extraFieldView, 8);
@@ -5459,6 +5542,7 @@
5459
5542
  if (gid !== UNDEFINED_VALUE) {
5460
5543
  directory.gid = gid;
5461
5544
  }
5545
+ return uid !== UNDEFINED_VALUE || gid !== UNDEFINED_VALUE;
5462
5546
  } catch {
5463
5547
  // ignored
5464
5548
  }
@@ -5531,26 +5615,25 @@
5531
5615
  }
5532
5616
  if (dataDescriptorLength) {
5533
5617
  const dataDescriptorArray = await readUint8Array(reader, dataOffset + compressedSize, dataDescriptorLength + DATA_DESCRIPTOR_RECORD_SIGNATURE_LENGTH);
5534
- const dataDescriptorSignature = dataDescriptorArray.length == dataDescriptorLength + DATA_DESCRIPTOR_RECORD_SIGNATURE_LENGTH &&
5535
- getUint32(getDataView(dataDescriptorArray), 0) == DATA_DESCRIPTOR_RECORD_SIGNATURE;
5536
- if (dataDescriptorSignature) {
5537
- const readCrc32 = getUint32(getDataView(dataDescriptorArray), 4);
5538
- let readCompressedSize;
5539
- let readUncompressedSize;
5540
- if (extraFieldZip64) {
5541
- readCompressedSize = getBigUint64(getDataView(dataDescriptorArray), 8);
5542
- readUncompressedSize = getBigUint64(getDataView(dataDescriptorArray), 16);
5543
- } else {
5544
- readCompressedSize = getUint32(getDataView(dataDescriptorArray), 8);
5545
- readUncompressedSize = getUint32(getDataView(dataDescriptorArray), 12);
5546
- }
5547
- const matchCrc32 = (fileEntry.encrypted && !fileEntry.zipCrypto) || readCrc32 == crc32;
5618
+ const dataDescriptorView = getDataView(dataDescriptorArray);
5619
+ let signature = dataDescriptorArray.length == dataDescriptorLength + DATA_DESCRIPTOR_RECORD_SIGNATURE_LENGTH &&
5620
+ getUint32(dataDescriptorView, 0) == DATA_DESCRIPTOR_RECORD_SIGNATURE;
5621
+ if (signature) {
5622
+ const signedDataDescriptor = readDataDescriptor(dataDescriptorView, DATA_DESCRIPTOR_RECORD_SIGNATURE_LENGTH, extraFieldZip64);
5623
+ const matchCrc32 = (fileEntry.encrypted && !fileEntry.zipCrypto) || signedDataDescriptor.crc32 == crc32;
5548
5624
  if (matchCrc32 &&
5549
- readCompressedSize == compressedSize &&
5550
- readUncompressedSize == uncompressedSize) {
5625
+ signedDataDescriptor.compressedSize == compressedSize &&
5626
+ signedDataDescriptor.uncompressedSize == uncompressedSize) {
5551
5627
  dataDescriptorLength += DATA_DESCRIPTOR_RECORD_SIGNATURE_LENGTH;
5628
+ } else {
5629
+ signature = false;
5552
5630
  }
5553
5631
  }
5632
+ if (dataDescriptorArray.length >= dataDescriptorLength) {
5633
+ const localDataDescriptor = readDataDescriptor(dataDescriptorView, signature ? DATA_DESCRIPTOR_RECORD_SIGNATURE_LENGTH : 0, extraFieldZip64);
5634
+ localDataDescriptor.signature = signature;
5635
+ fileEntry.localDirectory.dataDescriptor = localDataDescriptor;
5636
+ }
5554
5637
  }
5555
5638
  const range = {
5556
5639
  start: offset,
@@ -5567,6 +5650,20 @@
5567
5650
  readRanges.set(index, range);
5568
5651
  }
5569
5652
 
5653
+ function readDataDescriptor(dataDescriptorView, offset, extraFieldZip64) {
5654
+ const crc32 = getUint32(dataDescriptorView, offset);
5655
+ let compressedSize;
5656
+ let uncompressedSize;
5657
+ if (extraFieldZip64) {
5658
+ compressedSize = getBigUint64(dataDescriptorView, offset + 4);
5659
+ uncompressedSize = getBigUint64(dataDescriptorView, offset + 12);
5660
+ } else {
5661
+ compressedSize = getUint32(dataDescriptorView, offset + 4);
5662
+ uncompressedSize = getUint32(dataDescriptorView, offset + 8);
5663
+ }
5664
+ return { crc32, compressedSize, uncompressedSize };
5665
+ }
5666
+
5570
5667
  function getDiskOffset$1(reader, diskNumber) {
5571
5668
  return reader.getDiskOffset ? reader.getDiskOffset(diskNumber) : 0;
5572
5669
  }
@@ -5575,14 +5672,40 @@
5575
5672
  return value === STRICTNESS_STRICT || value === STRICTNESS_BALANCED || value === STRICTNESS_TOLERANT;
5576
5673
  }
5577
5674
 
5578
- function getStrictness(strictness, checkAmbiguity) {
5579
- if (strictness === UNDEFINED_VALUE) {
5580
- return checkAmbiguity ? STRICTNESS_STRICT : STRICTNESS_BALANCED;
5675
+ function getStrictness(options, inheritedOptions) {
5676
+ return resolveStrictness(options, resolveStrictness(inheritedOptions, STRICTNESS_BALANCED));
5677
+ }
5678
+
5679
+ function resolveStrictness(options, inheritedStrictness) {
5680
+ const strictness = options[OPTION_STRICTNESS];
5681
+ if (strictness !== UNDEFINED_VALUE) {
5682
+ if (!isStrictnessValue(strictness)) {
5683
+ throw new Error(ERR_INVALID_STRICTNESS);
5684
+ }
5685
+ return strictness;
5581
5686
  }
5582
- if (!isStrictnessValue(strictness)) {
5583
- throw new Error(ERR_INVALID_STRICTNESS);
5687
+ const checkAmbiguity = options[OPTION_CHECK_AMBIGUITY];
5688
+ if (checkAmbiguity === UNDEFINED_VALUE) {
5689
+ return inheritedStrictness;
5584
5690
  }
5585
- return strictness;
5691
+ if (checkAmbiguity) {
5692
+ return STRICTNESS_STRICT;
5693
+ }
5694
+ return inheritedStrictness == STRICTNESS_TOLERANT ? STRICTNESS_TOLERANT : STRICTNESS_BALANCED;
5695
+ }
5696
+
5697
+ function getCheckLocalDirectory(checkLocalDirectory, strictness) {
5698
+ if (checkLocalDirectory === UNDEFINED_VALUE) {
5699
+ return strictness != STRICTNESS_TOLERANT;
5700
+ }
5701
+ return Boolean(checkLocalDirectory);
5702
+ }
5703
+
5704
+ function getCheckLocalFilename(checkLocalFilename, strictness) {
5705
+ if (checkLocalFilename === UNDEFINED_VALUE) {
5706
+ return strictness == STRICTNESS_STRICT;
5707
+ }
5708
+ return Boolean(checkLocalFilename);
5586
5709
  }
5587
5710
 
5588
5711
  function getFilenameValidation(filenameValidation, strictness) {
@@ -5730,10 +5853,11 @@
5730
5853
  return UNDEFINED_VALUE;
5731
5854
  }
5732
5855
 
5733
- function checkLocalDirectory(zipEntry, localDirectory, rawLocalFilename) {
5856
+ function validateLocalDirectory(zipEntry, localDirectory, rawLocalFilename, checkLocalFilename) {
5734
5857
  const { rawFilename } = zipEntry;
5735
- if (rawLocalFilename.length != rawFilename.length ||
5736
- rawLocalFilename.some((byteValue, indexByte) => byteValue != rawFilename[indexByte])) {
5858
+ if (checkLocalFilename &&
5859
+ (rawLocalFilename.length != rawFilename.length ||
5860
+ rawLocalFilename.some((byteValue, indexByte) => byteValue != rawFilename[indexByte]))) {
5737
5861
  throwAmbiguousArchive("mismatched local file header (filename)");
5738
5862
  }
5739
5863
  if ((localDirectory.rawBitFlag & BITFLAG_AMBIGUITY_MASK) != (zipEntry.rawBitFlag & BITFLAG_AMBIGUITY_MASK)) {
@@ -5851,11 +5975,13 @@
5851
5975
 
5852
5976
  const ERR_DUPLICATED_NAME = "File already exists";
5853
5977
  const ERR_INVALID_COMMENT = "Zip file comment exceeds 64KB";
5978
+ const ERR_INVALID_COMMENT_TYPE = "Invalid zip file comment (must be a Uint8Array)";
5854
5979
  const ERR_INVALID_ENTRY_COMMENT = "File entry comment exceeds 64KB";
5855
5980
  const ERR_INVALID_ENTRY_NAME = "File entry name exceeds 64KB";
5856
5981
  const ERR_INVALID_VERSION = "Version exceeds 65535";
5857
5982
  const ERR_INVALID_ENCRYPTION_STRENGTH = "The strength must equal 1, 2, or 3";
5858
5983
  const ERR_UNSUPPORTED_ENCRYPTION_USDZ = "Encryption is not supported in USDZ files";
5984
+ const ERR_UNSUPPORTED_ENCRYPTION_PASS_THROUGH = "Encryption is not supported when the 'passThrough' option is set";
5859
5985
  const ERR_INVALID_EXTRAFIELD_TYPE = "Extra field type exceeds 65535";
5860
5986
  const ERR_INVALID_EXTRAFIELD_DATA = "Extra field data exceeds 64KB";
5861
5987
  const ERR_UNSUPPORTED_COMPRESSION = "Compression method not supported";
@@ -5865,6 +5991,7 @@
5865
5991
  const MAX_NTFS_TIME = BigInt("0x7fffffffffffffff");
5866
5992
  const ERR_UNSUPPORTED_FORMAT = "Zip64 is not supported (set the 'zip64' option to 'true')";
5867
5993
  const ERR_UNDEFINED_UNCOMPRESSED_SIZE = "Undefined uncompressed size";
5994
+ const ERR_UNDETERMINED_SIZE = "Undetermined size";
5868
5995
  const ERR_UNDEFINED_READER = "Undefined reader";
5869
5996
  const ERR_ZIP_NOT_EMPTY = "Zip file not empty";
5870
5997
  const ERR_INVALID_UID = "Invalid uid (must be integer 0..2^32-1)";
@@ -5917,6 +6044,10 @@
5917
6044
  }
5918
6045
  reader = new GenericReader(reader);
5919
6046
  await initStream(reader);
6047
+ if (reader.size === UNDEFINED_VALUE || !reader.readUint8Array) {
6048
+ reader = new BlobReader(await streamToBlob(reader.readable));
6049
+ await initStream(reader);
6050
+ }
5920
6051
  const { ZipReader } = await Promise.resolve().then(function () { return zipReader; });
5921
6052
  const zipReader$1 = new ZipReader(reader.readable);
5922
6053
  const entries = await zipReader$1.getEntries();
@@ -6065,6 +6196,9 @@
6065
6196
  const zipWriter = this;
6066
6197
  const { pendingAddFileCalls, writer } = this;
6067
6198
  const { writable } = writer;
6199
+ if (!(comment instanceof Uint8Array)) {
6200
+ throw new Error(ERR_INVALID_COMMENT_TYPE);
6201
+ }
6068
6202
  if (getLength(comment) > MAX_16_BITS) {
6069
6203
  throw new Error(ERR_INVALID_COMMENT);
6070
6204
  }
@@ -6072,7 +6206,7 @@
6072
6206
  await Promise.allSettled(Array.from(pendingAddFileCalls));
6073
6207
  }
6074
6208
  await closeFile(zipWriter, comment, options);
6075
- const preventClose = getOptionValue(zipWriter, options, OPTION_PREVENT_CLOSE);
6209
+ const preventClose = !ownsWritable(writer) && getOptionValue(zipWriter, options, OPTION_PREVENT_CLOSE);
6076
6210
  if (!preventClose) {
6077
6211
  await writable.getWriter().close();
6078
6212
  }
@@ -6161,8 +6295,6 @@
6161
6295
  const diskOffset = getDiskOffset(zipWriter.writer);
6162
6296
  const diskNumber = getDiskNumber(zipWriter.writer);
6163
6297
  options = Object.assign({}, options, attributesInfo.resolvedOptions, metadataInfo.resolvedOptions, sizesInfo.resolvedOptions, {
6164
- internalFileAttribute: metadataInfo.resolvedOptions.internalFileAttributes,
6165
- externalFileAttribute: attributesInfo.resolvedOptions.externalFileAttributes,
6166
6298
  signature: options[PROPERTY_NAME_SIGNATURE],
6167
6299
  crc32: options.crc32 === UNDEFINED_VALUE ? options[PROPERTY_NAME_SIGNATURE] : options.crc32,
6168
6300
  offset: zipWriter.offset - diskOffset,
@@ -6176,14 +6308,20 @@
6176
6308
  zipWriter.files.delete(name);
6177
6309
  throw error;
6178
6310
  }
6179
- Object.assign(fileEntry, { name, comment, extraField });
6311
+ Object.assign(fileEntry, {
6312
+ name,
6313
+ comment,
6314
+ extraField,
6315
+ [PROPERTY_NAME_DEPRECATED_INTERNAL_FILE_ATTRIBUTES]: fileEntry.internalFileAttributes,
6316
+ [PROPERTY_NAME_DEPRECATED_EXTERNAL_FILE_ATTRIBUTES]: fileEntry.externalFileAttributes
6317
+ });
6180
6318
  return new Entry(fileEntry);
6181
6319
  }
6182
6320
 
6183
6321
  function resolveAttributes(zipWriter, name, options) {
6184
6322
  name = name.trim();
6185
6323
  let msDosCompatible = getOptionValue(zipWriter, options, PROPERTY_NAME_MS_DOS_COMPATIBLE);
6186
- let versionMadeBy = getOptionValue(zipWriter, options, PROPERTY_NAME_VERSION_MADE_BY, msDosCompatible ? 20 : 768);
6324
+ let versionMadeBy = getOptionValue(zipWriter, options, PROPERTY_NAME_VERSION_MADE_BY, msDosCompatible ? VERSION_MADE_BY_MSDOS : VERSION_MADE_BY_UNIX);
6187
6325
  const executable = getOptionValue(zipWriter, options, PROPERTY_NAME_EXECUTABLE);
6188
6326
  const uid = getNumberOptionValue(zipWriter, options, PROPERTY_NAME_UID);
6189
6327
  const gid = getNumberOptionValue(zipWriter, options, PROPERTY_NAME_GID);
@@ -6217,7 +6355,7 @@
6217
6355
  const hasMsDosProvided = msdosAttributesRaw !== UNDEFINED_VALUE || msdosAttributes !== UNDEFINED_VALUE;
6218
6356
  if (hasUnixMetadata) {
6219
6357
  msDosCompatible = false;
6220
- versionMadeBy = (versionMadeBy & MAX_16_BITS) | (3 << 8);
6358
+ versionMadeBy = (versionMadeBy & MAX_8_BITS) | VERSION_MADE_BY_UNIX;
6221
6359
  } else if (hasMsDosProvided) {
6222
6360
  msDosCompatible = true;
6223
6361
  versionMadeBy = (versionMadeBy & MAX_8_BITS);
@@ -6231,7 +6369,7 @@
6231
6369
  if (versionMadeBy > MAX_16_BITS) {
6232
6370
  throw new Error(ERR_INVALID_VERSION);
6233
6371
  }
6234
- let externalFileAttributes = getOptionValue(zipWriter, options, PROPERTY_NAME_EXTERNAL_FILE_ATTRIBUTES);
6372
+ let externalFileAttributes = getAliasedOptionValue(zipWriter, options, PROPERTY_NAME_EXTERNAL_FILE_ATTRIBUTES, PROPERTY_NAME_DEPRECATED_EXTERNAL_FILE_ATTRIBUTES);
6235
6373
  const externalFileAttributesProvided = externalFileAttributes !== UNDEFINED_VALUE;
6236
6374
  if (!externalFileAttributesProvided) {
6237
6375
  externalFileAttributes = 0;
@@ -6257,11 +6395,10 @@
6257
6395
  externalFileAttributes = FILE_ATTR_UNIX_DEFAULT_MASK << 16;
6258
6396
  }
6259
6397
  }
6260
- let unixExternalUpper;
6261
6398
  if (!msDosCompatible) {
6262
6399
  const unixModeProvided = unixMode !== UNDEFINED_VALUE || Boolean(setuid || setgid || sticky);
6263
- unixExternalUpper = (externalFileAttributes >> 16) & MAX_16_BITS;
6264
- unixMode = unixMode === UNDEFINED_VALUE ? unixExternalUpper : (unixMode & MAX_16_BITS);
6400
+ const defaultUnixMode = (externalFileAttributes >> 16) & MAX_16_BITS;
6401
+ unixMode = unixMode === UNDEFINED_VALUE ? defaultUnixMode : (unixMode & MAX_16_BITS);
6265
6402
  if (setuid) {
6266
6403
  unixMode |= FILE_ATTR_UNIX_SETUID_MASK;
6267
6404
  } else {
@@ -6279,7 +6416,9 @@
6279
6416
  }
6280
6417
  if (!externalFileAttributesProvided || unixModeProvided) {
6281
6418
  if (directory) {
6282
- unixMode |= FILE_ATTR_UNIX_TYPE_DIR;
6419
+ unixMode = (unixMode & ~FILE_ATTR_UNIX_TYPE_MASK) | FILE_ATTR_UNIX_TYPE_DIR;
6420
+ } else if (!(unixMode & FILE_ATTR_UNIX_TYPE_MASK)) {
6421
+ unixMode |= FILE_ATTR_UNIX_TYPE_FILE;
6283
6422
  }
6284
6423
  externalFileAttributes = ((unixMode & MAX_16_BITS) << 16) | (externalFileAttributes & MAX_16_BITS);
6285
6424
  }
@@ -6288,17 +6427,20 @@
6288
6427
  if (hasMsDosProvided) {
6289
6428
  externalFileAttributes = (externalFileAttributes & MAX_32_BITS) | (msdosAttributesRaw & MAX_8_BITS);
6290
6429
  }
6430
+ const unixExternalUpper = (externalFileAttributes >> 16) & MAX_16_BITS;
6431
+ const symlink = unixMode !== UNDEFINED_VALUE && ((unixMode & FILE_ATTR_UNIX_TYPE_MASK) == FILE_ATTR_UNIX_TYPE_SYMLINK);
6291
6432
  return {
6292
6433
  name,
6293
6434
  resolvedOptions: {
6294
6435
  versionMadeBy,
6295
- msDosCompatible,
6436
+ msDosCompatible: Boolean(msDosCompatible),
6296
6437
  externalFileAttributes,
6297
6438
  unixExternalUpper,
6298
6439
  uid,
6299
6440
  gid,
6300
6441
  unixMode,
6301
6442
  unixExtraFieldType,
6443
+ symlink,
6302
6444
  setuid,
6303
6445
  setgid,
6304
6446
  sticky,
@@ -6332,15 +6474,12 @@
6332
6474
  const lastModDate = getOptionValue(zipWriter, options, PROPERTY_NAME_LAST_MODIFICATION_DATE, new Date());
6333
6475
  const lastAccessDate = getOptionValue(zipWriter, options, PROPERTY_NAME_LAST_ACCESS_DATE);
6334
6476
  const creationDate = getOptionValue(zipWriter, options, PROPERTY_NAME_CREATION_DATE);
6335
- const internalFileAttributes = getOptionValue(zipWriter, options, PROPERTY_NAME_INTERNAL_FILE_ATTRIBUTES, 0);
6477
+ const internalFileAttributes = getAliasedOptionValue(zipWriter, options, PROPERTY_NAME_INTERNAL_FILE_ATTRIBUTES, PROPERTY_NAME_DEPRECATED_INTERNAL_FILE_ATTRIBUTES, 0);
6336
6478
  const passThrough = getOptionValue(zipWriter, options, OPTION_PASS_THROUGH);
6337
- let password, rawPassword;
6338
- if (!passThrough) {
6339
- password = getOptionValue(zipWriter, options, OPTION_PASSWORD);
6340
- rawPassword = getOptionValue(zipWriter, options, OPTION_RAW_PASSWORD);
6341
- if ((password && typeof password != STRING_TYPE) || (rawPassword && !(rawPassword instanceof Uint8Array))) {
6342
- throw new Error(ERR_INVALID_PASSWORD_TYPE);
6343
- }
6479
+ const password = getOptionValue(zipWriter, options, OPTION_PASSWORD);
6480
+ const rawPassword = getOptionValue(zipWriter, options, OPTION_RAW_PASSWORD);
6481
+ if ((password && typeof password != STRING_TYPE) || (rawPassword && !(rawPassword instanceof Uint8Array))) {
6482
+ throw new Error(ERR_INVALID_PASSWORD_TYPE);
6344
6483
  }
6345
6484
  const encryptionStrength = getNumberOptionValue(zipWriter, options, OPTION_ENCRYPTION_STRENGTH, 3);
6346
6485
  const zipCrypto = getOptionValue(zipWriter, options, PROPERTY_NAME_ZIPCRYPTO);
@@ -6453,14 +6592,24 @@
6453
6592
  }
6454
6593
 
6455
6594
  async function resolveSizes(zipWriter, reader, { resolvedOptions: metadata }, options) {
6595
+ if (metadata.passThrough && !reader && !getOptionValue(zipWriter, options, PROPERTY_NAME_DIRECTORY)) {
6596
+ throw new Error(ERR_UNDEFINED_READER);
6597
+ }
6598
+ let contentSize;
6599
+ if (reader) {
6600
+ reader = new GenericReader(reader);
6601
+ await initStream(reader);
6602
+ ({ size: contentSize } = reader);
6603
+ }
6604
+ return Object.assign({ reader }, resolveEntrySizes(zipWriter, Boolean(reader), contentSize, metadata, options));
6605
+ }
6606
+
6607
+ function resolveEntrySizes(zipWriter, hasContent, contentSize, metadata, options) {
6456
6608
  const { passThrough, zipCrypto, password, rawPassword, encryptionStrength } = metadata;
6457
6609
  let { dataDescriptor, zip64, level, compressionMethod } = metadata;
6458
6610
  let maximumCompressedSize = 0;
6459
6611
  let uncompressedSize = 0;
6460
- if (passThrough) {
6461
- if (!reader) {
6462
- throw new Error(ERR_UNDEFINED_READER);
6463
- }
6612
+ if (passThrough && hasContent) {
6464
6613
  uncompressedSize = options[PROPERTY_NAME_UNCOMPRESSED_SIZE];
6465
6614
  if (uncompressedSize === UNDEFINED_VALUE) {
6466
6615
  throw new Error(ERR_UNDEFINED_UNCOMPRESSED_SIZE);
@@ -6468,29 +6617,30 @@
6468
6617
  }
6469
6618
  const zip64Enabled = zip64 === true;
6470
6619
  const encrypted = getOptionValue(zipWriter, options, PROPERTY_NAME_ENCRYPTED);
6471
- const encryptedEntry = Boolean(reader) && (Boolean((password && getLength(password)) || (rawPassword && getLength(rawPassword))) || (passThrough && encrypted));
6472
- if (!reader) {
6620
+ if (hasContent && passThrough && !encrypted && getLength(password, rawPassword)) {
6621
+ throw new Error(ERR_UNSUPPORTED_ENCRYPTION_PASS_THROUGH);
6622
+ }
6623
+ const encryptedEntry = hasContent && (Boolean((password && getLength(password)) || (rawPassword && getLength(rawPassword))) || (passThrough && encrypted));
6624
+ if (!hasContent) {
6473
6625
  level = 0;
6474
6626
  compressionMethod = COMPRESSION_METHOD_STORE;
6475
6627
  }
6476
6628
  const encryptionOverhead = encryptedEntry ? (zipCrypto ? 12 : 16 + encryptionStrength * 4) : 0;
6477
- if (reader) {
6478
- reader = new GenericReader(reader);
6479
- await initStream(reader);
6629
+ if (hasContent) {
6480
6630
  if (!passThrough) {
6481
- if (reader.size === UNDEFINED_VALUE) {
6631
+ if (contentSize === UNDEFINED_VALUE) {
6482
6632
  dataDescriptor = true;
6483
6633
  if (zip64 || zip64 === UNDEFINED_VALUE) {
6484
6634
  zip64 = true;
6485
6635
  uncompressedSize = maximumCompressedSize = MAX_32_BITS + 1;
6486
6636
  }
6487
6637
  } else {
6488
- options.uncompressedSize = uncompressedSize = reader.size;
6489
- maximumCompressedSize = getMaximumCompressedSize(uncompressedSize) + encryptionOverhead;
6638
+ options.uncompressedSize = uncompressedSize = contentSize;
6639
+ maximumCompressedSize = (isCompressed(compressionMethod, level) ? getMaximumCompressedSize(uncompressedSize) : uncompressedSize) + encryptionOverhead;
6490
6640
  }
6491
6641
  } else {
6492
6642
  options.uncompressedSize = uncompressedSize;
6493
- maximumCompressedSize = getMaximumCompressedSize(uncompressedSize) + encryptionOverhead;
6643
+ maximumCompressedSize = contentSize === UNDEFINED_VALUE ? getMaximumCompressedSize(uncompressedSize) + encryptionOverhead : contentSize;
6494
6644
  }
6495
6645
  }
6496
6646
  const zip64UncompressedSize = zip64Enabled || uncompressedSize >= MAX_32_BITS;
@@ -6504,7 +6654,7 @@
6504
6654
  }
6505
6655
  zip64 = zip64 || false;
6506
6656
  return {
6507
- reader,
6657
+ maximumCompressedSize,
6508
6658
  resolvedOptions: {
6509
6659
  dataDescriptor,
6510
6660
  zip64,
@@ -6518,6 +6668,81 @@
6518
6668
  };
6519
6669
  }
6520
6670
 
6671
+ async function getEntriesSize(writerOptions, entries, writeOrderGuaranteed, comment) {
6672
+ const zipWriter = { options: writerOptions, config: getConfiguration() };
6673
+ if (writerOptions[OPTION_SIGN_CENTRAL_DIRECTORY]) {
6674
+ throw new Error(ERR_UNDETERMINED_SIZE);
6675
+ }
6676
+ if (comment !== UNDEFINED_VALUE && !(comment instanceof Uint8Array)) {
6677
+ throw new Error(ERR_INVALID_COMMENT_TYPE);
6678
+ }
6679
+ const commentLength = getLength(comment);
6680
+ if (commentLength > MAX_16_BITS) {
6681
+ throw new Error(ERR_INVALID_COMMENT);
6682
+ }
6683
+ const usdz = writerOptions[OPTION_USDZ];
6684
+ const files = new Map();
6685
+ let layoutDependsOnWriteOrder = Boolean(usdz);
6686
+ let offset = 0;
6687
+ for (const entry of entries) {
6688
+ let { name } = entry;
6689
+ const { size } = entry;
6690
+ const options = Object.assign({}, entry.options);
6691
+ name = name.trim();
6692
+ if (getOptionValue(zipWriter, options, PROPERTY_NAME_DIRECTORY) && !name.endsWith(DIRECTORY_SIGNATURE)) {
6693
+ name += DIRECTORY_SIGNATURE;
6694
+ }
6695
+ const attributesInfo = resolveAttributes(zipWriter, name, options);
6696
+ ({ name } = attributesInfo);
6697
+ const { resolvedOptions: metadata } = resolveMetadata(zipWriter, name, options);
6698
+ if (metadata.level != 0 && metadata.compressionMethod === UNDEFINED_VALUE &&
6699
+ !metadata.passThrough && !(await supportsDeflate(zipWriter.config))) {
6700
+ metadata.level = 0;
6701
+ }
6702
+ const hasContent = !getOptionValue(zipWriter, options, PROPERTY_NAME_DIRECTORY);
6703
+ if (hasContent && size === UNDEFINED_VALUE) {
6704
+ throw new Error(ERR_UNDETERMINED_SIZE);
6705
+ }
6706
+ const { maximumCompressedSize, resolvedOptions: sizes } = resolveEntrySizes(zipWriter, hasContent, size, metadata, options);
6707
+ if (hasContent && !metadata.passThrough && isCompressed(sizes.compressionMethod, sizes.level)) {
6708
+ throw new Error(ERR_UNDETERMINED_SIZE);
6709
+ }
6710
+ const entryOptions = Object.assign({}, options, attributesInfo.resolvedOptions, metadata, sizes);
6711
+ const headerInfo = getHeaderInfo(entryOptions);
6712
+ const dataDescriptorInfo = getDataDescriptorInfo(entryOptions);
6713
+ const entryInfo = {
6714
+ headerInfo,
6715
+ metadataSize: getLength(headerInfo.localHeaderArray, dataDescriptorInfo.dataDescriptorArray)
6716
+ };
6717
+ if (usdz) {
6718
+ appendExtraFieldUSDZ(entryInfo, offset);
6719
+ }
6720
+ const compressedSize = hasContent ? maximumCompressedSize : 0;
6721
+ if (offset >= MAX_32_BITS) {
6722
+ layoutDependsOnWriteOrder = true;
6723
+ }
6724
+ files.set(name, Object.assign({}, entryOptions, headerInfo, {
6725
+ offset,
6726
+ diskNumberStart: 0,
6727
+ compressedSize
6728
+ }));
6729
+ offset += entryInfo.metadataSize + compressedSize;
6730
+ }
6731
+ if (layoutDependsOnWriteOrder && !writeOrderGuaranteed) {
6732
+ throw new Error(ERR_UNDETERMINED_SIZE);
6733
+ }
6734
+ const directoryDataLength = createDirectoryRecords(files);
6735
+ let zip64 = getOptionValue(zipWriter, writerOptions, PROPERTY_NAME_ZIP64);
6736
+ if (offset >= MAX_32_BITS || directoryDataLength >= MAX_32_BITS || files.size >= MAX_16_BITS) {
6737
+ if (zip64 === false) {
6738
+ throw new Error(ERR_UNSUPPORTED_FORMAT);
6739
+ } else {
6740
+ zip64 = true;
6741
+ }
6742
+ }
6743
+ return offset + directoryDataLength + commentLength + (zip64 ? ZIP64_END_OF_CENTRAL_DIR_TOTAL_LENGTH : END_OF_CENTRAL_DIR_LENGTH);
6744
+ }
6745
+
6521
6746
  async function getFileEntry(zipWriter, name, reader, entryInfo, options) {
6522
6747
  const {
6523
6748
  files,
@@ -6732,6 +6957,7 @@
6732
6957
  uid,
6733
6958
  gid,
6734
6959
  unixMode,
6960
+ symlink,
6735
6961
  setuid,
6736
6962
  setgid,
6737
6963
  sticky,
@@ -6768,6 +6994,7 @@
6768
6994
  uid,
6769
6995
  gid,
6770
6996
  unixMode,
6997
+ symlink: Boolean(symlink),
6771
6998
  setuid,
6772
6999
  setgid,
6773
7000
  sticky,
@@ -6848,8 +7075,8 @@
6848
7075
  rawLastModDate,
6849
7076
  creationDate,
6850
7077
  lastAccessDate,
6851
- encrypted,
6852
- zipCrypto,
7078
+ encrypted: Boolean(encrypted),
7079
+ zipCrypto: Boolean(zipCrypto),
6853
7080
  size: metadataSize + compressedSize,
6854
7081
  compressionMethod,
6855
7082
  version,
@@ -6889,9 +7116,7 @@
6889
7116
  crc32
6890
7117
  } = options;
6891
7118
  let { version, compressionMethod } = options;
6892
- const compressed = !directory && (compressionMethod === UNDEFINED_VALUE
6893
- ? (level === UNDEFINED_VALUE || level > 0)
6894
- : compressionMethod !== COMPRESSION_METHOD_STORE);
7119
+ const compressed = !directory && isCompressed(compressionMethod, level);
6895
7120
  let rawLocalExtraFieldZip64;
6896
7121
  const uncompressedFile = passThrough || !compressed;
6897
7122
  const zip64ExtraFieldComplete = zip64 && (options.bufferedWrite || !dataDescriptor || ((!zip64UncompressedSize && !zip64CompressedSize) || uncompressedFile));
@@ -7578,6 +7803,16 @@
7578
7803
  return result === UNDEFINED_VALUE ? defaultValue : result;
7579
7804
  }
7580
7805
 
7806
+ function getAliasedOptionValue(zipWriter, options, name, deprecatedName, defaultValue) {
7807
+ const value = getAliasedValue(options, name, deprecatedName);
7808
+ const result = value === UNDEFINED_VALUE ? getAliasedValue(zipWriter.options, name, deprecatedName) : value;
7809
+ return result === UNDEFINED_VALUE ? defaultValue : result;
7810
+ }
7811
+
7812
+ function getAliasedValue(options, name, deprecatedName) {
7813
+ return options[name] === UNDEFINED_VALUE ? options[deprecatedName] : options[name];
7814
+ }
7815
+
7581
7816
  function getNumberOptionValue(zipWriter, options, name, defaultValue) {
7582
7817
  return toNumber(getOptionValue(zipWriter, options, name, defaultValue));
7583
7818
  }
@@ -7590,6 +7825,12 @@
7590
7825
  return uncompressedSize + (5 * (Math.floor(uncompressedSize / 16383) + 1));
7591
7826
  }
7592
7827
 
7828
+ function isCompressed(compressionMethod, level) {
7829
+ return compressionMethod === UNDEFINED_VALUE
7830
+ ? (level === UNDEFINED_VALUE || level > 0)
7831
+ : compressionMethod !== COMPRESSION_METHOD_STORE;
7832
+ }
7833
+
7593
7834
  function setUint8(view, offset, value) {
7594
7835
  view.setUint8(offset, value);
7595
7836
  }
@@ -8603,6 +8844,7 @@
8603
8844
 
8604
8845
  const ERR_ENTRY_EXISTS = "Entry filename already exists";
8605
8846
  const ERR_READABLE_CONSUMED = "Readable stream already consumed";
8847
+ const ERR_INVALID_PASS_THROUGH = "Invalid passThrough option (use readerOptions.passThrough or set uncompressedSize for each entry)";
8606
8848
  const ERR_ABORT_EXPORT = "zipjs-abort-export";
8607
8849
  const ERR_ABORTED = "The operation was aborted";
8608
8850
  const ABORT_ERROR_NAME = "AbortError";
@@ -8640,6 +8882,7 @@
8640
8882
  parent,
8641
8883
  children: [],
8642
8884
  uncompressedSize: params.uncompressedSize || 0,
8885
+ undeterminedSize: params.undeterminedSize || params.uncompressedSize === UNDEFINED_VALUE,
8643
8886
  passThrough: params.passThrough
8644
8887
  });
8645
8888
  if (parent || !fs.root) {
@@ -8707,16 +8950,17 @@
8707
8950
 
8708
8951
  async getData(writer, options = {}) {
8709
8952
  const zipEntry = this;
8710
- if (!writer || (writer.constructor == zipEntry.Writer && zipEntry.data)) {
8953
+ if (!writer || (writer.constructor == zipEntry.Writer && zipEntry.data && keepsContentType(writer, zipEntry.data))) {
8711
8954
  return zipEntry.data;
8712
8955
  } else {
8713
8956
  const reader = zipEntry.reader = createReader(zipEntry.Reader, zipEntry.data, options);
8714
- const uncompressedSize = zipEntry.data ? zipEntry.data.uncompressedSize : reader.size;
8715
- await Promise.all([initStream(reader), initStream(writer, uncompressedSize)]);
8716
- const { readable } = reader;
8957
+ const dataSize = zipEntry.uncompressedSize || reader.size;
8958
+ await Promise.all([initStream(reader), initStream(writer, dataSize)]);
8717
8959
  const { signal } = options;
8960
+ const readable = createProgressReadable(zipEntry, reader, options, signal);
8961
+ const preventClose = !ownsWritable(writer) && Boolean(options.preventClose);
8718
8962
  zipEntry.uncompressedSize = reader.size;
8719
- await toCompatibleReadable(readable).pipeTo(toCompatibleWritable(writer.writable), { signal });
8963
+ await toCompatibleReadable(readable).pipeTo(toCompatibleWritable(writer.writable), { signal, preventClose, preventAbort: preventClose });
8720
8964
  return writer.getData ? writer.getData() : writer.writable;
8721
8965
  }
8722
8966
  }
@@ -8847,7 +9091,7 @@
8847
9091
  Reader: TextReader,
8848
9092
  Writer: TextWriter,
8849
9093
  options,
8850
- uncompressedSize: text.length
9094
+ uncompressedSize: getTextSize(text)
8851
9095
  });
8852
9096
  }
8853
9097
 
@@ -8976,10 +9220,16 @@
8976
9220
  }
8977
9221
 
8978
9222
  async importZip(reader, options = {}) {
8979
- await initStream(reader);
8980
- const zipReader = new ZipReader(reader, options);
9223
+ let zipReader;
9224
+ if (reader && typeof reader.getEntries == FUNCTION_TYPE) {
9225
+ zipReader = reader;
9226
+ options = Object.assign({}, zipReader.options, options);
9227
+ } else {
9228
+ await initStream(reader);
9229
+ zipReader = new ZipReader(reader, options);
9230
+ }
8981
9231
  const importedEntries = [];
8982
- const entries = await zipReader.getEntries();
9232
+ const entries = await zipReader.getEntries(options);
8983
9233
  for (const entry of entries) {
8984
9234
  let parent = this;
8985
9235
  try {
@@ -9001,7 +9251,7 @@
9001
9251
  importedEntries.push(addChild(parent, name, {
9002
9252
  data: entry,
9003
9253
  Reader: getZipBlobReader(Object.assign({}, options)),
9004
- uncompressedSize: entry.uncompressedSize,
9254
+ uncompressedSize: options.passThrough ? entry.compressedSize : entry.uncompressedSize,
9005
9255
  passThrough: options.passThrough
9006
9256
  }));
9007
9257
  } else {
@@ -9043,11 +9293,25 @@
9043
9293
  }
9044
9294
  const [readers] = await Promise.all([initReaders(zipEntry, options.readerOptions), initStream(writer)]);
9045
9295
  const zipWriter = new ZipWriter(writer, options);
9046
- await exportZip(zipWriter, zipEntry, getTotalSize([zipEntry], "uncompressedSize"), options, readers);
9047
- await zipWriter.close();
9296
+ await exportZip(zipWriter, zipEntry, getTotalSize([zipEntry], getUncompressedSize), options, readers);
9297
+ await zipWriter.close(options.globalComment);
9048
9298
  return writer.getData ? writer.getData() : writer.writable;
9049
9299
  }
9050
9300
 
9301
+ getExportedSize(options = {}) {
9302
+ const zipEntry = this;
9303
+ options = Object.assign({}, options);
9304
+ if (options.bufferedWrite === UNDEFINED_VALUE) {
9305
+ options.bufferedWrite = true;
9306
+ }
9307
+ const writeOrderGuaranteed = !options.bufferedWrite ||
9308
+ (options.keepOrder !== false && zipEntry.children.every(child => !child.children.length));
9309
+ return getEntriesSize(options, Array.from(zipEntry.getChildren({ recursive: true }), child => {
9310
+ const { name, entryOptions } = getChildEntryOptions(child, zipEntry, options);
9311
+ return { name, size: child.directory ? 0 : getDeterminedSize(child, isPassThrough(child, options)), options: entryOptions };
9312
+ }), writeOrderGuaranteed, options.globalComment);
9313
+ }
9314
+
9051
9315
  getChildByName(name) {
9052
9316
  const children = this.children;
9053
9317
  for (let childIndex = 0; childIndex < children.length; childIndex++) {
@@ -9255,6 +9519,10 @@
9255
9519
  return this.root.exportZip(writer, options);
9256
9520
  }
9257
9521
 
9522
+ getExportedSize(options) {
9523
+ return this.root.getExportedSize(options);
9524
+ }
9525
+
9258
9526
  isPasswordProtected() {
9259
9527
  return this.root.isPasswordProtected();
9260
9528
  }
@@ -9266,12 +9534,12 @@
9266
9534
 
9267
9535
  const fs = { FS, ZipDirectoryEntry, ZipFileEntry };
9268
9536
 
9269
- function getTotalSize(entries, propertyName) {
9537
+ function getTotalSize(entries, getEntrySize) {
9270
9538
  let size = 0;
9271
9539
  const pendingEntries = Array.from(entries);
9272
9540
  while (pendingEntries.length) {
9273
9541
  const entry = pendingEntries.pop();
9274
- size += entry[propertyName] || 0;
9542
+ size += getEntrySize(entry) || 0;
9275
9543
  for (const child of entry.children) {
9276
9544
  pendingEntries.push(child);
9277
9545
  }
@@ -9279,6 +9547,15 @@
9279
9547
  return size;
9280
9548
  }
9281
9549
 
9550
+ function getUncompressedSize(entry) {
9551
+ return entry.uncompressedSize;
9552
+ }
9553
+
9554
+ function getExtractedSize(entry, passThrough) {
9555
+ const { data } = entry;
9556
+ return passThrough && data instanceof Entry ? data.compressedSize : entry.uncompressedSize;
9557
+ }
9558
+
9282
9559
  function getReadableReader(readable) {
9283
9560
  let consumed;
9284
9561
  return function () {
@@ -9301,10 +9578,17 @@
9301
9578
 
9302
9579
  async init() {
9303
9580
  const zipBlobReader = this;
9304
- zipBlobReader.size = zipBlobReader.entry.uncompressedSize;
9305
- const data = await zipBlobReader.entry.getData(new BlobWriter(), Object.assign({}, options, zipBlobReader.options));
9581
+ const readerOptions = Object.assign({}, options, zipBlobReader.options);
9582
+ const { checkOverlappingEntry, checkOverlappingEntryOnly } = readerOptions;
9583
+ const data = await zipBlobReader.entry.getData(new BlobWriter(), Object.assign(readerOptions, {
9584
+ checkPasswordOnly: false,
9585
+ checkOverlappingEntry: checkOverlappingEntryOnly || checkOverlappingEntry,
9586
+ checkOverlappingEntryOnly: false,
9587
+ preventClose: false
9588
+ }));
9306
9589
  zipBlobReader.data = data;
9307
9590
  zipBlobReader.blobReader = new BlobReader(data);
9591
+ zipBlobReader.size = data.size;
9308
9592
  super.init();
9309
9593
  }
9310
9594
 
@@ -9318,6 +9602,30 @@
9318
9602
  return Reader.prototype ? new Reader(data, options) : Reader(data, options);
9319
9603
  }
9320
9604
 
9605
+ function keepsContentType(writer, data) {
9606
+ const { contentType } = writer;
9607
+ if (contentType === UNDEFINED_VALUE) {
9608
+ return true;
9609
+ } else if (writer.constructor == BlobWriter) {
9610
+ return data.type == contentType;
9611
+ } else if (writer.constructor == Data64URIWriter) {
9612
+ return data.startsWith(writer.data);
9613
+ } else {
9614
+ return true;
9615
+ }
9616
+ }
9617
+
9618
+ function createProgressReadable(zipEntry, reader, options, signal) {
9619
+ const { onstart, onprogress, onend } = options;
9620
+ const { readable } = reader;
9621
+ const coreReaderReportsProgress = zipEntry.data instanceof Entry;
9622
+ if (coreReaderReportsProgress || (!onstart && !onprogress && !onend)) {
9623
+ return readable;
9624
+ } else {
9625
+ return toCompatibleReadable(readable).pipeThrough(new ProgressWatcherStream({ onstart, onprogress, onend, size: reader.size }), { signal });
9626
+ }
9627
+ }
9628
+
9321
9629
  async function initReaders(entry, options) {
9322
9630
  const fileEntries = [];
9323
9631
  const pendingEntries = [entry];
@@ -9350,6 +9658,7 @@
9350
9658
  }
9351
9659
  if (reader.size !== UNDEFINED_VALUE) {
9352
9660
  child.uncompressedSize = reader.size;
9661
+ child.undeterminedSize = false;
9353
9662
  }
9354
9663
  }));
9355
9664
  return readers;
@@ -9399,6 +9708,90 @@
9399
9708
  return error;
9400
9709
  }
9401
9710
 
9711
+ function getChildEntryOptions(child, selectedEntry, options) {
9712
+ const name = options.relativePath ? child.getRelativeName(selectedEntry) : child.getFullname();
9713
+ const childOptions = child.options || {};
9714
+ let zipEntryMetadata = {};
9715
+ let passThroughOptions = {};
9716
+ if (child.data instanceof Entry) {
9717
+ const {
9718
+ externalFileAttributes,
9719
+ versionMadeBy,
9720
+ comment,
9721
+ lastModDate,
9722
+ creationDate,
9723
+ lastAccessDate,
9724
+ uncompressedSize,
9725
+ encrypted,
9726
+ zipCrypto,
9727
+ crc32,
9728
+ compressionMethod,
9729
+ extraFieldAES,
9730
+ internalFileAttributes,
9731
+ extraField,
9732
+ uid,
9733
+ gid
9734
+ } = child.data;
9735
+ zipEntryMetadata = {
9736
+ externalFileAttributes,
9737
+ versionMadeBy,
9738
+ comment,
9739
+ lastModDate,
9740
+ creationDate,
9741
+ lastAccessDate,
9742
+ internalFileAttributes
9743
+ };
9744
+ const userExtraField = getUserExtraField(extraField);
9745
+ if (userExtraField) {
9746
+ zipEntryMetadata.extraField = userExtraField;
9747
+ }
9748
+ if (uid !== UNDEFINED_VALUE || gid !== UNDEFINED_VALUE) {
9749
+ Object.assign(zipEntryMetadata, {
9750
+ uid,
9751
+ gid,
9752
+ unixExtraFieldType: INFOZIP_EXTRA_FIELD_TYPE
9753
+ });
9754
+ }
9755
+ if (isPassThrough(child, options)) {
9756
+ let level, encryptionStrength;
9757
+ if (compressionMethod === 0) {
9758
+ level = 0;
9759
+ }
9760
+ if (extraFieldAES) {
9761
+ encryptionStrength = extraFieldAES.strength;
9762
+ }
9763
+ passThroughOptions = {
9764
+ passThrough: true,
9765
+ encrypted,
9766
+ zipCrypto,
9767
+ crc32,
9768
+ uncompressedSize,
9769
+ level,
9770
+ encryptionStrength,
9771
+ compressionMethod
9772
+ };
9773
+ }
9774
+ }
9775
+ const entryOptions = Object.assign({}, zipEntryMetadata, options, passThroughOptions, childOptions, { directory: child.directory });
9776
+ if (!child.directory && entryOptions.passThrough && entryOptions.uncompressedSize === UNDEFINED_VALUE) {
9777
+ throw new Error(ERR_INVALID_PASS_THROUGH);
9778
+ }
9779
+ return { name, entryOptions };
9780
+ }
9781
+
9782
+ function getDeterminedSize(child, passThrough) {
9783
+ const { reader } = child;
9784
+ if (reader && reader.size !== UNDEFINED_VALUE) {
9785
+ return reader.size;
9786
+ }
9787
+ return child.undeterminedSize ? UNDEFINED_VALUE : getExtractedSize(child, passThrough);
9788
+ }
9789
+
9790
+ function isPassThrough(child, options) {
9791
+ const { readerOptions } = options;
9792
+ return Boolean(!child.directory && (child.passThrough || (readerOptions && readerOptions.passThrough)));
9793
+ }
9794
+
9402
9795
  function getUserExtraField(extraField) {
9403
9796
  if (extraField) {
9404
9797
  const userExtraField = new Map();
@@ -9414,8 +9807,14 @@
9414
9807
  }
9415
9808
 
9416
9809
  async function exportZip(zipWriter, entry, totalSize, options, readers) {
9810
+ const { onstart, onprogress, onend, onentryprogress } = options;
9417
9811
  const selectedEntry = entry;
9418
- const entryOffsets = new Map();
9812
+ const totalEntries = getTotalSize(entry.children, () => 1);
9813
+ let writtenSize = 0;
9814
+ let writtenEntries = 0;
9815
+ if (onstart) {
9816
+ await callHandler(onstart, totalSize);
9817
+ }
9419
9818
  if (options.bufferedWrite) {
9420
9819
  await processChildren(entry);
9421
9820
  } else {
@@ -9423,6 +9822,9 @@
9423
9822
  await addChild(child);
9424
9823
  }
9425
9824
  }
9825
+ if (onend) {
9826
+ await callHandler(onend, writtenSize);
9827
+ }
9426
9828
 
9427
9829
  async function processChildren(entry) {
9428
9830
  const results = await Promise.allSettled(entry.children.map(async child => {
@@ -9436,81 +9838,23 @@
9436
9838
  }
9437
9839
 
9438
9840
  async function addChild(child) {
9439
- const name = options.relativePath ? child.getRelativeName(selectedEntry) : child.getFullname();
9440
- const childOptions = child.options || {};
9441
- let zipEntryOptions = {};
9442
- if (child.data instanceof Entry) {
9443
- const {
9444
- externalFileAttributes,
9445
- versionMadeBy,
9446
- comment,
9447
- lastModDate,
9448
- creationDate,
9449
- lastAccessDate,
9450
- uncompressedSize,
9451
- encrypted,
9452
- zipCrypto,
9453
- crc32,
9454
- compressionMethod,
9455
- extraFieldAES,
9456
- internalFileAttributes,
9457
- extraField,
9458
- uid,
9459
- gid
9460
- } = child.data;
9461
- zipEntryOptions = {
9462
- externalFileAttributes,
9463
- versionMadeBy,
9464
- comment,
9465
- lastModDate,
9466
- creationDate,
9467
- lastAccessDate,
9468
- internalFileAttributes
9469
- };
9470
- const userExtraField = getUserExtraField(extraField);
9471
- if (userExtraField) {
9472
- zipEntryOptions.extraField = userExtraField;
9473
- }
9474
- if (uid !== UNDEFINED_VALUE || gid !== UNDEFINED_VALUE) {
9475
- Object.assign(zipEntryOptions, {
9476
- uid,
9477
- gid,
9478
- unixExtraFieldType: options.unixExtraFieldType || INFOZIP_EXTRA_FIELD_TYPE
9479
- });
9480
- }
9481
- if (child.passThrough) {
9482
- let level, encryptionStrength;
9483
- if (compressionMethod === 0) {
9484
- level = 0;
9485
- }
9486
- if (extraFieldAES) {
9487
- encryptionStrength = extraFieldAES.strength;
9488
- }
9489
- zipEntryOptions = Object.assign(zipEntryOptions, {
9490
- passThrough: true,
9491
- encrypted,
9492
- zipCrypto,
9493
- crc32,
9494
- uncompressedSize,
9495
- level,
9496
- encryptionStrength,
9497
- compressionMethod
9498
- });
9499
- }
9500
- }
9501
- await zipWriter.add(name, readers.get(child), Object.assign({}, options, zipEntryOptions, childOptions, {
9502
- directory: child.directory,
9841
+ const { name, entryOptions } = getChildEntryOptions(child, selectedEntry, options);
9842
+ let entryWrittenSize = 0;
9843
+ const entryMetadata = await zipWriter.add(name, readers.get(child), Object.assign(entryOptions, {
9844
+ onstart: UNDEFINED_VALUE,
9845
+ onend: UNDEFINED_VALUE,
9503
9846
  onprogress: async indexProgress => {
9504
- if (options.onprogress) {
9505
- entryOffsets.set(name, indexProgress);
9506
- try {
9507
- await options.onprogress(Array.from(entryOffsets.values()).reduce((previousValue, currentValue) => previousValue + currentValue), totalSize);
9508
- } catch {
9509
- // ignored
9510
- }
9847
+ writtenSize += indexProgress - entryWrittenSize;
9848
+ entryWrittenSize = indexProgress;
9849
+ if (onprogress) {
9850
+ await callHandler(onprogress, writtenSize, totalSize);
9511
9851
  }
9512
9852
  }
9513
9853
  }));
9854
+ writtenEntries++;
9855
+ if (onentryprogress) {
9856
+ await callHandler(onentryprogress, writtenEntries, totalEntries, entryMetadata);
9857
+ }
9514
9858
  }
9515
9859
  }
9516
9860
 
@@ -9538,7 +9882,7 @@
9538
9882
  })
9539
9883
  );
9540
9884
  } else if (handle.kind == "directory") {
9541
- const directoryEntry = parentEntry.addDirectory(handle.name);
9885
+ const directoryEntry = parentEntry.addDirectory(handle.name, options);
9542
9886
  addedEntries.push(directoryEntry);
9543
9887
  for await (const childHandle of handle.values()) {
9544
9888
  await addFile(directoryEntry, childHandle, addedEntries, entryName);
@@ -9560,15 +9904,29 @@
9560
9904
  }
9561
9905
 
9562
9906
  async function exportFileSystemHandle(zipEntry, directoryHandle, options) {
9563
- const totalSize = getTotalSize([zipEntry], "uncompressedSize");
9564
- const writtenSizes = new Map();
9907
+ const { onstart, onprogress, onend } = options;
9565
9908
  const abortController = new AbortController();
9566
9909
  const { signal } = abortController;
9567
9910
  const releaseSignal = forwardAbort(options.signal, abortController);
9911
+ const getDataOptions = Object.assign({}, options, options.readerOptions, {
9912
+ signal,
9913
+ onstart: UNDEFINED_VALUE,
9914
+ onprogress: UNDEFINED_VALUE,
9915
+ onend: UNDEFINED_VALUE,
9916
+ preventClose: false
9917
+ });
9918
+ const totalSize = getTotalSize([zipEntry], entry => getExtractedSize(entry, getDataOptions.passThrough));
9568
9919
  const exportedEntryNames = [];
9569
9920
  let exportAborted = false;
9921
+ let writtenSize = 0;
9570
9922
  try {
9923
+ if (onstart) {
9924
+ await callHandler(onstart, totalSize);
9925
+ }
9571
9926
  await exportChildren(zipEntry, directoryHandle);
9927
+ if (onend) {
9928
+ await callHandler(onend, writtenSize);
9929
+ }
9572
9930
  } catch (error) {
9573
9931
  try {
9574
9932
  error.exportedEntryNames = exportedEntryNames;
@@ -9581,6 +9939,25 @@
9581
9939
  }
9582
9940
  return directoryHandle;
9583
9941
 
9942
+ function createProgressWritable(writable) {
9943
+ const writer = writable.getWriter();
9944
+ return new WritableStream({
9945
+ async write(chunk) {
9946
+ await writer.write(chunk);
9947
+ writtenSize += chunk.length;
9948
+ if (onprogress) {
9949
+ await callHandler(onprogress, writtenSize, totalSize);
9950
+ }
9951
+ },
9952
+ close() {
9953
+ return writer.close();
9954
+ },
9955
+ abort(reason) {
9956
+ return writer.abort(reason);
9957
+ }
9958
+ });
9959
+ }
9960
+
9584
9961
  async function exportChildren(entry, parentHandle) {
9585
9962
  if (options.concurrent) {
9586
9963
  const results = await Promise.allSettled(entry.children.map(child => exportChild(child, parentHandle)));
@@ -9612,19 +9989,7 @@
9612
9989
  const fileHandle = await parentHandle.getFileHandle(child.name, { create: true });
9613
9990
  const writable = await fileHandle.createWritable();
9614
9991
  try {
9615
- await child.getData({ writable }, Object.assign({}, options, {
9616
- signal,
9617
- onprogress: async progress => {
9618
- if (options.onprogress) {
9619
- writtenSizes.set(child.id, progress);
9620
- try {
9621
- await options.onprogress(Array.from(writtenSizes.values()).reduce((previousValue, currentValue) => previousValue + currentValue, 0), totalSize);
9622
- } catch {
9623
- // ignored
9624
- }
9625
- }
9626
- }
9627
- }));
9992
+ await child.getData({ writable: createProgressWritable(writable) }, getDataOptions);
9628
9993
  } catch (error) {
9629
9994
  throw exportAborted ? new Error(ERR_ABORT_EXPORT) : error;
9630
9995
  }
@@ -9853,6 +10218,7 @@
9853
10218
  exports.ERR_INVALID_CODEC_DEFINITION = ERR_INVALID_CODEC_DEFINITION;
9854
10219
  exports.ERR_INVALID_CODEC_MODULE = ERR_INVALID_CODEC_MODULE;
9855
10220
  exports.ERR_INVALID_COMMENT = ERR_INVALID_COMMENT;
10221
+ exports.ERR_INVALID_COMMENT_TYPE = ERR_INVALID_COMMENT_TYPE;
9856
10222
  exports.ERR_INVALID_COMPRESSED_DATA = ERR_INVALID_COMPRESSED_DATA;
9857
10223
  exports.ERR_INVALID_CRC32 = ERR_INVALID_CRC32;
9858
10224
  exports.ERR_INVALID_ENCRYPTION_STRENGTH = ERR_INVALID_ENCRYPTION_STRENGTH;
@@ -9868,6 +10234,7 @@
9868
10234
  exports.ERR_INVALID_MSDOS_DATA = ERR_INVALID_MSDOS_DATA;
9869
10235
  exports.ERR_INVALID_PASSWORD = ERR_INVALID_PASSWORD;
9870
10236
  exports.ERR_INVALID_PASSWORD_TYPE = ERR_INVALID_PASSWORD_TYPE;
10237
+ exports.ERR_INVALID_PASS_THROUGH = ERR_INVALID_PASS_THROUGH;
9871
10238
  exports.ERR_INVALID_SIGNATURE = ERR_INVALID_SIGNATURE;
9872
10239
  exports.ERR_INVALID_SIGNATURE_DATA = ERR_INVALID_SIGNATURE_DATA;
9873
10240
  exports.ERR_INVALID_STRICTNESS = ERR_INVALID_STRICTNESS;
@@ -9885,11 +10252,13 @@
9885
10252
  exports.ERR_SPLIT_ZIP_FILE = ERR_SPLIT_ZIP_FILE;
9886
10253
  exports.ERR_UNDEFINED_READER = ERR_UNDEFINED_READER;
9887
10254
  exports.ERR_UNDEFINED_UNCOMPRESSED_SIZE = ERR_UNDEFINED_UNCOMPRESSED_SIZE;
10255
+ exports.ERR_UNDETERMINED_SIZE = ERR_UNDETERMINED_SIZE;
9888
10256
  exports.ERR_UNSAFE_FILENAME = ERR_UNSAFE_FILENAME;
9889
10257
  exports.ERR_UNSUPPORTED_COMPRESSION = ERR_UNSUPPORTED_COMPRESSION$1;
9890
10258
  exports.ERR_UNSUPPORTED_CONTEXT = ERR_UNSUPPORTED_CONTEXT;
9891
10259
  exports.ERR_UNSUPPORTED_CRYPTO_API = ERR_UNSUPPORTED_CRYPTO_API;
9892
10260
  exports.ERR_UNSUPPORTED_ENCRYPTION = ERR_UNSUPPORTED_ENCRYPTION;
10261
+ exports.ERR_UNSUPPORTED_ENCRYPTION_PASS_THROUGH = ERR_UNSUPPORTED_ENCRYPTION_PASS_THROUGH;
9893
10262
  exports.ERR_UNSUPPORTED_ENCRYPTION_USDZ = ERR_UNSUPPORTED_ENCRYPTION_USDZ;
9894
10263
  exports.ERR_UNSUPPORTED_FORMAT = ERR_UNSUPPORTED_FORMAT;
9895
10264
  exports.ERR_WORKER_STARTUP_TIMEOUT = ERR_WORKER_STARTUP_TIMEOUT;