@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
@@ -89,6 +89,8 @@
89
89
  const FILE_ATTR_MSDOS_ARCHIVE_MASK = 0x20;
90
90
  const FILE_ATTR_UNIX_TYPE_MASK = 0o170000;
91
91
  const FILE_ATTR_UNIX_TYPE_DIR = 0o040000;
92
+ const FILE_ATTR_UNIX_TYPE_SYMLINK = 0o120000;
93
+ const FILE_ATTR_UNIX_TYPE_FILE = 0o100000;
92
94
  const FILE_ATTR_UNIX_EXECUTABLE_MASK = 0o111;
93
95
  const FILE_ATTR_UNIX_DEFAULT_MASK = 0o644;
94
96
  const FILE_ATTR_UNIX_SETUID_MASK = 0o4000;
@@ -99,6 +101,9 @@
99
101
  const VERSION_ZIP64 = 0x2D;
100
102
  const VERSION_AES = 0x33;
101
103
 
104
+ const VERSION_MADE_BY_MSDOS = 0x0014;
105
+ const VERSION_MADE_BY_UNIX = 0x0300;
106
+
102
107
  const DIRECTORY_SIGNATURE = "/";
103
108
 
104
109
  const HEADER_SIZE = 30;
@@ -257,8 +262,6 @@
257
262
  */
258
263
 
259
264
 
260
- const HTTP_HEADER_CONTENT_TYPE = "Content-Type";
261
-
262
265
  function toCompatibleReadable(readable) {
263
266
  if (readable instanceof ReadableStream) {
264
267
  return readable;
@@ -281,12 +284,9 @@
281
284
 
282
285
  function streamToBlob(readable, contentType) {
283
286
  readable = toCompatibleReadable(readable);
287
+ const blobOptions = contentType ? { type: contentType } : {};
284
288
  if (responseSupportsGlobalReadable()) {
285
- const options = {};
286
- if (contentType) {
287
- options.headers = [[HTTP_HEADER_CONTENT_TYPE, contentType]];
288
- }
289
- return new Response(readable, options).blob();
289
+ return new Response(readable).blob().then(blob => contentType ? new Blob([blob], blobOptions) : blob);
290
290
  }
291
291
  const chunks = [];
292
292
  return readable
@@ -295,7 +295,7 @@
295
295
  chunks.push(chunk);
296
296
  }
297
297
  }))
298
- .then(() => new Blob(chunks, contentType ? { type: contentType } : {}));
298
+ .then(() => new Blob(chunks, blobOptions));
299
299
  }
300
300
 
301
301
  function responseSupportsGlobalReadable() {
@@ -396,8 +396,10 @@
396
396
  async pull(controller) {
397
397
  const dataSize = size === UNDEFINED_VALUE ? chunkSize : Math.min(chunkSize, size - chunkOffset);
398
398
  const data = await readUint8Array(reader, offset + chunkOffset, dataSize);
399
- controller.enqueue(data);
400
- if ((chunkOffset + chunkSize > size) || (size === UNDEFINED_VALUE && !data.length && dataSize)) {
399
+ if (data.length) {
400
+ controller.enqueue(data);
401
+ }
402
+ if ((chunkOffset + chunkSize >= size) || (size === UNDEFINED_VALUE && !data.length && dataSize)) {
401
403
  controller.close();
402
404
  } else {
403
405
  chunkOffset += chunkSize;
@@ -475,6 +477,7 @@
475
477
  constructor(contentType) {
476
478
  super();
477
479
  Object.assign(this, {
480
+ contentType,
478
481
  data: "data:" + (contentType || "") + ";base64,",
479
482
  pending: []
480
483
  });
@@ -576,6 +579,7 @@
576
579
  return transformStream.writable;
577
580
  }
578
581
  });
582
+ writer.contentType = contentType;
579
583
  writer.blob = streamToBlob(transformStream.readable, contentType);
580
584
  writer.blob.catch(() => { });
581
585
  }
@@ -592,6 +596,26 @@
592
596
  }
593
597
  }
594
598
 
599
+ function getTextSize(text) {
600
+ let size = 0;
601
+ for (let indexCharacter = 0; indexCharacter < text.length; indexCharacter++) {
602
+ const characterCode = text.charCodeAt(indexCharacter);
603
+ if (characterCode < 0x80) {
604
+ size += 1;
605
+ } else if (characterCode < 0x800) {
606
+ size += 2;
607
+ } else if (characterCode < 0xd800 || characterCode >= 0xe000) {
608
+ size += 3;
609
+ } else if (characterCode < 0xdc00 && (text.charCodeAt(indexCharacter + 1) & 0xfc00) == 0xdc00) {
610
+ size += 4;
611
+ indexCharacter++;
612
+ } else {
613
+ size += 3;
614
+ }
615
+ }
616
+ return size;
617
+ }
618
+
595
619
  class TextWriter extends BlobWriter {
596
620
 
597
621
  constructor(encoding) {
@@ -1069,9 +1093,8 @@
1069
1093
 
1070
1094
  async init() {
1071
1095
  const reader = this;
1072
- const { readers } = reader;
1073
1096
  reader.lastDiskNumber = 0;
1074
- await Promise.all(readers.map(diskReader => initStream(diskReader)));
1097
+ const readers = reader.readers = await Promise.all(reader.readers.map(initDiskReader));
1075
1098
  reader.diskOffsets = readers.map(diskReader => {
1076
1099
  const diskOffset = reader.size;
1077
1100
  reader.size += diskReader.size;
@@ -1248,6 +1271,10 @@
1248
1271
  }
1249
1272
  }
1250
1273
 
1274
+ function ownsWritable(writer) {
1275
+ return Boolean(writer && writer.getData);
1276
+ }
1277
+
1251
1278
  function isHttpFamily(url) {
1252
1279
  const { baseURI } = getConfiguration();
1253
1280
  const { protocol } = new URL(url, baseURI);
@@ -1262,6 +1289,16 @@
1262
1289
  }
1263
1290
  }
1264
1291
 
1292
+ async function initDiskReader(diskReader) {
1293
+ diskReader = new GenericReader(diskReader);
1294
+ await initStream(diskReader);
1295
+ if (diskReader.size === UNDEFINED_VALUE || !diskReader.readUint8Array) {
1296
+ diskReader = new BlobReader(await streamToBlob(diskReader.readable));
1297
+ await initStream(diskReader);
1298
+ }
1299
+ return diskReader;
1300
+ }
1301
+
1265
1302
  function readUint8Array(reader, offset, size) {
1266
1303
  return reader.readUint8Array(offset, size);
1267
1304
  }
@@ -3783,6 +3820,8 @@
3783
3820
  const PROPERTY_NAME_RAW_CREATION_DATE = "rawCreationDate";
3784
3821
  const PROPERTY_NAME_INTERNAL_FILE_ATTRIBUTES = "internalFileAttributes";
3785
3822
  const PROPERTY_NAME_EXTERNAL_FILE_ATTRIBUTES = "externalFileAttributes";
3823
+ const PROPERTY_NAME_DEPRECATED_INTERNAL_FILE_ATTRIBUTES = "internalFileAttribute";
3824
+ const PROPERTY_NAME_DEPRECATED_EXTERNAL_FILE_ATTRIBUTES = "externalFileAttribute";
3786
3825
  const PROPERTY_NAME_MSDOS_ATTRIBUTES_RAW = "msdosAttributesRaw";
3787
3826
  const PROPERTY_NAME_MSDOS_ATTRIBUTES = "msdosAttributes";
3788
3827
  const PROPERTY_NAME_MS_DOS_COMPATIBLE = "msDosCompatible";
@@ -3793,6 +3832,7 @@
3793
3832
  const PROPERTY_NAME_ZIPCRYPTO = "zipCrypto";
3794
3833
  const PROPERTY_NAME_DIRECTORY = "directory";
3795
3834
  const PROPERTY_NAME_EXECUTABLE = "executable";
3835
+ const PROPERTY_NAME_SYMLINK = "symlink";
3796
3836
  const PROPERTY_NAME_COMPRESSION_METHOD = "compressionMethod";
3797
3837
  const PROPERTY_NAME_SIGNATURE = "signature";
3798
3838
  const PROPERTY_NAME_CRC32 = "crc32";
@@ -3808,6 +3848,10 @@
3808
3848
  const PROPERTY_NAME_SETGID = "setgid";
3809
3849
  const PROPERTY_NAME_STICKY = "sticky";
3810
3850
  const PROPERTY_NAME_BITFLAG = "bitFlag";
3851
+ const PROPERTY_NAME_RAW_BITFLAG = "rawBitFlag";
3852
+ const PROPERTY_NAME_FILENAME_LENGTH = "filenameLength";
3853
+ const PROPERTY_NAME_EXTRA_FIELD_LENGTH = "extraFieldLength";
3854
+ const PROPERTY_NAME_UNIX_EXTERNAL_UPPER = "unixExternalUpper";
3811
3855
  const PROPERTY_NAME_FILENAME_UTF8 = "filenameUTF8";
3812
3856
  const PROPERTY_NAME_COMMENT_UTF8 = "commentUTF8";
3813
3857
  const PROPERTY_NAME_RAW_EXTRA_FIELD = "rawExtraField";
@@ -3836,6 +3880,8 @@
3836
3880
  PROPERTY_NAME_DISK_NUMBER_START,
3837
3881
  PROPERTY_NAME_INTERNAL_FILE_ATTRIBUTES,
3838
3882
  PROPERTY_NAME_EXTERNAL_FILE_ATTRIBUTES,
3883
+ PROPERTY_NAME_DEPRECATED_INTERNAL_FILE_ATTRIBUTES,
3884
+ PROPERTY_NAME_DEPRECATED_EXTERNAL_FILE_ATTRIBUTES,
3839
3885
  PROPERTY_NAME_MSDOS_ATTRIBUTES_RAW,
3840
3886
  PROPERTY_NAME_MSDOS_ATTRIBUTES,
3841
3887
  PROPERTY_NAME_MS_DOS_COMPATIBLE,
@@ -3846,6 +3892,7 @@
3846
3892
  PROPERTY_NAME_ZIPCRYPTO,
3847
3893
  PROPERTY_NAME_DIRECTORY,
3848
3894
  PROPERTY_NAME_EXECUTABLE,
3895
+ PROPERTY_NAME_SYMLINK,
3849
3896
  PROPERTY_NAME_COMPRESSION_METHOD,
3850
3897
  PROPERTY_NAME_SIGNATURE,
3851
3898
  PROPERTY_NAME_CRC32,
@@ -3857,10 +3904,14 @@
3857
3904
  PROPERTY_NAME_UID,
3858
3905
  PROPERTY_NAME_GID,
3859
3906
  PROPERTY_NAME_UNIX_MODE,
3907
+ PROPERTY_NAME_UNIX_EXTERNAL_UPPER,
3860
3908
  PROPERTY_NAME_SETUID,
3861
3909
  PROPERTY_NAME_SETGID,
3862
3910
  PROPERTY_NAME_STICKY,
3863
3911
  PROPERTY_NAME_BITFLAG,
3912
+ PROPERTY_NAME_RAW_BITFLAG,
3913
+ PROPERTY_NAME_FILENAME_LENGTH,
3914
+ PROPERTY_NAME_EXTRA_FIELD_LENGTH,
3864
3915
  PROPERTY_NAME_FILENAME_UTF8,
3865
3916
  PROPERTY_NAME_COMMENT_UTF8,
3866
3917
  PROPERTY_NAME_RAW_EXTRA_FIELD,
@@ -3922,6 +3973,7 @@
3922
3973
  const OPTION_CHECK_OVERLAPPING_ENTRY_ONLY = "checkOverlappingEntryOnly";
3923
3974
  const OPTION_CHECK_OVERLAPPING_ENTRY = "checkOverlappingEntry";
3924
3975
  const OPTION_CHECK_AMBIGUITY = "checkAmbiguity";
3976
+ const OPTION_CHECK_LOCAL_DIRECTORY = "checkLocalDirectory";
3925
3977
  const OPTION_CHECK_SIGNATURE = "checkSignature";
3926
3978
  const OPTION_CHECK_CRC32 = "checkCrc32";
3927
3979
  const OPTION_CHECK_AUTHENTICATION_CODE = "checkAuthenticationCode";
@@ -4053,7 +4105,7 @@
4053
4105
  if (reader.size < END_OF_CENTRAL_DIR_LENGTH) {
4054
4106
  throw new Error(ERR_BAD_FORMAT);
4055
4107
  }
4056
- const strictness = getStrictness(getOptionValue$1(zipReader, options, OPTION_STRICTNESS), getOptionValue$1(zipReader, options, OPTION_CHECK_AMBIGUITY));
4108
+ const strictness = getStrictness(options, zipReader.options);
4057
4109
  const checkAmbiguity = strictness == STRICTNESS_STRICT;
4058
4110
  const rejectAmbiguousEndOfDirectory = strictness != STRICTNESS_TOLERANT;
4059
4111
  const maxAppendedDataSize = getMaxAppendedDataSize(getOptionValue$1(zipReader, options, OPTION_MAX_APPENDED_DATA_SIZE), strictness);
@@ -4275,6 +4327,7 @@
4275
4327
  index: indexFile,
4276
4328
  versionMadeBy,
4277
4329
  msDosCompatible,
4330
+ zip64: false,
4278
4331
  compressedSize: 0,
4279
4332
  uncompressedSize: 0,
4280
4333
  commentLength,
@@ -4308,15 +4361,18 @@
4308
4361
  const setuid = Boolean(fileEntry.unixMode & FILE_ATTR_UNIX_SETUID_MASK);
4309
4362
  const setgid = Boolean(fileEntry.unixMode & FILE_ATTR_UNIX_SETGID_MASK);
4310
4363
  const sticky = Boolean(fileEntry.unixMode & FILE_ATTR_UNIX_STICKY_MASK);
4311
- const executable = (fileEntry.unixMode !== UNDEFINED_VALUE)
4364
+ const unixType = fileEntry.unixMode === UNDEFINED_VALUE ? unixExternalUpper : fileEntry.unixMode;
4365
+ const symlink = (unixType & FILE_ATTR_UNIX_TYPE_MASK) == FILE_ATTR_UNIX_TYPE_SYMLINK;
4366
+ const executable = !symlink && ((fileEntry.unixMode !== UNDEFINED_VALUE)
4312
4367
  ? ((fileEntry.unixMode & FILE_ATTR_UNIX_EXECUTABLE_MASK) != 0)
4313
- : (unixCompatible && ((unixExternalUpper & FILE_ATTR_UNIX_EXECUTABLE_MASK) != 0));
4368
+ : (unixCompatible && ((unixExternalUpper & FILE_ATTR_UNIX_EXECUTABLE_MASK) != 0)));
4314
4369
  const modeIsDir = fileEntry.unixMode !== UNDEFINED_VALUE && ((fileEntry.unixMode & FILE_ATTR_UNIX_TYPE_MASK) == FILE_ATTR_UNIX_TYPE_DIR);
4315
4370
  const upperIsDir = ((unixExternalUpper & FILE_ATTR_UNIX_TYPE_MASK) == FILE_ATTR_UNIX_TYPE_DIR);
4316
4371
  Object.assign(fileEntry, {
4317
4372
  setuid,
4318
4373
  setgid,
4319
4374
  sticky,
4375
+ symlink,
4320
4376
  unixExternalUpper,
4321
4377
  internalFileAttribute: fileEntry.internalFileAttributes,
4322
4378
  externalFileAttribute: fileEntry.externalFileAttributes,
@@ -4382,6 +4438,10 @@
4382
4438
  }
4383
4439
 
4384
4440
  async close() {
4441
+ const { reader } = this;
4442
+ if (!reader.readUint8Array && reader.readable && !reader.readable.locked) {
4443
+ await reader.readable.cancel();
4444
+ }
4385
4445
  }
4386
4446
  }
4387
4447
 
@@ -4438,9 +4498,12 @@
4438
4498
  extraFieldLength,
4439
4499
  filenameLength
4440
4500
  } = localDirectory;
4441
- const checkAmbiguity = getStrictness(getOptionValue$1(zipEntry, options, OPTION_STRICTNESS), getOptionValue$1(zipEntry, options, OPTION_CHECK_AMBIGUITY)) == STRICTNESS_STRICT;
4501
+ const checkLocalDirectoryOption = getOptionValue$1(zipEntry, options, OPTION_CHECK_LOCAL_DIRECTORY);
4502
+ const entryStrictness = getStrictness(options, zipEntry.options);
4503
+ const checkLocalDirectory = getCheckLocalDirectory(checkLocalDirectoryOption, entryStrictness);
4504
+ const checkLocalFilename = getCheckLocalFilename(checkLocalDirectoryOption, entryStrictness);
4442
4505
  let rawLocalFilename = EMPTY_UINT8_ARRAY;
4443
- if (checkAmbiguity && (filenameLength || extraFieldLength)) {
4506
+ if (checkLocalFilename && (filenameLength || extraFieldLength)) {
4444
4507
  const trailingDataArray = await readUint8Array(reader, localHeaderOffset + HEADER_SIZE, filenameLength + extraFieldLength);
4445
4508
  rawLocalFilename = trailingDataArray.subarray(0, filenameLength);
4446
4509
  localDirectory.rawExtraField = trailingDataArray.subarray(filenameLength);
@@ -4449,17 +4512,26 @@
4449
4512
  await readUint8Array(reader, localHeaderOffset + HEADER_SIZE + filenameLength, extraFieldLength) :
4450
4513
  EMPTY_UINT8_ARRAY;
4451
4514
  }
4515
+ if (checkLocalFilename) {
4516
+ localDirectory.rawFilename = rawLocalFilename;
4517
+ }
4452
4518
  readCommonFooter(zipEntry, localDirectory, dataView, 4, true);
4453
- if (checkAmbiguity) {
4454
- checkLocalDirectory(zipEntry, localDirectory, rawLocalFilename);
4519
+ if (checkLocalDirectory) {
4520
+ validateLocalDirectory(zipEntry, localDirectory, rawLocalFilename, checkLocalFilename);
4455
4521
  }
4456
- const { lastAccessDate, creationDate } = localDirectory;
4522
+ const { lastAccessDate, creationDate, uid, gid } = localDirectory;
4457
4523
  if (lastAccessDate) {
4458
4524
  fileEntry.lastAccessDate = lastAccessDate;
4459
4525
  }
4460
4526
  if (creationDate) {
4461
4527
  fileEntry.creationDate = creationDate;
4462
4528
  }
4529
+ if (uid !== UNDEFINED_VALUE && fileEntry.uid === UNDEFINED_VALUE) {
4530
+ fileEntry.uid = uid;
4531
+ }
4532
+ if (gid !== UNDEFINED_VALUE && fileEntry.gid === UNDEFINED_VALUE) {
4533
+ fileEntry.gid = gid;
4534
+ }
4463
4535
  const encrypted = zipEntry.encrypted && localDirectory.encrypted && !passThrough;
4464
4536
  const zipCrypto = encrypted && !extraFieldAES;
4465
4537
  if (!passThrough) {
@@ -4566,7 +4638,7 @@
4566
4638
  throw error;
4567
4639
  }
4568
4640
  } finally {
4569
- const preventClose = getOptionValue$1(zipEntry, options, OPTION_PREVENT_CLOSE);
4641
+ const preventClose = !ownsWritable(writer) && getOptionValue$1(zipEntry, options, OPTION_PREVENT_CLOSE);
4570
4642
  if (!preventClose && writable && !writable.locked) {
4571
4643
  const writableWriter = writable.getWriter();
4572
4644
  if (abortError) {
@@ -4695,10 +4767,12 @@
4695
4767
  directory.extraFieldNTFS = extraFieldNTFS;
4696
4768
  }
4697
4769
  const extraFieldUnix = extraField.get(EXTRAFIELD_TYPE_UNIX);
4770
+ let unixIdsRead;
4698
4771
  if (extraFieldUnix) {
4699
- readExtraFieldUnix(extraFieldUnix, directory, false);
4772
+ unixIdsRead = readExtraFieldUnix(extraFieldUnix, directory, false);
4700
4773
  directory.extraFieldUnix = extraFieldUnix;
4701
- } else {
4774
+ }
4775
+ if (!unixIdsRead) {
4702
4776
  const extraFieldInfoZip = extraField.get(EXTRAFIELD_TYPE_INFOZIP);
4703
4777
  if (extraFieldInfoZip) {
4704
4778
  readExtraFieldUnix(extraFieldInfoZip, directory, true);
@@ -4801,7 +4875,7 @@
4801
4875
  const creationDate = getDateNTFS(rawCreationDate);
4802
4876
  const extraFieldData = { lastModDate, lastAccessDate, creationDate };
4803
4877
  Object.assign(extraFieldNTFS, extraFieldData);
4804
- Object.assign(directory, extraFieldData);
4878
+ Object.assign(directory, extraFieldData, { rawLastAccessDate, rawCreationDate });
4805
4879
  }
4806
4880
  }
4807
4881
 
@@ -4810,8 +4884,8 @@
4810
4884
  return;
4811
4885
  }
4812
4886
  const extraFieldView = getDataView(extraField.data);
4813
- const lastAccessDate = new Date(getUint32(extraFieldView, 0) * 1000);
4814
- const lastModDate = new Date(getUint32(extraFieldView, 4) * 1000);
4887
+ const lastAccessDate = new Date((getUint32(extraFieldView, 0) | 0) * 1000);
4888
+ const lastModDate = new Date((getUint32(extraFieldView, 4) | 0) * 1000);
4815
4889
  const extraFieldData = { lastAccessDate, lastModDate };
4816
4890
  if (extraField.data.length >= 12) {
4817
4891
  extraFieldData.uid = getUint16(extraFieldView, 8);
@@ -4845,6 +4919,7 @@
4845
4919
  if (gid !== UNDEFINED_VALUE) {
4846
4920
  directory.gid = gid;
4847
4921
  }
4922
+ return uid !== UNDEFINED_VALUE || gid !== UNDEFINED_VALUE;
4848
4923
  } catch {
4849
4924
  // ignored
4850
4925
  }
@@ -4917,26 +4992,25 @@
4917
4992
  }
4918
4993
  if (dataDescriptorLength) {
4919
4994
  const dataDescriptorArray = await readUint8Array(reader, dataOffset + compressedSize, dataDescriptorLength + DATA_DESCRIPTOR_RECORD_SIGNATURE_LENGTH);
4920
- const dataDescriptorSignature = dataDescriptorArray.length == dataDescriptorLength + DATA_DESCRIPTOR_RECORD_SIGNATURE_LENGTH &&
4921
- getUint32(getDataView(dataDescriptorArray), 0) == DATA_DESCRIPTOR_RECORD_SIGNATURE;
4922
- if (dataDescriptorSignature) {
4923
- const readCrc32 = getUint32(getDataView(dataDescriptorArray), 4);
4924
- let readCompressedSize;
4925
- let readUncompressedSize;
4926
- if (extraFieldZip64) {
4927
- readCompressedSize = getBigUint64(getDataView(dataDescriptorArray), 8);
4928
- readUncompressedSize = getBigUint64(getDataView(dataDescriptorArray), 16);
4929
- } else {
4930
- readCompressedSize = getUint32(getDataView(dataDescriptorArray), 8);
4931
- readUncompressedSize = getUint32(getDataView(dataDescriptorArray), 12);
4932
- }
4933
- const matchCrc32 = (fileEntry.encrypted && !fileEntry.zipCrypto) || readCrc32 == crc32;
4995
+ const dataDescriptorView = getDataView(dataDescriptorArray);
4996
+ let signature = dataDescriptorArray.length == dataDescriptorLength + DATA_DESCRIPTOR_RECORD_SIGNATURE_LENGTH &&
4997
+ getUint32(dataDescriptorView, 0) == DATA_DESCRIPTOR_RECORD_SIGNATURE;
4998
+ if (signature) {
4999
+ const signedDataDescriptor = readDataDescriptor(dataDescriptorView, DATA_DESCRIPTOR_RECORD_SIGNATURE_LENGTH, extraFieldZip64);
5000
+ const matchCrc32 = (fileEntry.encrypted && !fileEntry.zipCrypto) || signedDataDescriptor.crc32 == crc32;
4934
5001
  if (matchCrc32 &&
4935
- readCompressedSize == compressedSize &&
4936
- readUncompressedSize == uncompressedSize) {
5002
+ signedDataDescriptor.compressedSize == compressedSize &&
5003
+ signedDataDescriptor.uncompressedSize == uncompressedSize) {
4937
5004
  dataDescriptorLength += DATA_DESCRIPTOR_RECORD_SIGNATURE_LENGTH;
5005
+ } else {
5006
+ signature = false;
4938
5007
  }
4939
5008
  }
5009
+ if (dataDescriptorArray.length >= dataDescriptorLength) {
5010
+ const localDataDescriptor = readDataDescriptor(dataDescriptorView, signature ? DATA_DESCRIPTOR_RECORD_SIGNATURE_LENGTH : 0, extraFieldZip64);
5011
+ localDataDescriptor.signature = signature;
5012
+ fileEntry.localDirectory.dataDescriptor = localDataDescriptor;
5013
+ }
4940
5014
  }
4941
5015
  const range = {
4942
5016
  start: offset,
@@ -4953,6 +5027,20 @@
4953
5027
  readRanges.set(index, range);
4954
5028
  }
4955
5029
 
5030
+ function readDataDescriptor(dataDescriptorView, offset, extraFieldZip64) {
5031
+ const crc32 = getUint32(dataDescriptorView, offset);
5032
+ let compressedSize;
5033
+ let uncompressedSize;
5034
+ if (extraFieldZip64) {
5035
+ compressedSize = getBigUint64(dataDescriptorView, offset + 4);
5036
+ uncompressedSize = getBigUint64(dataDescriptorView, offset + 12);
5037
+ } else {
5038
+ compressedSize = getUint32(dataDescriptorView, offset + 4);
5039
+ uncompressedSize = getUint32(dataDescriptorView, offset + 8);
5040
+ }
5041
+ return { crc32, compressedSize, uncompressedSize };
5042
+ }
5043
+
4956
5044
  function getDiskOffset$1(reader, diskNumber) {
4957
5045
  return reader.getDiskOffset ? reader.getDiskOffset(diskNumber) : 0;
4958
5046
  }
@@ -4961,14 +5049,40 @@
4961
5049
  return value === STRICTNESS_STRICT || value === STRICTNESS_BALANCED || value === STRICTNESS_TOLERANT;
4962
5050
  }
4963
5051
 
4964
- function getStrictness(strictness, checkAmbiguity) {
4965
- if (strictness === UNDEFINED_VALUE) {
4966
- return checkAmbiguity ? STRICTNESS_STRICT : STRICTNESS_BALANCED;
5052
+ function getStrictness(options, inheritedOptions) {
5053
+ return resolveStrictness(options, resolveStrictness(inheritedOptions, STRICTNESS_BALANCED));
5054
+ }
5055
+
5056
+ function resolveStrictness(options, inheritedStrictness) {
5057
+ const strictness = options[OPTION_STRICTNESS];
5058
+ if (strictness !== UNDEFINED_VALUE) {
5059
+ if (!isStrictnessValue(strictness)) {
5060
+ throw new Error(ERR_INVALID_STRICTNESS);
5061
+ }
5062
+ return strictness;
5063
+ }
5064
+ const checkAmbiguity = options[OPTION_CHECK_AMBIGUITY];
5065
+ if (checkAmbiguity === UNDEFINED_VALUE) {
5066
+ return inheritedStrictness;
5067
+ }
5068
+ if (checkAmbiguity) {
5069
+ return STRICTNESS_STRICT;
5070
+ }
5071
+ return inheritedStrictness == STRICTNESS_TOLERANT ? STRICTNESS_TOLERANT : STRICTNESS_BALANCED;
5072
+ }
5073
+
5074
+ function getCheckLocalDirectory(checkLocalDirectory, strictness) {
5075
+ if (checkLocalDirectory === UNDEFINED_VALUE) {
5076
+ return strictness != STRICTNESS_TOLERANT;
4967
5077
  }
4968
- if (!isStrictnessValue(strictness)) {
4969
- throw new Error(ERR_INVALID_STRICTNESS);
5078
+ return Boolean(checkLocalDirectory);
5079
+ }
5080
+
5081
+ function getCheckLocalFilename(checkLocalFilename, strictness) {
5082
+ if (checkLocalFilename === UNDEFINED_VALUE) {
5083
+ return strictness == STRICTNESS_STRICT;
4970
5084
  }
4971
- return strictness;
5085
+ return Boolean(checkLocalFilename);
4972
5086
  }
4973
5087
 
4974
5088
  function getFilenameValidation(filenameValidation, strictness) {
@@ -5116,10 +5230,11 @@
5116
5230
  return UNDEFINED_VALUE;
5117
5231
  }
5118
5232
 
5119
- function checkLocalDirectory(zipEntry, localDirectory, rawLocalFilename) {
5233
+ function validateLocalDirectory(zipEntry, localDirectory, rawLocalFilename, checkLocalFilename) {
5120
5234
  const { rawFilename } = zipEntry;
5121
- if (rawLocalFilename.length != rawFilename.length ||
5122
- rawLocalFilename.some((byteValue, indexByte) => byteValue != rawFilename[indexByte])) {
5235
+ if (checkLocalFilename &&
5236
+ (rawLocalFilename.length != rawFilename.length ||
5237
+ rawLocalFilename.some((byteValue, indexByte) => byteValue != rawFilename[indexByte]))) {
5123
5238
  throwAmbiguousArchive("mismatched local file header (filename)");
5124
5239
  }
5125
5240
  if ((localDirectory.rawBitFlag & BITFLAG_AMBIGUITY_MASK) != (zipEntry.rawBitFlag & BITFLAG_AMBIGUITY_MASK)) {
@@ -5235,11 +5350,13 @@
5235
5350
 
5236
5351
  const ERR_DUPLICATED_NAME = "File already exists";
5237
5352
  const ERR_INVALID_COMMENT = "Zip file comment exceeds 64KB";
5353
+ const ERR_INVALID_COMMENT_TYPE = "Invalid zip file comment (must be a Uint8Array)";
5238
5354
  const ERR_INVALID_ENTRY_COMMENT = "File entry comment exceeds 64KB";
5239
5355
  const ERR_INVALID_ENTRY_NAME = "File entry name exceeds 64KB";
5240
5356
  const ERR_INVALID_VERSION = "Version exceeds 65535";
5241
5357
  const ERR_INVALID_ENCRYPTION_STRENGTH = "The strength must equal 1, 2, or 3";
5242
5358
  const ERR_UNSUPPORTED_ENCRYPTION_USDZ = "Encryption is not supported in USDZ files";
5359
+ const ERR_UNSUPPORTED_ENCRYPTION_PASS_THROUGH = "Encryption is not supported when the 'passThrough' option is set";
5243
5360
  const ERR_INVALID_EXTRAFIELD_TYPE = "Extra field type exceeds 65535";
5244
5361
  const ERR_INVALID_EXTRAFIELD_DATA = "Extra field data exceeds 64KB";
5245
5362
  const ERR_UNSUPPORTED_COMPRESSION = "Compression method not supported";
@@ -5249,6 +5366,7 @@
5249
5366
  const MAX_NTFS_TIME = BigInt("0x7fffffffffffffff");
5250
5367
  const ERR_UNSUPPORTED_FORMAT = "Zip64 is not supported (set the 'zip64' option to 'true')";
5251
5368
  const ERR_UNDEFINED_UNCOMPRESSED_SIZE = "Undefined uncompressed size";
5369
+ const ERR_UNDETERMINED_SIZE = "Undetermined size";
5252
5370
  const ERR_UNDEFINED_READER = "Undefined reader";
5253
5371
  const ERR_ZIP_NOT_EMPTY = "Zip file not empty";
5254
5372
  const ERR_INVALID_UID = "Invalid uid (must be integer 0..2^32-1)";
@@ -5301,6 +5419,10 @@
5301
5419
  }
5302
5420
  reader = new GenericReader(reader);
5303
5421
  await initStream(reader);
5422
+ if (reader.size === UNDEFINED_VALUE || !reader.readUint8Array) {
5423
+ reader = new BlobReader(await streamToBlob(reader.readable));
5424
+ await initStream(reader);
5425
+ }
5304
5426
  const { ZipReader } = await Promise.resolve().then(function () { return zipReader; });
5305
5427
  const zipReader$1 = new ZipReader(reader.readable);
5306
5428
  const entries = await zipReader$1.getEntries();
@@ -5449,6 +5571,9 @@
5449
5571
  const zipWriter = this;
5450
5572
  const { pendingAddFileCalls, writer } = this;
5451
5573
  const { writable } = writer;
5574
+ if (!(comment instanceof Uint8Array)) {
5575
+ throw new Error(ERR_INVALID_COMMENT_TYPE);
5576
+ }
5452
5577
  if (getLength(comment) > MAX_16_BITS) {
5453
5578
  throw new Error(ERR_INVALID_COMMENT);
5454
5579
  }
@@ -5456,7 +5581,7 @@
5456
5581
  await Promise.allSettled(Array.from(pendingAddFileCalls));
5457
5582
  }
5458
5583
  await closeFile(zipWriter, comment, options);
5459
- const preventClose = getOptionValue(zipWriter, options, OPTION_PREVENT_CLOSE);
5584
+ const preventClose = !ownsWritable(writer) && getOptionValue(zipWriter, options, OPTION_PREVENT_CLOSE);
5460
5585
  if (!preventClose) {
5461
5586
  await writable.getWriter().close();
5462
5587
  }
@@ -5483,8 +5608,6 @@
5483
5608
  const diskOffset = getDiskOffset(zipWriter.writer);
5484
5609
  const diskNumber = getDiskNumber(zipWriter.writer);
5485
5610
  options = Object.assign({}, options, attributesInfo.resolvedOptions, metadataInfo.resolvedOptions, sizesInfo.resolvedOptions, {
5486
- internalFileAttribute: metadataInfo.resolvedOptions.internalFileAttributes,
5487
- externalFileAttribute: attributesInfo.resolvedOptions.externalFileAttributes,
5488
5611
  signature: options[PROPERTY_NAME_SIGNATURE],
5489
5612
  crc32: options.crc32 === UNDEFINED_VALUE ? options[PROPERTY_NAME_SIGNATURE] : options.crc32,
5490
5613
  offset: zipWriter.offset - diskOffset,
@@ -5498,14 +5621,20 @@
5498
5621
  zipWriter.files.delete(name);
5499
5622
  throw error;
5500
5623
  }
5501
- Object.assign(fileEntry, { name, comment, extraField });
5624
+ Object.assign(fileEntry, {
5625
+ name,
5626
+ comment,
5627
+ extraField,
5628
+ [PROPERTY_NAME_DEPRECATED_INTERNAL_FILE_ATTRIBUTES]: fileEntry.internalFileAttributes,
5629
+ [PROPERTY_NAME_DEPRECATED_EXTERNAL_FILE_ATTRIBUTES]: fileEntry.externalFileAttributes
5630
+ });
5502
5631
  return new Entry(fileEntry);
5503
5632
  }
5504
5633
 
5505
5634
  function resolveAttributes(zipWriter, name, options) {
5506
5635
  name = name.trim();
5507
5636
  let msDosCompatible = getOptionValue(zipWriter, options, PROPERTY_NAME_MS_DOS_COMPATIBLE);
5508
- let versionMadeBy = getOptionValue(zipWriter, options, PROPERTY_NAME_VERSION_MADE_BY, msDosCompatible ? 20 : 768);
5637
+ let versionMadeBy = getOptionValue(zipWriter, options, PROPERTY_NAME_VERSION_MADE_BY, msDosCompatible ? VERSION_MADE_BY_MSDOS : VERSION_MADE_BY_UNIX);
5509
5638
  const executable = getOptionValue(zipWriter, options, PROPERTY_NAME_EXECUTABLE);
5510
5639
  const uid = getNumberOptionValue(zipWriter, options, PROPERTY_NAME_UID);
5511
5640
  const gid = getNumberOptionValue(zipWriter, options, PROPERTY_NAME_GID);
@@ -5539,7 +5668,7 @@
5539
5668
  const hasMsDosProvided = msdosAttributesRaw !== UNDEFINED_VALUE || msdosAttributes !== UNDEFINED_VALUE;
5540
5669
  if (hasUnixMetadata) {
5541
5670
  msDosCompatible = false;
5542
- versionMadeBy = (versionMadeBy & MAX_16_BITS) | (3 << 8);
5671
+ versionMadeBy = (versionMadeBy & MAX_8_BITS) | VERSION_MADE_BY_UNIX;
5543
5672
  } else if (hasMsDosProvided) {
5544
5673
  msDosCompatible = true;
5545
5674
  versionMadeBy = (versionMadeBy & MAX_8_BITS);
@@ -5553,7 +5682,7 @@
5553
5682
  if (versionMadeBy > MAX_16_BITS) {
5554
5683
  throw new Error(ERR_INVALID_VERSION);
5555
5684
  }
5556
- let externalFileAttributes = getOptionValue(zipWriter, options, PROPERTY_NAME_EXTERNAL_FILE_ATTRIBUTES);
5685
+ let externalFileAttributes = getAliasedOptionValue(zipWriter, options, PROPERTY_NAME_EXTERNAL_FILE_ATTRIBUTES, PROPERTY_NAME_DEPRECATED_EXTERNAL_FILE_ATTRIBUTES);
5557
5686
  const externalFileAttributesProvided = externalFileAttributes !== UNDEFINED_VALUE;
5558
5687
  if (!externalFileAttributesProvided) {
5559
5688
  externalFileAttributes = 0;
@@ -5579,11 +5708,10 @@
5579
5708
  externalFileAttributes = FILE_ATTR_UNIX_DEFAULT_MASK << 16;
5580
5709
  }
5581
5710
  }
5582
- let unixExternalUpper;
5583
5711
  if (!msDosCompatible) {
5584
5712
  const unixModeProvided = unixMode !== UNDEFINED_VALUE || Boolean(setuid || setgid || sticky);
5585
- unixExternalUpper = (externalFileAttributes >> 16) & MAX_16_BITS;
5586
- unixMode = unixMode === UNDEFINED_VALUE ? unixExternalUpper : (unixMode & MAX_16_BITS);
5713
+ const defaultUnixMode = (externalFileAttributes >> 16) & MAX_16_BITS;
5714
+ unixMode = unixMode === UNDEFINED_VALUE ? defaultUnixMode : (unixMode & MAX_16_BITS);
5587
5715
  if (setuid) {
5588
5716
  unixMode |= FILE_ATTR_UNIX_SETUID_MASK;
5589
5717
  } else {
@@ -5601,7 +5729,9 @@
5601
5729
  }
5602
5730
  if (!externalFileAttributesProvided || unixModeProvided) {
5603
5731
  if (directory) {
5604
- unixMode |= FILE_ATTR_UNIX_TYPE_DIR;
5732
+ unixMode = (unixMode & ~FILE_ATTR_UNIX_TYPE_MASK) | FILE_ATTR_UNIX_TYPE_DIR;
5733
+ } else if (!(unixMode & FILE_ATTR_UNIX_TYPE_MASK)) {
5734
+ unixMode |= FILE_ATTR_UNIX_TYPE_FILE;
5605
5735
  }
5606
5736
  externalFileAttributes = ((unixMode & MAX_16_BITS) << 16) | (externalFileAttributes & MAX_16_BITS);
5607
5737
  }
@@ -5610,17 +5740,20 @@
5610
5740
  if (hasMsDosProvided) {
5611
5741
  externalFileAttributes = (externalFileAttributes & MAX_32_BITS) | (msdosAttributesRaw & MAX_8_BITS);
5612
5742
  }
5743
+ const unixExternalUpper = (externalFileAttributes >> 16) & MAX_16_BITS;
5744
+ const symlink = unixMode !== UNDEFINED_VALUE && ((unixMode & FILE_ATTR_UNIX_TYPE_MASK) == FILE_ATTR_UNIX_TYPE_SYMLINK);
5613
5745
  return {
5614
5746
  name,
5615
5747
  resolvedOptions: {
5616
5748
  versionMadeBy,
5617
- msDosCompatible,
5749
+ msDosCompatible: Boolean(msDosCompatible),
5618
5750
  externalFileAttributes,
5619
5751
  unixExternalUpper,
5620
5752
  uid,
5621
5753
  gid,
5622
5754
  unixMode,
5623
5755
  unixExtraFieldType,
5756
+ symlink,
5624
5757
  setuid,
5625
5758
  setgid,
5626
5759
  sticky,
@@ -5654,15 +5787,12 @@
5654
5787
  const lastModDate = getOptionValue(zipWriter, options, PROPERTY_NAME_LAST_MODIFICATION_DATE, new Date());
5655
5788
  const lastAccessDate = getOptionValue(zipWriter, options, PROPERTY_NAME_LAST_ACCESS_DATE);
5656
5789
  const creationDate = getOptionValue(zipWriter, options, PROPERTY_NAME_CREATION_DATE);
5657
- const internalFileAttributes = getOptionValue(zipWriter, options, PROPERTY_NAME_INTERNAL_FILE_ATTRIBUTES, 0);
5790
+ const internalFileAttributes = getAliasedOptionValue(zipWriter, options, PROPERTY_NAME_INTERNAL_FILE_ATTRIBUTES, PROPERTY_NAME_DEPRECATED_INTERNAL_FILE_ATTRIBUTES, 0);
5658
5791
  const passThrough = getOptionValue(zipWriter, options, OPTION_PASS_THROUGH);
5659
- let password, rawPassword;
5660
- if (!passThrough) {
5661
- password = getOptionValue(zipWriter, options, OPTION_PASSWORD);
5662
- rawPassword = getOptionValue(zipWriter, options, OPTION_RAW_PASSWORD);
5663
- if ((password && typeof password != STRING_TYPE) || (rawPassword && !(rawPassword instanceof Uint8Array))) {
5664
- throw new Error(ERR_INVALID_PASSWORD_TYPE);
5665
- }
5792
+ const password = getOptionValue(zipWriter, options, OPTION_PASSWORD);
5793
+ const rawPassword = getOptionValue(zipWriter, options, OPTION_RAW_PASSWORD);
5794
+ if ((password && typeof password != STRING_TYPE) || (rawPassword && !(rawPassword instanceof Uint8Array))) {
5795
+ throw new Error(ERR_INVALID_PASSWORD_TYPE);
5666
5796
  }
5667
5797
  const encryptionStrength = getNumberOptionValue(zipWriter, options, OPTION_ENCRYPTION_STRENGTH, 3);
5668
5798
  const zipCrypto = getOptionValue(zipWriter, options, PROPERTY_NAME_ZIPCRYPTO);
@@ -5775,14 +5905,24 @@
5775
5905
  }
5776
5906
 
5777
5907
  async function resolveSizes(zipWriter, reader, { resolvedOptions: metadata }, options) {
5908
+ if (metadata.passThrough && !reader && !getOptionValue(zipWriter, options, PROPERTY_NAME_DIRECTORY)) {
5909
+ throw new Error(ERR_UNDEFINED_READER);
5910
+ }
5911
+ let contentSize;
5912
+ if (reader) {
5913
+ reader = new GenericReader(reader);
5914
+ await initStream(reader);
5915
+ ({ size: contentSize } = reader);
5916
+ }
5917
+ return Object.assign({ reader }, resolveEntrySizes(zipWriter, Boolean(reader), contentSize, metadata, options));
5918
+ }
5919
+
5920
+ function resolveEntrySizes(zipWriter, hasContent, contentSize, metadata, options) {
5778
5921
  const { passThrough, zipCrypto, password, rawPassword, encryptionStrength } = metadata;
5779
5922
  let { dataDescriptor, zip64, level, compressionMethod } = metadata;
5780
5923
  let maximumCompressedSize = 0;
5781
5924
  let uncompressedSize = 0;
5782
- if (passThrough) {
5783
- if (!reader) {
5784
- throw new Error(ERR_UNDEFINED_READER);
5785
- }
5925
+ if (passThrough && hasContent) {
5786
5926
  uncompressedSize = options[PROPERTY_NAME_UNCOMPRESSED_SIZE];
5787
5927
  if (uncompressedSize === UNDEFINED_VALUE) {
5788
5928
  throw new Error(ERR_UNDEFINED_UNCOMPRESSED_SIZE);
@@ -5790,29 +5930,30 @@
5790
5930
  }
5791
5931
  const zip64Enabled = zip64 === true;
5792
5932
  const encrypted = getOptionValue(zipWriter, options, PROPERTY_NAME_ENCRYPTED);
5793
- const encryptedEntry = Boolean(reader) && (Boolean((password && getLength(password)) || (rawPassword && getLength(rawPassword))) || (passThrough && encrypted));
5794
- if (!reader) {
5933
+ if (hasContent && passThrough && !encrypted && getLength(password, rawPassword)) {
5934
+ throw new Error(ERR_UNSUPPORTED_ENCRYPTION_PASS_THROUGH);
5935
+ }
5936
+ const encryptedEntry = hasContent && (Boolean((password && getLength(password)) || (rawPassword && getLength(rawPassword))) || (passThrough && encrypted));
5937
+ if (!hasContent) {
5795
5938
  level = 0;
5796
5939
  compressionMethod = COMPRESSION_METHOD_STORE;
5797
5940
  }
5798
5941
  const encryptionOverhead = encryptedEntry ? (zipCrypto ? 12 : 16 + encryptionStrength * 4) : 0;
5799
- if (reader) {
5800
- reader = new GenericReader(reader);
5801
- await initStream(reader);
5942
+ if (hasContent) {
5802
5943
  if (!passThrough) {
5803
- if (reader.size === UNDEFINED_VALUE) {
5944
+ if (contentSize === UNDEFINED_VALUE) {
5804
5945
  dataDescriptor = true;
5805
5946
  if (zip64 || zip64 === UNDEFINED_VALUE) {
5806
5947
  zip64 = true;
5807
5948
  uncompressedSize = maximumCompressedSize = MAX_32_BITS + 1;
5808
5949
  }
5809
5950
  } else {
5810
- options.uncompressedSize = uncompressedSize = reader.size;
5811
- maximumCompressedSize = getMaximumCompressedSize(uncompressedSize) + encryptionOverhead;
5951
+ options.uncompressedSize = uncompressedSize = contentSize;
5952
+ maximumCompressedSize = (isCompressed(compressionMethod, level) ? getMaximumCompressedSize(uncompressedSize) : uncompressedSize) + encryptionOverhead;
5812
5953
  }
5813
5954
  } else {
5814
5955
  options.uncompressedSize = uncompressedSize;
5815
- maximumCompressedSize = getMaximumCompressedSize(uncompressedSize) + encryptionOverhead;
5956
+ maximumCompressedSize = contentSize === UNDEFINED_VALUE ? getMaximumCompressedSize(uncompressedSize) + encryptionOverhead : contentSize;
5816
5957
  }
5817
5958
  }
5818
5959
  const zip64UncompressedSize = zip64Enabled || uncompressedSize >= MAX_32_BITS;
@@ -5826,7 +5967,7 @@
5826
5967
  }
5827
5968
  zip64 = zip64 || false;
5828
5969
  return {
5829
- reader,
5970
+ maximumCompressedSize,
5830
5971
  resolvedOptions: {
5831
5972
  dataDescriptor,
5832
5973
  zip64,
@@ -5840,6 +5981,81 @@
5840
5981
  };
5841
5982
  }
5842
5983
 
5984
+ async function getEntriesSize(writerOptions, entries, writeOrderGuaranteed, comment) {
5985
+ const zipWriter = { options: writerOptions, config: getConfiguration() };
5986
+ if (writerOptions[OPTION_SIGN_CENTRAL_DIRECTORY]) {
5987
+ throw new Error(ERR_UNDETERMINED_SIZE);
5988
+ }
5989
+ if (comment !== UNDEFINED_VALUE && !(comment instanceof Uint8Array)) {
5990
+ throw new Error(ERR_INVALID_COMMENT_TYPE);
5991
+ }
5992
+ const commentLength = getLength(comment);
5993
+ if (commentLength > MAX_16_BITS) {
5994
+ throw new Error(ERR_INVALID_COMMENT);
5995
+ }
5996
+ const usdz = writerOptions[OPTION_USDZ];
5997
+ const files = new Map();
5998
+ let layoutDependsOnWriteOrder = Boolean(usdz);
5999
+ let offset = 0;
6000
+ for (const entry of entries) {
6001
+ let { name } = entry;
6002
+ const { size } = entry;
6003
+ const options = Object.assign({}, entry.options);
6004
+ name = name.trim();
6005
+ if (getOptionValue(zipWriter, options, PROPERTY_NAME_DIRECTORY) && !name.endsWith(DIRECTORY_SIGNATURE)) {
6006
+ name += DIRECTORY_SIGNATURE;
6007
+ }
6008
+ const attributesInfo = resolveAttributes(zipWriter, name, options);
6009
+ ({ name } = attributesInfo);
6010
+ const { resolvedOptions: metadata } = resolveMetadata(zipWriter, name, options);
6011
+ if (metadata.level != 0 && metadata.compressionMethod === UNDEFINED_VALUE &&
6012
+ !metadata.passThrough && !(await supportsDeflate(zipWriter.config))) {
6013
+ metadata.level = 0;
6014
+ }
6015
+ const hasContent = !getOptionValue(zipWriter, options, PROPERTY_NAME_DIRECTORY);
6016
+ if (hasContent && size === UNDEFINED_VALUE) {
6017
+ throw new Error(ERR_UNDETERMINED_SIZE);
6018
+ }
6019
+ const { maximumCompressedSize, resolvedOptions: sizes } = resolveEntrySizes(zipWriter, hasContent, size, metadata, options);
6020
+ if (hasContent && !metadata.passThrough && isCompressed(sizes.compressionMethod, sizes.level)) {
6021
+ throw new Error(ERR_UNDETERMINED_SIZE);
6022
+ }
6023
+ const entryOptions = Object.assign({}, options, attributesInfo.resolvedOptions, metadata, sizes);
6024
+ const headerInfo = getHeaderInfo(entryOptions);
6025
+ const dataDescriptorInfo = getDataDescriptorInfo(entryOptions);
6026
+ const entryInfo = {
6027
+ headerInfo,
6028
+ metadataSize: getLength(headerInfo.localHeaderArray, dataDescriptorInfo.dataDescriptorArray)
6029
+ };
6030
+ if (usdz) {
6031
+ appendExtraFieldUSDZ(entryInfo, offset);
6032
+ }
6033
+ const compressedSize = hasContent ? maximumCompressedSize : 0;
6034
+ if (offset >= MAX_32_BITS) {
6035
+ layoutDependsOnWriteOrder = true;
6036
+ }
6037
+ files.set(name, Object.assign({}, entryOptions, headerInfo, {
6038
+ offset,
6039
+ diskNumberStart: 0,
6040
+ compressedSize
6041
+ }));
6042
+ offset += entryInfo.metadataSize + compressedSize;
6043
+ }
6044
+ if (layoutDependsOnWriteOrder && !writeOrderGuaranteed) {
6045
+ throw new Error(ERR_UNDETERMINED_SIZE);
6046
+ }
6047
+ const directoryDataLength = createDirectoryRecords(files);
6048
+ let zip64 = getOptionValue(zipWriter, writerOptions, PROPERTY_NAME_ZIP64);
6049
+ if (offset >= MAX_32_BITS || directoryDataLength >= MAX_32_BITS || files.size >= MAX_16_BITS) {
6050
+ if (zip64 === false) {
6051
+ throw new Error(ERR_UNSUPPORTED_FORMAT);
6052
+ } else {
6053
+ zip64 = true;
6054
+ }
6055
+ }
6056
+ return offset + directoryDataLength + commentLength + (zip64 ? ZIP64_END_OF_CENTRAL_DIR_TOTAL_LENGTH : END_OF_CENTRAL_DIR_LENGTH);
6057
+ }
6058
+
5843
6059
  async function getFileEntry(zipWriter, name, reader, entryInfo, options) {
5844
6060
  const {
5845
6061
  files,
@@ -6054,6 +6270,7 @@
6054
6270
  uid,
6055
6271
  gid,
6056
6272
  unixMode,
6273
+ symlink,
6057
6274
  setuid,
6058
6275
  setgid,
6059
6276
  sticky,
@@ -6090,6 +6307,7 @@
6090
6307
  uid,
6091
6308
  gid,
6092
6309
  unixMode,
6310
+ symlink: Boolean(symlink),
6093
6311
  setuid,
6094
6312
  setgid,
6095
6313
  sticky,
@@ -6170,8 +6388,8 @@
6170
6388
  rawLastModDate,
6171
6389
  creationDate,
6172
6390
  lastAccessDate,
6173
- encrypted,
6174
- zipCrypto,
6391
+ encrypted: Boolean(encrypted),
6392
+ zipCrypto: Boolean(zipCrypto),
6175
6393
  size: metadataSize + compressedSize,
6176
6394
  compressionMethod,
6177
6395
  version,
@@ -6211,9 +6429,7 @@
6211
6429
  crc32
6212
6430
  } = options;
6213
6431
  let { version, compressionMethod } = options;
6214
- const compressed = !directory && (compressionMethod === UNDEFINED_VALUE
6215
- ? (level === UNDEFINED_VALUE || level > 0)
6216
- : compressionMethod !== COMPRESSION_METHOD_STORE);
6432
+ const compressed = !directory && isCompressed(compressionMethod, level);
6217
6433
  let rawLocalExtraFieldZip64;
6218
6434
  const uncompressedFile = passThrough || !compressed;
6219
6435
  const zip64ExtraFieldComplete = zip64 && (options.bufferedWrite || !dataDescriptor || ((!zip64UncompressedSize && !zip64CompressedSize) || uncompressedFile));
@@ -6900,6 +7116,16 @@
6900
7116
  return result === UNDEFINED_VALUE ? defaultValue : result;
6901
7117
  }
6902
7118
 
7119
+ function getAliasedOptionValue(zipWriter, options, name, deprecatedName, defaultValue) {
7120
+ const value = getAliasedValue(options, name, deprecatedName);
7121
+ const result = value === UNDEFINED_VALUE ? getAliasedValue(zipWriter.options, name, deprecatedName) : value;
7122
+ return result === UNDEFINED_VALUE ? defaultValue : result;
7123
+ }
7124
+
7125
+ function getAliasedValue(options, name, deprecatedName) {
7126
+ return options[name] === UNDEFINED_VALUE ? options[deprecatedName] : options[name];
7127
+ }
7128
+
6903
7129
  function getNumberOptionValue(zipWriter, options, name, defaultValue) {
6904
7130
  return toNumber(getOptionValue(zipWriter, options, name, defaultValue));
6905
7131
  }
@@ -6912,6 +7138,12 @@
6912
7138
  return uncompressedSize + (5 * (Math.floor(uncompressedSize / 16383) + 1));
6913
7139
  }
6914
7140
 
7141
+ function isCompressed(compressionMethod, level) {
7142
+ return compressionMethod === UNDEFINED_VALUE
7143
+ ? (level === UNDEFINED_VALUE || level > 0)
7144
+ : compressionMethod !== COMPRESSION_METHOD_STORE;
7145
+ }
7146
+
6915
7147
  function setUint8(view, offset, value) {
6916
7148
  view.setUint8(offset, value);
6917
7149
  }
@@ -7042,6 +7274,7 @@
7042
7274
 
7043
7275
  const ERR_ENTRY_EXISTS = "Entry filename already exists";
7044
7276
  const ERR_READABLE_CONSUMED = "Readable stream already consumed";
7277
+ const ERR_INVALID_PASS_THROUGH = "Invalid passThrough option (use readerOptions.passThrough or set uncompressedSize for each entry)";
7045
7278
  const ERR_ABORT_EXPORT = "zipjs-abort-export";
7046
7279
  const ERR_ABORTED = "The operation was aborted";
7047
7280
  const ABORT_ERROR_NAME = "AbortError";
@@ -7079,6 +7312,7 @@
7079
7312
  parent,
7080
7313
  children: [],
7081
7314
  uncompressedSize: params.uncompressedSize || 0,
7315
+ undeterminedSize: params.undeterminedSize || params.uncompressedSize === UNDEFINED_VALUE,
7082
7316
  passThrough: params.passThrough
7083
7317
  });
7084
7318
  if (parent || !fs.root) {
@@ -7146,16 +7380,17 @@
7146
7380
 
7147
7381
  async getData(writer, options = {}) {
7148
7382
  const zipEntry = this;
7149
- if (!writer || (writer.constructor == zipEntry.Writer && zipEntry.data)) {
7383
+ if (!writer || (writer.constructor == zipEntry.Writer && zipEntry.data && keepsContentType(writer, zipEntry.data))) {
7150
7384
  return zipEntry.data;
7151
7385
  } else {
7152
7386
  const reader = zipEntry.reader = createReader(zipEntry.Reader, zipEntry.data, options);
7153
- const uncompressedSize = zipEntry.data ? zipEntry.data.uncompressedSize : reader.size;
7154
- await Promise.all([initStream(reader), initStream(writer, uncompressedSize)]);
7155
- const { readable } = reader;
7387
+ const dataSize = zipEntry.uncompressedSize || reader.size;
7388
+ await Promise.all([initStream(reader), initStream(writer, dataSize)]);
7156
7389
  const { signal } = options;
7390
+ const readable = createProgressReadable(zipEntry, reader, options, signal);
7391
+ const preventClose = !ownsWritable(writer) && Boolean(options.preventClose);
7157
7392
  zipEntry.uncompressedSize = reader.size;
7158
- await toCompatibleReadable(readable).pipeTo(toCompatibleWritable(writer.writable), { signal });
7393
+ await toCompatibleReadable(readable).pipeTo(toCompatibleWritable(writer.writable), { signal, preventClose, preventAbort: preventClose });
7159
7394
  return writer.getData ? writer.getData() : writer.writable;
7160
7395
  }
7161
7396
  }
@@ -7286,7 +7521,7 @@
7286
7521
  Reader: TextReader,
7287
7522
  Writer: TextWriter,
7288
7523
  options,
7289
- uncompressedSize: text.length
7524
+ uncompressedSize: getTextSize(text)
7290
7525
  });
7291
7526
  }
7292
7527
 
@@ -7415,10 +7650,16 @@
7415
7650
  }
7416
7651
 
7417
7652
  async importZip(reader, options = {}) {
7418
- await initStream(reader);
7419
- const zipReader = new ZipReader(reader, options);
7653
+ let zipReader;
7654
+ if (reader && typeof reader.getEntries == FUNCTION_TYPE) {
7655
+ zipReader = reader;
7656
+ options = Object.assign({}, zipReader.options, options);
7657
+ } else {
7658
+ await initStream(reader);
7659
+ zipReader = new ZipReader(reader, options);
7660
+ }
7420
7661
  const importedEntries = [];
7421
- const entries = await zipReader.getEntries();
7662
+ const entries = await zipReader.getEntries(options);
7422
7663
  for (const entry of entries) {
7423
7664
  let parent = this;
7424
7665
  try {
@@ -7440,7 +7681,7 @@
7440
7681
  importedEntries.push(addChild(parent, name, {
7441
7682
  data: entry,
7442
7683
  Reader: getZipBlobReader(Object.assign({}, options)),
7443
- uncompressedSize: entry.uncompressedSize,
7684
+ uncompressedSize: options.passThrough ? entry.compressedSize : entry.uncompressedSize,
7444
7685
  passThrough: options.passThrough
7445
7686
  }));
7446
7687
  } else {
@@ -7482,11 +7723,25 @@
7482
7723
  }
7483
7724
  const [readers] = await Promise.all([initReaders(zipEntry, options.readerOptions), initStream(writer)]);
7484
7725
  const zipWriter = new ZipWriter(writer, options);
7485
- await exportZip(zipWriter, zipEntry, getTotalSize([zipEntry], "uncompressedSize"), options, readers);
7486
- await zipWriter.close();
7726
+ await exportZip(zipWriter, zipEntry, getTotalSize([zipEntry], getUncompressedSize), options, readers);
7727
+ await zipWriter.close(options.globalComment);
7487
7728
  return writer.getData ? writer.getData() : writer.writable;
7488
7729
  }
7489
7730
 
7731
+ getExportedSize(options = {}) {
7732
+ const zipEntry = this;
7733
+ options = Object.assign({}, options);
7734
+ if (options.bufferedWrite === UNDEFINED_VALUE) {
7735
+ options.bufferedWrite = true;
7736
+ }
7737
+ const writeOrderGuaranteed = !options.bufferedWrite ||
7738
+ (options.keepOrder !== false && zipEntry.children.every(child => !child.children.length));
7739
+ return getEntriesSize(options, Array.from(zipEntry.getChildren({ recursive: true }), child => {
7740
+ const { name, entryOptions } = getChildEntryOptions(child, zipEntry, options);
7741
+ return { name, size: child.directory ? 0 : getDeterminedSize(child, isPassThrough(child, options)), options: entryOptions };
7742
+ }), writeOrderGuaranteed, options.globalComment);
7743
+ }
7744
+
7490
7745
  getChildByName(name) {
7491
7746
  const children = this.children;
7492
7747
  for (let childIndex = 0; childIndex < children.length; childIndex++) {
@@ -7694,6 +7949,10 @@
7694
7949
  return this.root.exportZip(writer, options);
7695
7950
  }
7696
7951
 
7952
+ getExportedSize(options) {
7953
+ return this.root.getExportedSize(options);
7954
+ }
7955
+
7697
7956
  isPasswordProtected() {
7698
7957
  return this.root.isPasswordProtected();
7699
7958
  }
@@ -7705,12 +7964,12 @@
7705
7964
 
7706
7965
  const fs = { FS, ZipDirectoryEntry, ZipFileEntry };
7707
7966
 
7708
- function getTotalSize(entries, propertyName) {
7967
+ function getTotalSize(entries, getEntrySize) {
7709
7968
  let size = 0;
7710
7969
  const pendingEntries = Array.from(entries);
7711
7970
  while (pendingEntries.length) {
7712
7971
  const entry = pendingEntries.pop();
7713
- size += entry[propertyName] || 0;
7972
+ size += getEntrySize(entry) || 0;
7714
7973
  for (const child of entry.children) {
7715
7974
  pendingEntries.push(child);
7716
7975
  }
@@ -7718,6 +7977,15 @@
7718
7977
  return size;
7719
7978
  }
7720
7979
 
7980
+ function getUncompressedSize(entry) {
7981
+ return entry.uncompressedSize;
7982
+ }
7983
+
7984
+ function getExtractedSize(entry, passThrough) {
7985
+ const { data } = entry;
7986
+ return passThrough && data instanceof Entry ? data.compressedSize : entry.uncompressedSize;
7987
+ }
7988
+
7721
7989
  function getReadableReader(readable) {
7722
7990
  let consumed;
7723
7991
  return function () {
@@ -7740,10 +8008,17 @@
7740
8008
 
7741
8009
  async init() {
7742
8010
  const zipBlobReader = this;
7743
- zipBlobReader.size = zipBlobReader.entry.uncompressedSize;
7744
- const data = await zipBlobReader.entry.getData(new BlobWriter(), Object.assign({}, options, zipBlobReader.options));
8011
+ const readerOptions = Object.assign({}, options, zipBlobReader.options);
8012
+ const { checkOverlappingEntry, checkOverlappingEntryOnly } = readerOptions;
8013
+ const data = await zipBlobReader.entry.getData(new BlobWriter(), Object.assign(readerOptions, {
8014
+ checkPasswordOnly: false,
8015
+ checkOverlappingEntry: checkOverlappingEntryOnly || checkOverlappingEntry,
8016
+ checkOverlappingEntryOnly: false,
8017
+ preventClose: false
8018
+ }));
7745
8019
  zipBlobReader.data = data;
7746
8020
  zipBlobReader.blobReader = new BlobReader(data);
8021
+ zipBlobReader.size = data.size;
7747
8022
  super.init();
7748
8023
  }
7749
8024
 
@@ -7757,6 +8032,30 @@
7757
8032
  return Reader.prototype ? new Reader(data, options) : Reader(data, options);
7758
8033
  }
7759
8034
 
8035
+ function keepsContentType(writer, data) {
8036
+ const { contentType } = writer;
8037
+ if (contentType === UNDEFINED_VALUE) {
8038
+ return true;
8039
+ } else if (writer.constructor == BlobWriter) {
8040
+ return data.type == contentType;
8041
+ } else if (writer.constructor == Data64URIWriter) {
8042
+ return data.startsWith(writer.data);
8043
+ } else {
8044
+ return true;
8045
+ }
8046
+ }
8047
+
8048
+ function createProgressReadable(zipEntry, reader, options, signal) {
8049
+ const { onstart, onprogress, onend } = options;
8050
+ const { readable } = reader;
8051
+ const coreReaderReportsProgress = zipEntry.data instanceof Entry;
8052
+ if (coreReaderReportsProgress || (!onstart && !onprogress && !onend)) {
8053
+ return readable;
8054
+ } else {
8055
+ return toCompatibleReadable(readable).pipeThrough(new ProgressWatcherStream({ onstart, onprogress, onend, size: reader.size }), { signal });
8056
+ }
8057
+ }
8058
+
7760
8059
  async function initReaders(entry, options) {
7761
8060
  const fileEntries = [];
7762
8061
  const pendingEntries = [entry];
@@ -7789,6 +8088,7 @@
7789
8088
  }
7790
8089
  if (reader.size !== UNDEFINED_VALUE) {
7791
8090
  child.uncompressedSize = reader.size;
8091
+ child.undeterminedSize = false;
7792
8092
  }
7793
8093
  }));
7794
8094
  return readers;
@@ -7838,6 +8138,90 @@
7838
8138
  return error;
7839
8139
  }
7840
8140
 
8141
+ function getChildEntryOptions(child, selectedEntry, options) {
8142
+ const name = options.relativePath ? child.getRelativeName(selectedEntry) : child.getFullname();
8143
+ const childOptions = child.options || {};
8144
+ let zipEntryMetadata = {};
8145
+ let passThroughOptions = {};
8146
+ if (child.data instanceof Entry) {
8147
+ const {
8148
+ externalFileAttributes,
8149
+ versionMadeBy,
8150
+ comment,
8151
+ lastModDate,
8152
+ creationDate,
8153
+ lastAccessDate,
8154
+ uncompressedSize,
8155
+ encrypted,
8156
+ zipCrypto,
8157
+ crc32,
8158
+ compressionMethod,
8159
+ extraFieldAES,
8160
+ internalFileAttributes,
8161
+ extraField,
8162
+ uid,
8163
+ gid
8164
+ } = child.data;
8165
+ zipEntryMetadata = {
8166
+ externalFileAttributes,
8167
+ versionMadeBy,
8168
+ comment,
8169
+ lastModDate,
8170
+ creationDate,
8171
+ lastAccessDate,
8172
+ internalFileAttributes
8173
+ };
8174
+ const userExtraField = getUserExtraField(extraField);
8175
+ if (userExtraField) {
8176
+ zipEntryMetadata.extraField = userExtraField;
8177
+ }
8178
+ if (uid !== UNDEFINED_VALUE || gid !== UNDEFINED_VALUE) {
8179
+ Object.assign(zipEntryMetadata, {
8180
+ uid,
8181
+ gid,
8182
+ unixExtraFieldType: INFOZIP_EXTRA_FIELD_TYPE
8183
+ });
8184
+ }
8185
+ if (isPassThrough(child, options)) {
8186
+ let level, encryptionStrength;
8187
+ if (compressionMethod === 0) {
8188
+ level = 0;
8189
+ }
8190
+ if (extraFieldAES) {
8191
+ encryptionStrength = extraFieldAES.strength;
8192
+ }
8193
+ passThroughOptions = {
8194
+ passThrough: true,
8195
+ encrypted,
8196
+ zipCrypto,
8197
+ crc32,
8198
+ uncompressedSize,
8199
+ level,
8200
+ encryptionStrength,
8201
+ compressionMethod
8202
+ };
8203
+ }
8204
+ }
8205
+ const entryOptions = Object.assign({}, zipEntryMetadata, options, passThroughOptions, childOptions, { directory: child.directory });
8206
+ if (!child.directory && entryOptions.passThrough && entryOptions.uncompressedSize === UNDEFINED_VALUE) {
8207
+ throw new Error(ERR_INVALID_PASS_THROUGH);
8208
+ }
8209
+ return { name, entryOptions };
8210
+ }
8211
+
8212
+ function getDeterminedSize(child, passThrough) {
8213
+ const { reader } = child;
8214
+ if (reader && reader.size !== UNDEFINED_VALUE) {
8215
+ return reader.size;
8216
+ }
8217
+ return child.undeterminedSize ? UNDEFINED_VALUE : getExtractedSize(child, passThrough);
8218
+ }
8219
+
8220
+ function isPassThrough(child, options) {
8221
+ const { readerOptions } = options;
8222
+ return Boolean(!child.directory && (child.passThrough || (readerOptions && readerOptions.passThrough)));
8223
+ }
8224
+
7841
8225
  function getUserExtraField(extraField) {
7842
8226
  if (extraField) {
7843
8227
  const userExtraField = new Map();
@@ -7853,8 +8237,14 @@
7853
8237
  }
7854
8238
 
7855
8239
  async function exportZip(zipWriter, entry, totalSize, options, readers) {
8240
+ const { onstart, onprogress, onend, onentryprogress } = options;
7856
8241
  const selectedEntry = entry;
7857
- const entryOffsets = new Map();
8242
+ const totalEntries = getTotalSize(entry.children, () => 1);
8243
+ let writtenSize = 0;
8244
+ let writtenEntries = 0;
8245
+ if (onstart) {
8246
+ await callHandler(onstart, totalSize);
8247
+ }
7858
8248
  if (options.bufferedWrite) {
7859
8249
  await processChildren(entry);
7860
8250
  } else {
@@ -7862,6 +8252,9 @@
7862
8252
  await addChild(child);
7863
8253
  }
7864
8254
  }
8255
+ if (onend) {
8256
+ await callHandler(onend, writtenSize);
8257
+ }
7865
8258
 
7866
8259
  async function processChildren(entry) {
7867
8260
  const results = await Promise.allSettled(entry.children.map(async child => {
@@ -7875,81 +8268,23 @@
7875
8268
  }
7876
8269
 
7877
8270
  async function addChild(child) {
7878
- const name = options.relativePath ? child.getRelativeName(selectedEntry) : child.getFullname();
7879
- const childOptions = child.options || {};
7880
- let zipEntryOptions = {};
7881
- if (child.data instanceof Entry) {
7882
- const {
7883
- externalFileAttributes,
7884
- versionMadeBy,
7885
- comment,
7886
- lastModDate,
7887
- creationDate,
7888
- lastAccessDate,
7889
- uncompressedSize,
7890
- encrypted,
7891
- zipCrypto,
7892
- crc32,
7893
- compressionMethod,
7894
- extraFieldAES,
7895
- internalFileAttributes,
7896
- extraField,
7897
- uid,
7898
- gid
7899
- } = child.data;
7900
- zipEntryOptions = {
7901
- externalFileAttributes,
7902
- versionMadeBy,
7903
- comment,
7904
- lastModDate,
7905
- creationDate,
7906
- lastAccessDate,
7907
- internalFileAttributes
7908
- };
7909
- const userExtraField = getUserExtraField(extraField);
7910
- if (userExtraField) {
7911
- zipEntryOptions.extraField = userExtraField;
7912
- }
7913
- if (uid !== UNDEFINED_VALUE || gid !== UNDEFINED_VALUE) {
7914
- Object.assign(zipEntryOptions, {
7915
- uid,
7916
- gid,
7917
- unixExtraFieldType: options.unixExtraFieldType || INFOZIP_EXTRA_FIELD_TYPE
7918
- });
7919
- }
7920
- if (child.passThrough) {
7921
- let level, encryptionStrength;
7922
- if (compressionMethod === 0) {
7923
- level = 0;
7924
- }
7925
- if (extraFieldAES) {
7926
- encryptionStrength = extraFieldAES.strength;
7927
- }
7928
- zipEntryOptions = Object.assign(zipEntryOptions, {
7929
- passThrough: true,
7930
- encrypted,
7931
- zipCrypto,
7932
- crc32,
7933
- uncompressedSize,
7934
- level,
7935
- encryptionStrength,
7936
- compressionMethod
7937
- });
7938
- }
7939
- }
7940
- await zipWriter.add(name, readers.get(child), Object.assign({}, options, zipEntryOptions, childOptions, {
7941
- directory: child.directory,
8271
+ const { name, entryOptions } = getChildEntryOptions(child, selectedEntry, options);
8272
+ let entryWrittenSize = 0;
8273
+ const entryMetadata = await zipWriter.add(name, readers.get(child), Object.assign(entryOptions, {
8274
+ onstart: UNDEFINED_VALUE,
8275
+ onend: UNDEFINED_VALUE,
7942
8276
  onprogress: async indexProgress => {
7943
- if (options.onprogress) {
7944
- entryOffsets.set(name, indexProgress);
7945
- try {
7946
- await options.onprogress(Array.from(entryOffsets.values()).reduce((previousValue, currentValue) => previousValue + currentValue), totalSize);
7947
- } catch {
7948
- // ignored
7949
- }
8277
+ writtenSize += indexProgress - entryWrittenSize;
8278
+ entryWrittenSize = indexProgress;
8279
+ if (onprogress) {
8280
+ await callHandler(onprogress, writtenSize, totalSize);
7950
8281
  }
7951
8282
  }
7952
8283
  }));
8284
+ writtenEntries++;
8285
+ if (onentryprogress) {
8286
+ await callHandler(onentryprogress, writtenEntries, totalEntries, entryMetadata);
8287
+ }
7953
8288
  }
7954
8289
  }
7955
8290
 
@@ -7977,7 +8312,7 @@
7977
8312
  })
7978
8313
  );
7979
8314
  } else if (handle.kind == "directory") {
7980
- const directoryEntry = parentEntry.addDirectory(handle.name);
8315
+ const directoryEntry = parentEntry.addDirectory(handle.name, options);
7981
8316
  addedEntries.push(directoryEntry);
7982
8317
  for await (const childHandle of handle.values()) {
7983
8318
  await addFile(directoryEntry, childHandle, addedEntries, entryName);
@@ -7999,15 +8334,29 @@
7999
8334
  }
8000
8335
 
8001
8336
  async function exportFileSystemHandle(zipEntry, directoryHandle, options) {
8002
- const totalSize = getTotalSize([zipEntry], "uncompressedSize");
8003
- const writtenSizes = new Map();
8337
+ const { onstart, onprogress, onend } = options;
8004
8338
  const abortController = new AbortController();
8005
8339
  const { signal } = abortController;
8006
8340
  const releaseSignal = forwardAbort(options.signal, abortController);
8341
+ const getDataOptions = Object.assign({}, options, options.readerOptions, {
8342
+ signal,
8343
+ onstart: UNDEFINED_VALUE,
8344
+ onprogress: UNDEFINED_VALUE,
8345
+ onend: UNDEFINED_VALUE,
8346
+ preventClose: false
8347
+ });
8348
+ const totalSize = getTotalSize([zipEntry], entry => getExtractedSize(entry, getDataOptions.passThrough));
8007
8349
  const exportedEntryNames = [];
8008
8350
  let exportAborted = false;
8351
+ let writtenSize = 0;
8009
8352
  try {
8353
+ if (onstart) {
8354
+ await callHandler(onstart, totalSize);
8355
+ }
8010
8356
  await exportChildren(zipEntry, directoryHandle);
8357
+ if (onend) {
8358
+ await callHandler(onend, writtenSize);
8359
+ }
8011
8360
  } catch (error) {
8012
8361
  try {
8013
8362
  error.exportedEntryNames = exportedEntryNames;
@@ -8020,6 +8369,25 @@
8020
8369
  }
8021
8370
  return directoryHandle;
8022
8371
 
8372
+ function createProgressWritable(writable) {
8373
+ const writer = writable.getWriter();
8374
+ return new WritableStream({
8375
+ async write(chunk) {
8376
+ await writer.write(chunk);
8377
+ writtenSize += chunk.length;
8378
+ if (onprogress) {
8379
+ await callHandler(onprogress, writtenSize, totalSize);
8380
+ }
8381
+ },
8382
+ close() {
8383
+ return writer.close();
8384
+ },
8385
+ abort(reason) {
8386
+ return writer.abort(reason);
8387
+ }
8388
+ });
8389
+ }
8390
+
8023
8391
  async function exportChildren(entry, parentHandle) {
8024
8392
  if (options.concurrent) {
8025
8393
  const results = await Promise.allSettled(entry.children.map(child => exportChild(child, parentHandle)));
@@ -8051,19 +8419,7 @@
8051
8419
  const fileHandle = await parentHandle.getFileHandle(child.name, { create: true });
8052
8420
  const writable = await fileHandle.createWritable();
8053
8421
  try {
8054
- await child.getData({ writable }, Object.assign({}, options, {
8055
- signal,
8056
- onprogress: async progress => {
8057
- if (options.onprogress) {
8058
- writtenSizes.set(child.id, progress);
8059
- try {
8060
- await options.onprogress(Array.from(writtenSizes.values()).reduce((previousValue, currentValue) => previousValue + currentValue, 0), totalSize);
8061
- } catch {
8062
- // ignored
8063
- }
8064
- }
8065
- }
8066
- }));
8422
+ await child.getData({ writable: createProgressWritable(writable) }, getDataOptions);
8067
8423
  } catch (error) {
8068
8424
  throw exportAborted ? new Error(ERR_ABORT_EXPORT) : error;
8069
8425
  }
@@ -8178,6 +8534,7 @@
8178
8534
 
8179
8535
  exports.ERR_ABORTED = ERR_ABORTED;
8180
8536
  exports.ERR_ENTRY_EXISTS = ERR_ENTRY_EXISTS;
8537
+ exports.ERR_INVALID_PASS_THROUGH = ERR_INVALID_PASS_THROUGH;
8181
8538
  exports.ERR_READABLE_CONSUMED = ERR_READABLE_CONSUMED;
8182
8539
  exports.fs = fs;
8183
8540