@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/index-native.cjs CHANGED
@@ -84,6 +84,8 @@ const FILE_ATTR_MSDOS_SYSTEM_MASK = 0x04;
84
84
  const FILE_ATTR_MSDOS_ARCHIVE_MASK = 0x20;
85
85
  const FILE_ATTR_UNIX_TYPE_MASK = 0o170000;
86
86
  const FILE_ATTR_UNIX_TYPE_DIR = 0o040000;
87
+ const FILE_ATTR_UNIX_TYPE_SYMLINK = 0o120000;
88
+ const FILE_ATTR_UNIX_TYPE_FILE = 0o100000;
87
89
  const FILE_ATTR_UNIX_EXECUTABLE_MASK = 0o111;
88
90
  const FILE_ATTR_UNIX_DEFAULT_MASK = 0o644;
89
91
  const FILE_ATTR_UNIX_SETUID_MASK = 0o4000;
@@ -94,6 +96,9 @@ const VERSION_DEFLATE = 0x14;
94
96
  const VERSION_ZIP64 = 0x2D;
95
97
  const VERSION_AES = 0x33;
96
98
 
99
+ const VERSION_MADE_BY_MSDOS = 0x0014;
100
+ const VERSION_MADE_BY_UNIX = 0x0300;
101
+
97
102
  const DIRECTORY_SIGNATURE = "/";
98
103
 
99
104
  const HEADER_SIZE = 30;
@@ -1775,8 +1780,6 @@ function getInt32(number) {
1775
1780
  */
1776
1781
 
1777
1782
 
1778
- const HTTP_HEADER_CONTENT_TYPE = "Content-Type";
1779
-
1780
1783
  function toCompatibleReadable(readable) {
1781
1784
  if (readable instanceof ReadableStream) {
1782
1785
  return readable;
@@ -1799,12 +1802,9 @@ function toCompatibleReadable(readable) {
1799
1802
 
1800
1803
  function streamToBlob(readable, contentType) {
1801
1804
  readable = toCompatibleReadable(readable);
1805
+ const blobOptions = contentType ? { type: contentType } : {};
1802
1806
  if (responseSupportsGlobalReadable()) {
1803
- const options = {};
1804
- if (contentType) {
1805
- options.headers = [[HTTP_HEADER_CONTENT_TYPE, contentType]];
1806
- }
1807
- return new Response(readable, options).blob();
1807
+ return new Response(readable).blob().then(blob => contentType ? new Blob([blob], blobOptions) : blob);
1808
1808
  }
1809
1809
  const chunks = [];
1810
1810
  return readable
@@ -1813,7 +1813,7 @@ function streamToBlob(readable, contentType) {
1813
1813
  chunks.push(chunk);
1814
1814
  }
1815
1815
  }))
1816
- .then(() => new Blob(chunks, contentType ? { type: contentType } : {}));
1816
+ .then(() => new Blob(chunks, blobOptions));
1817
1817
  }
1818
1818
 
1819
1819
  function responseSupportsGlobalReadable() {
@@ -2755,6 +2755,7 @@ function createWebWorkerInterface(workerData, config) {
2755
2755
  worker,
2756
2756
  workerAlive: false,
2757
2757
  terminated: false,
2758
+ startupError: null,
2758
2759
  interface: {
2759
2760
  run: async () => {
2760
2761
  try {
@@ -2782,6 +2783,13 @@ function createWebWorkerInterface(workerData, config) {
2782
2783
  }
2783
2784
 
2784
2785
  async function runWebWorker(workerData, config) {
2786
+ if (!workerData.worker) {
2787
+ const { startupError } = workerData;
2788
+ workerData.startupError = null;
2789
+ const error = startupError || new Error(ERR_WORKER_STARTUP_TIMEOUT);
2790
+ error.workerStartupFailed = true;
2791
+ throw error;
2792
+ }
2785
2793
  let resolveResult, rejectResult;
2786
2794
  const result = new Promise((resolve, reject) => {
2787
2795
  resolveResult = resolve;
@@ -2995,11 +3003,12 @@ function onWorkerError(event, workerData) {
2995
3003
  if (!workerAlive) {
2996
3004
  workerData.worker = null;
2997
3005
  }
3006
+ let error = event.error || new Error(event.message || ERROR_EVENT_TYPE);
3007
+ if (!workerAlive) {
3008
+ error = Object.assign(new Error(error.message || ERROR_EVENT_TYPE), { workerStartupFailed: true });
3009
+ workerData.startupError = error;
3010
+ }
2998
3011
  if (rejectResult) {
2999
- let error = event.error || new Error(event.message || ERROR_EVENT_TYPE);
3000
- if (!workerAlive) {
3001
- error = Object.assign(new Error(error.message || ERROR_EVENT_TYPE), { workerStartupFailed: true });
3002
- }
3003
3012
  rejectResult(error);
3004
3013
  if (writer) {
3005
3014
  writer.releaseLock();
@@ -3344,8 +3353,10 @@ class Reader extends Stream {
3344
3353
  async pull(controller) {
3345
3354
  const dataSize = size === UNDEFINED_VALUE ? chunkSize : Math.min(chunkSize, size - chunkOffset);
3346
3355
  const data = await readUint8Array(reader, offset + chunkOffset, dataSize);
3347
- controller.enqueue(data);
3348
- if ((chunkOffset + chunkSize > size) || (size === UNDEFINED_VALUE && !data.length && dataSize)) {
3356
+ if (data.length) {
3357
+ controller.enqueue(data);
3358
+ }
3359
+ if ((chunkOffset + chunkSize >= size) || (size === UNDEFINED_VALUE && !data.length && dataSize)) {
3349
3360
  controller.close();
3350
3361
  } else {
3351
3362
  chunkOffset += chunkSize;
@@ -3423,6 +3434,7 @@ class Data64URIWriter extends Writer {
3423
3434
  constructor(contentType) {
3424
3435
  super();
3425
3436
  Object.assign(this, {
3437
+ contentType,
3426
3438
  data: "data:" + (contentType || "") + ";base64,",
3427
3439
  pending: []
3428
3440
  });
@@ -3524,6 +3536,7 @@ class BlobWriter extends Stream {
3524
3536
  return transformStream.writable;
3525
3537
  }
3526
3538
  });
3539
+ writer.contentType = contentType;
3527
3540
  writer.blob = streamToBlob(transformStream.readable, contentType);
3528
3541
  writer.blob.catch(() => { });
3529
3542
  }
@@ -3540,6 +3553,26 @@ class TextReader extends BlobReader {
3540
3553
  }
3541
3554
  }
3542
3555
 
3556
+ function getTextSize(text) {
3557
+ let size = 0;
3558
+ for (let indexCharacter = 0; indexCharacter < text.length; indexCharacter++) {
3559
+ const characterCode = text.charCodeAt(indexCharacter);
3560
+ if (characterCode < 0x80) {
3561
+ size += 1;
3562
+ } else if (characterCode < 0x800) {
3563
+ size += 2;
3564
+ } else if (characterCode < 0xd800 || characterCode >= 0xe000) {
3565
+ size += 3;
3566
+ } else if (characterCode < 0xdc00 && (text.charCodeAt(indexCharacter + 1) & 0xfc00) == 0xdc00) {
3567
+ size += 4;
3568
+ indexCharacter++;
3569
+ } else {
3570
+ size += 3;
3571
+ }
3572
+ }
3573
+ return size;
3574
+ }
3575
+
3543
3576
  class TextWriter extends BlobWriter {
3544
3577
 
3545
3578
  constructor(encoding) {
@@ -4024,9 +4057,8 @@ class SplitDataReader extends Reader {
4024
4057
 
4025
4058
  async init() {
4026
4059
  const reader = this;
4027
- const { readers } = reader;
4028
4060
  reader.lastDiskNumber = 0;
4029
- await Promise.all(readers.map(diskReader => initStream(diskReader)));
4061
+ const readers = reader.readers = await Promise.all(reader.readers.map(initDiskReader));
4030
4062
  reader.diskOffsets = readers.map(diskReader => {
4031
4063
  const diskOffset = reader.size;
4032
4064
  reader.size += diskReader.size;
@@ -4203,6 +4235,10 @@ class GenericWriter {
4203
4235
  }
4204
4236
  }
4205
4237
 
4238
+ function ownsWritable(writer) {
4239
+ return Boolean(writer && writer.getData);
4240
+ }
4241
+
4206
4242
  function isHttpFamily(url) {
4207
4243
  const { baseURI } = getConfiguration();
4208
4244
  const { protocol } = new URL(url, baseURI);
@@ -4217,6 +4253,16 @@ async function initStream(stream, initSize) {
4217
4253
  }
4218
4254
  }
4219
4255
 
4256
+ async function initDiskReader(diskReader) {
4257
+ diskReader = new GenericReader(diskReader);
4258
+ await initStream(diskReader);
4259
+ if (diskReader.size === UNDEFINED_VALUE || !diskReader.readUint8Array) {
4260
+ diskReader = new BlobReader(await streamToBlob(diskReader.readable));
4261
+ await initStream(diskReader);
4262
+ }
4263
+ return diskReader;
4264
+ }
4265
+
4220
4266
  function readUint8Array(reader, offset, size) {
4221
4267
  return reader.readUint8Array(offset, size);
4222
4268
  }
@@ -4347,6 +4393,8 @@ const PROPERTY_NAME_CREATION_DATE = "creationDate";
4347
4393
  const PROPERTY_NAME_RAW_CREATION_DATE = "rawCreationDate";
4348
4394
  const PROPERTY_NAME_INTERNAL_FILE_ATTRIBUTES = "internalFileAttributes";
4349
4395
  const PROPERTY_NAME_EXTERNAL_FILE_ATTRIBUTES = "externalFileAttributes";
4396
+ const PROPERTY_NAME_DEPRECATED_INTERNAL_FILE_ATTRIBUTES = "internalFileAttribute";
4397
+ const PROPERTY_NAME_DEPRECATED_EXTERNAL_FILE_ATTRIBUTES = "externalFileAttribute";
4350
4398
  const PROPERTY_NAME_MSDOS_ATTRIBUTES_RAW = "msdosAttributesRaw";
4351
4399
  const PROPERTY_NAME_MSDOS_ATTRIBUTES = "msdosAttributes";
4352
4400
  const PROPERTY_NAME_MS_DOS_COMPATIBLE = "msDosCompatible";
@@ -4357,6 +4405,7 @@ const PROPERTY_NAME_VERSION_MADE_BY = "versionMadeBy";
4357
4405
  const PROPERTY_NAME_ZIPCRYPTO = "zipCrypto";
4358
4406
  const PROPERTY_NAME_DIRECTORY = "directory";
4359
4407
  const PROPERTY_NAME_EXECUTABLE = "executable";
4408
+ const PROPERTY_NAME_SYMLINK = "symlink";
4360
4409
  const PROPERTY_NAME_COMPRESSION_METHOD = "compressionMethod";
4361
4410
  const PROPERTY_NAME_SIGNATURE = "signature";
4362
4411
  const PROPERTY_NAME_CRC32 = "crc32";
@@ -4372,6 +4421,10 @@ const PROPERTY_NAME_SETUID = "setuid";
4372
4421
  const PROPERTY_NAME_SETGID = "setgid";
4373
4422
  const PROPERTY_NAME_STICKY = "sticky";
4374
4423
  const PROPERTY_NAME_BITFLAG = "bitFlag";
4424
+ const PROPERTY_NAME_RAW_BITFLAG = "rawBitFlag";
4425
+ const PROPERTY_NAME_FILENAME_LENGTH = "filenameLength";
4426
+ const PROPERTY_NAME_EXTRA_FIELD_LENGTH = "extraFieldLength";
4427
+ const PROPERTY_NAME_UNIX_EXTERNAL_UPPER = "unixExternalUpper";
4375
4428
  const PROPERTY_NAME_FILENAME_UTF8 = "filenameUTF8";
4376
4429
  const PROPERTY_NAME_COMMENT_UTF8 = "commentUTF8";
4377
4430
  const PROPERTY_NAME_RAW_EXTRA_FIELD = "rawExtraField";
@@ -4400,6 +4453,8 @@ const PROPERTY_NAMES = [
4400
4453
  PROPERTY_NAME_DISK_NUMBER_START,
4401
4454
  PROPERTY_NAME_INTERNAL_FILE_ATTRIBUTES,
4402
4455
  PROPERTY_NAME_EXTERNAL_FILE_ATTRIBUTES,
4456
+ PROPERTY_NAME_DEPRECATED_INTERNAL_FILE_ATTRIBUTES,
4457
+ PROPERTY_NAME_DEPRECATED_EXTERNAL_FILE_ATTRIBUTES,
4403
4458
  PROPERTY_NAME_MSDOS_ATTRIBUTES_RAW,
4404
4459
  PROPERTY_NAME_MSDOS_ATTRIBUTES,
4405
4460
  PROPERTY_NAME_MS_DOS_COMPATIBLE,
@@ -4410,6 +4465,7 @@ const PROPERTY_NAMES = [
4410
4465
  PROPERTY_NAME_ZIPCRYPTO,
4411
4466
  PROPERTY_NAME_DIRECTORY,
4412
4467
  PROPERTY_NAME_EXECUTABLE,
4468
+ PROPERTY_NAME_SYMLINK,
4413
4469
  PROPERTY_NAME_COMPRESSION_METHOD,
4414
4470
  PROPERTY_NAME_SIGNATURE,
4415
4471
  PROPERTY_NAME_CRC32,
@@ -4421,10 +4477,14 @@ const PROPERTY_NAMES = [
4421
4477
  PROPERTY_NAME_UID,
4422
4478
  PROPERTY_NAME_GID,
4423
4479
  PROPERTY_NAME_UNIX_MODE,
4480
+ PROPERTY_NAME_UNIX_EXTERNAL_UPPER,
4424
4481
  PROPERTY_NAME_SETUID,
4425
4482
  PROPERTY_NAME_SETGID,
4426
4483
  PROPERTY_NAME_STICKY,
4427
4484
  PROPERTY_NAME_BITFLAG,
4485
+ PROPERTY_NAME_RAW_BITFLAG,
4486
+ PROPERTY_NAME_FILENAME_LENGTH,
4487
+ PROPERTY_NAME_EXTRA_FIELD_LENGTH,
4428
4488
  PROPERTY_NAME_FILENAME_UTF8,
4429
4489
  PROPERTY_NAME_COMMENT_UTF8,
4430
4490
  PROPERTY_NAME_RAW_EXTRA_FIELD,
@@ -4486,6 +4546,7 @@ const OPTION_CHECK_PASSWORD_ONLY = "checkPasswordOnly";
4486
4546
  const OPTION_CHECK_OVERLAPPING_ENTRY_ONLY = "checkOverlappingEntryOnly";
4487
4547
  const OPTION_CHECK_OVERLAPPING_ENTRY = "checkOverlappingEntry";
4488
4548
  const OPTION_CHECK_AMBIGUITY = "checkAmbiguity";
4549
+ const OPTION_CHECK_LOCAL_DIRECTORY = "checkLocalDirectory";
4489
4550
  const OPTION_CHECK_SIGNATURE = "checkSignature";
4490
4551
  const OPTION_CHECK_CRC32 = "checkCrc32";
4491
4552
  const OPTION_CHECK_AUTHENTICATION_CODE = "checkAuthenticationCode";
@@ -4617,7 +4678,7 @@ class ZipReader {
4617
4678
  if (reader.size < END_OF_CENTRAL_DIR_LENGTH) {
4618
4679
  throw new Error(ERR_BAD_FORMAT);
4619
4680
  }
4620
- const strictness = getStrictness(getOptionValue$1(zipReader, options, OPTION_STRICTNESS), getOptionValue$1(zipReader, options, OPTION_CHECK_AMBIGUITY));
4681
+ const strictness = getStrictness(options, zipReader.options);
4621
4682
  const checkAmbiguity = strictness == STRICTNESS_STRICT;
4622
4683
  const rejectAmbiguousEndOfDirectory = strictness != STRICTNESS_TOLERANT;
4623
4684
  const maxAppendedDataSize = getMaxAppendedDataSize(getOptionValue$1(zipReader, options, OPTION_MAX_APPENDED_DATA_SIZE), strictness);
@@ -4839,6 +4900,7 @@ class ZipReader {
4839
4900
  index: indexFile,
4840
4901
  versionMadeBy,
4841
4902
  msDosCompatible,
4903
+ zip64: false,
4842
4904
  compressedSize: 0,
4843
4905
  uncompressedSize: 0,
4844
4906
  commentLength,
@@ -4872,15 +4934,18 @@ class ZipReader {
4872
4934
  const setuid = Boolean(fileEntry.unixMode & FILE_ATTR_UNIX_SETUID_MASK);
4873
4935
  const setgid = Boolean(fileEntry.unixMode & FILE_ATTR_UNIX_SETGID_MASK);
4874
4936
  const sticky = Boolean(fileEntry.unixMode & FILE_ATTR_UNIX_STICKY_MASK);
4875
- const executable = (fileEntry.unixMode !== UNDEFINED_VALUE)
4937
+ const unixType = fileEntry.unixMode === UNDEFINED_VALUE ? unixExternalUpper : fileEntry.unixMode;
4938
+ const symlink = (unixType & FILE_ATTR_UNIX_TYPE_MASK) == FILE_ATTR_UNIX_TYPE_SYMLINK;
4939
+ const executable = !symlink && ((fileEntry.unixMode !== UNDEFINED_VALUE)
4876
4940
  ? ((fileEntry.unixMode & FILE_ATTR_UNIX_EXECUTABLE_MASK) != 0)
4877
- : (unixCompatible && ((unixExternalUpper & FILE_ATTR_UNIX_EXECUTABLE_MASK) != 0));
4941
+ : (unixCompatible && ((unixExternalUpper & FILE_ATTR_UNIX_EXECUTABLE_MASK) != 0)));
4878
4942
  const modeIsDir = fileEntry.unixMode !== UNDEFINED_VALUE && ((fileEntry.unixMode & FILE_ATTR_UNIX_TYPE_MASK) == FILE_ATTR_UNIX_TYPE_DIR);
4879
4943
  const upperIsDir = ((unixExternalUpper & FILE_ATTR_UNIX_TYPE_MASK) == FILE_ATTR_UNIX_TYPE_DIR);
4880
4944
  Object.assign(fileEntry, {
4881
4945
  setuid,
4882
4946
  setgid,
4883
4947
  sticky,
4948
+ symlink,
4884
4949
  unixExternalUpper,
4885
4950
  internalFileAttribute: fileEntry.internalFileAttributes,
4886
4951
  externalFileAttribute: fileEntry.externalFileAttributes,
@@ -4946,6 +5011,10 @@ class ZipReader {
4946
5011
  }
4947
5012
 
4948
5013
  async close() {
5014
+ const { reader } = this;
5015
+ if (!reader.readUint8Array && reader.readable && !reader.readable.locked) {
5016
+ await reader.readable.cancel();
5017
+ }
4949
5018
  }
4950
5019
  }
4951
5020
 
@@ -5042,9 +5111,12 @@ let ZipEntry$1 = class ZipEntry {
5042
5111
  extraFieldLength,
5043
5112
  filenameLength
5044
5113
  } = localDirectory;
5045
- const checkAmbiguity = getStrictness(getOptionValue$1(zipEntry, options, OPTION_STRICTNESS), getOptionValue$1(zipEntry, options, OPTION_CHECK_AMBIGUITY)) == STRICTNESS_STRICT;
5114
+ const checkLocalDirectoryOption = getOptionValue$1(zipEntry, options, OPTION_CHECK_LOCAL_DIRECTORY);
5115
+ const entryStrictness = getStrictness(options, zipEntry.options);
5116
+ const checkLocalDirectory = getCheckLocalDirectory(checkLocalDirectoryOption, entryStrictness);
5117
+ const checkLocalFilename = getCheckLocalFilename(checkLocalDirectoryOption, entryStrictness);
5046
5118
  let rawLocalFilename = EMPTY_UINT8_ARRAY;
5047
- if (checkAmbiguity && (filenameLength || extraFieldLength)) {
5119
+ if (checkLocalFilename && (filenameLength || extraFieldLength)) {
5048
5120
  const trailingDataArray = await readUint8Array(reader, localHeaderOffset + HEADER_SIZE, filenameLength + extraFieldLength);
5049
5121
  rawLocalFilename = trailingDataArray.subarray(0, filenameLength);
5050
5122
  localDirectory.rawExtraField = trailingDataArray.subarray(filenameLength);
@@ -5053,17 +5125,26 @@ let ZipEntry$1 = class ZipEntry {
5053
5125
  await readUint8Array(reader, localHeaderOffset + HEADER_SIZE + filenameLength, extraFieldLength) :
5054
5126
  EMPTY_UINT8_ARRAY;
5055
5127
  }
5128
+ if (checkLocalFilename) {
5129
+ localDirectory.rawFilename = rawLocalFilename;
5130
+ }
5056
5131
  readCommonFooter(zipEntry, localDirectory, dataView, 4, true);
5057
- if (checkAmbiguity) {
5058
- checkLocalDirectory(zipEntry, localDirectory, rawLocalFilename);
5132
+ if (checkLocalDirectory) {
5133
+ validateLocalDirectory(zipEntry, localDirectory, rawLocalFilename, checkLocalFilename);
5059
5134
  }
5060
- const { lastAccessDate, creationDate } = localDirectory;
5135
+ const { lastAccessDate, creationDate, uid, gid } = localDirectory;
5061
5136
  if (lastAccessDate) {
5062
5137
  fileEntry.lastAccessDate = lastAccessDate;
5063
5138
  }
5064
5139
  if (creationDate) {
5065
5140
  fileEntry.creationDate = creationDate;
5066
5141
  }
5142
+ if (uid !== UNDEFINED_VALUE && fileEntry.uid === UNDEFINED_VALUE) {
5143
+ fileEntry.uid = uid;
5144
+ }
5145
+ if (gid !== UNDEFINED_VALUE && fileEntry.gid === UNDEFINED_VALUE) {
5146
+ fileEntry.gid = gid;
5147
+ }
5067
5148
  const encrypted = zipEntry.encrypted && localDirectory.encrypted && !passThrough;
5068
5149
  const zipCrypto = encrypted && !extraFieldAES;
5069
5150
  if (!passThrough) {
@@ -5170,7 +5251,7 @@ let ZipEntry$1 = class ZipEntry {
5170
5251
  throw error;
5171
5252
  }
5172
5253
  } finally {
5173
- const preventClose = getOptionValue$1(zipEntry, options, OPTION_PREVENT_CLOSE);
5254
+ const preventClose = !ownsWritable(writer) && getOptionValue$1(zipEntry, options, OPTION_PREVENT_CLOSE);
5174
5255
  if (!preventClose && writable && !writable.locked) {
5175
5256
  const writableWriter = writable.getWriter();
5176
5257
  if (abortError) {
@@ -5299,10 +5380,12 @@ function readCommonFooter(fileEntry, directory, dataView, offset, localDirectory
5299
5380
  directory.extraFieldNTFS = extraFieldNTFS;
5300
5381
  }
5301
5382
  const extraFieldUnix = extraField.get(EXTRAFIELD_TYPE_UNIX);
5383
+ let unixIdsRead;
5302
5384
  if (extraFieldUnix) {
5303
- readExtraFieldUnix(extraFieldUnix, directory, false);
5385
+ unixIdsRead = readExtraFieldUnix(extraFieldUnix, directory, false);
5304
5386
  directory.extraFieldUnix = extraFieldUnix;
5305
- } else {
5387
+ }
5388
+ if (!unixIdsRead) {
5306
5389
  const extraFieldInfoZip = extraField.get(EXTRAFIELD_TYPE_INFOZIP);
5307
5390
  if (extraFieldInfoZip) {
5308
5391
  readExtraFieldUnix(extraFieldInfoZip, directory, true);
@@ -5405,7 +5488,7 @@ function readExtraFieldNTFS(extraFieldNTFS, directory) {
5405
5488
  const creationDate = getDateNTFS(rawCreationDate);
5406
5489
  const extraFieldData = { lastModDate, lastAccessDate, creationDate };
5407
5490
  Object.assign(extraFieldNTFS, extraFieldData);
5408
- Object.assign(directory, extraFieldData);
5491
+ Object.assign(directory, extraFieldData, { rawLastAccessDate, rawCreationDate });
5409
5492
  }
5410
5493
  }
5411
5494
 
@@ -5414,8 +5497,8 @@ function readExtraFieldUnixDates(extraField, directory) {
5414
5497
  return;
5415
5498
  }
5416
5499
  const extraFieldView = getDataView(extraField.data);
5417
- const lastAccessDate = new Date(getUint32(extraFieldView, 0) * 1000);
5418
- const lastModDate = new Date(getUint32(extraFieldView, 4) * 1000);
5500
+ const lastAccessDate = new Date((getUint32(extraFieldView, 0) | 0) * 1000);
5501
+ const lastModDate = new Date((getUint32(extraFieldView, 4) | 0) * 1000);
5419
5502
  const extraFieldData = { lastAccessDate, lastModDate };
5420
5503
  if (extraField.data.length >= 12) {
5421
5504
  extraFieldData.uid = getUint16(extraFieldView, 8);
@@ -5449,6 +5532,7 @@ function readExtraFieldUnix(extraField, directory, isInfoZip) {
5449
5532
  if (gid !== UNDEFINED_VALUE) {
5450
5533
  directory.gid = gid;
5451
5534
  }
5535
+ return uid !== UNDEFINED_VALUE || gid !== UNDEFINED_VALUE;
5452
5536
  } catch {
5453
5537
  // ignored
5454
5538
  }
@@ -5521,26 +5605,25 @@ async function detectOverlappingEntry({
5521
5605
  }
5522
5606
  if (dataDescriptorLength) {
5523
5607
  const dataDescriptorArray = await readUint8Array(reader, dataOffset + compressedSize, dataDescriptorLength + DATA_DESCRIPTOR_RECORD_SIGNATURE_LENGTH);
5524
- const dataDescriptorSignature = dataDescriptorArray.length == dataDescriptorLength + DATA_DESCRIPTOR_RECORD_SIGNATURE_LENGTH &&
5525
- getUint32(getDataView(dataDescriptorArray), 0) == DATA_DESCRIPTOR_RECORD_SIGNATURE;
5526
- if (dataDescriptorSignature) {
5527
- const readCrc32 = getUint32(getDataView(dataDescriptorArray), 4);
5528
- let readCompressedSize;
5529
- let readUncompressedSize;
5530
- if (extraFieldZip64) {
5531
- readCompressedSize = getBigUint64(getDataView(dataDescriptorArray), 8);
5532
- readUncompressedSize = getBigUint64(getDataView(dataDescriptorArray), 16);
5533
- } else {
5534
- readCompressedSize = getUint32(getDataView(dataDescriptorArray), 8);
5535
- readUncompressedSize = getUint32(getDataView(dataDescriptorArray), 12);
5536
- }
5537
- const matchCrc32 = (fileEntry.encrypted && !fileEntry.zipCrypto) || readCrc32 == crc32;
5608
+ const dataDescriptorView = getDataView(dataDescriptorArray);
5609
+ let signature = dataDescriptorArray.length == dataDescriptorLength + DATA_DESCRIPTOR_RECORD_SIGNATURE_LENGTH &&
5610
+ getUint32(dataDescriptorView, 0) == DATA_DESCRIPTOR_RECORD_SIGNATURE;
5611
+ if (signature) {
5612
+ const signedDataDescriptor = readDataDescriptor(dataDescriptorView, DATA_DESCRIPTOR_RECORD_SIGNATURE_LENGTH, extraFieldZip64);
5613
+ const matchCrc32 = (fileEntry.encrypted && !fileEntry.zipCrypto) || signedDataDescriptor.crc32 == crc32;
5538
5614
  if (matchCrc32 &&
5539
- readCompressedSize == compressedSize &&
5540
- readUncompressedSize == uncompressedSize) {
5615
+ signedDataDescriptor.compressedSize == compressedSize &&
5616
+ signedDataDescriptor.uncompressedSize == uncompressedSize) {
5541
5617
  dataDescriptorLength += DATA_DESCRIPTOR_RECORD_SIGNATURE_LENGTH;
5618
+ } else {
5619
+ signature = false;
5542
5620
  }
5543
5621
  }
5622
+ if (dataDescriptorArray.length >= dataDescriptorLength) {
5623
+ const localDataDescriptor = readDataDescriptor(dataDescriptorView, signature ? DATA_DESCRIPTOR_RECORD_SIGNATURE_LENGTH : 0, extraFieldZip64);
5624
+ localDataDescriptor.signature = signature;
5625
+ fileEntry.localDirectory.dataDescriptor = localDataDescriptor;
5626
+ }
5544
5627
  }
5545
5628
  const range = {
5546
5629
  start: offset,
@@ -5557,6 +5640,20 @@ async function detectOverlappingEntry({
5557
5640
  readRanges.set(index, range);
5558
5641
  }
5559
5642
 
5643
+ function readDataDescriptor(dataDescriptorView, offset, extraFieldZip64) {
5644
+ const crc32 = getUint32(dataDescriptorView, offset);
5645
+ let compressedSize;
5646
+ let uncompressedSize;
5647
+ if (extraFieldZip64) {
5648
+ compressedSize = getBigUint64(dataDescriptorView, offset + 4);
5649
+ uncompressedSize = getBigUint64(dataDescriptorView, offset + 12);
5650
+ } else {
5651
+ compressedSize = getUint32(dataDescriptorView, offset + 4);
5652
+ uncompressedSize = getUint32(dataDescriptorView, offset + 8);
5653
+ }
5654
+ return { crc32, compressedSize, uncompressedSize };
5655
+ }
5656
+
5560
5657
  function getDiskOffset$1(reader, diskNumber) {
5561
5658
  return reader.getDiskOffset ? reader.getDiskOffset(diskNumber) : 0;
5562
5659
  }
@@ -5565,14 +5662,40 @@ function isStrictnessValue(value) {
5565
5662
  return value === STRICTNESS_STRICT || value === STRICTNESS_BALANCED || value === STRICTNESS_TOLERANT;
5566
5663
  }
5567
5664
 
5568
- function getStrictness(strictness, checkAmbiguity) {
5569
- if (strictness === UNDEFINED_VALUE) {
5570
- return checkAmbiguity ? STRICTNESS_STRICT : STRICTNESS_BALANCED;
5665
+ function getStrictness(options, inheritedOptions) {
5666
+ return resolveStrictness(options, resolveStrictness(inheritedOptions, STRICTNESS_BALANCED));
5667
+ }
5668
+
5669
+ function resolveStrictness(options, inheritedStrictness) {
5670
+ const strictness = options[OPTION_STRICTNESS];
5671
+ if (strictness !== UNDEFINED_VALUE) {
5672
+ if (!isStrictnessValue(strictness)) {
5673
+ throw new Error(ERR_INVALID_STRICTNESS);
5674
+ }
5675
+ return strictness;
5571
5676
  }
5572
- if (!isStrictnessValue(strictness)) {
5573
- throw new Error(ERR_INVALID_STRICTNESS);
5677
+ const checkAmbiguity = options[OPTION_CHECK_AMBIGUITY];
5678
+ if (checkAmbiguity === UNDEFINED_VALUE) {
5679
+ return inheritedStrictness;
5574
5680
  }
5575
- return strictness;
5681
+ if (checkAmbiguity) {
5682
+ return STRICTNESS_STRICT;
5683
+ }
5684
+ return inheritedStrictness == STRICTNESS_TOLERANT ? STRICTNESS_TOLERANT : STRICTNESS_BALANCED;
5685
+ }
5686
+
5687
+ function getCheckLocalDirectory(checkLocalDirectory, strictness) {
5688
+ if (checkLocalDirectory === UNDEFINED_VALUE) {
5689
+ return strictness != STRICTNESS_TOLERANT;
5690
+ }
5691
+ return Boolean(checkLocalDirectory);
5692
+ }
5693
+
5694
+ function getCheckLocalFilename(checkLocalFilename, strictness) {
5695
+ if (checkLocalFilename === UNDEFINED_VALUE) {
5696
+ return strictness == STRICTNESS_STRICT;
5697
+ }
5698
+ return Boolean(checkLocalFilename);
5576
5699
  }
5577
5700
 
5578
5701
  function getFilenameValidation(filenameValidation, strictness) {
@@ -5720,10 +5843,11 @@ async function readSignature(reader, view, anchoredOffset, signatureOffset, size
5720
5843
  return UNDEFINED_VALUE;
5721
5844
  }
5722
5845
 
5723
- function checkLocalDirectory(zipEntry, localDirectory, rawLocalFilename) {
5846
+ function validateLocalDirectory(zipEntry, localDirectory, rawLocalFilename, checkLocalFilename) {
5724
5847
  const { rawFilename } = zipEntry;
5725
- if (rawLocalFilename.length != rawFilename.length ||
5726
- rawLocalFilename.some((byteValue, indexByte) => byteValue != rawFilename[indexByte])) {
5848
+ if (checkLocalFilename &&
5849
+ (rawLocalFilename.length != rawFilename.length ||
5850
+ rawLocalFilename.some((byteValue, indexByte) => byteValue != rawFilename[indexByte]))) {
5727
5851
  throwAmbiguousArchive("mismatched local file header (filename)");
5728
5852
  }
5729
5853
  if ((localDirectory.rawBitFlag & BITFLAG_AMBIGUITY_MASK) != (zipEntry.rawBitFlag & BITFLAG_AMBIGUITY_MASK)) {
@@ -5841,11 +5965,13 @@ var zipReader = /*#__PURE__*/Object.freeze({
5841
5965
 
5842
5966
  const ERR_DUPLICATED_NAME = "File already exists";
5843
5967
  const ERR_INVALID_COMMENT = "Zip file comment exceeds 64KB";
5968
+ const ERR_INVALID_COMMENT_TYPE = "Invalid zip file comment (must be a Uint8Array)";
5844
5969
  const ERR_INVALID_ENTRY_COMMENT = "File entry comment exceeds 64KB";
5845
5970
  const ERR_INVALID_ENTRY_NAME = "File entry name exceeds 64KB";
5846
5971
  const ERR_INVALID_VERSION = "Version exceeds 65535";
5847
5972
  const ERR_INVALID_ENCRYPTION_STRENGTH = "The strength must equal 1, 2, or 3";
5848
5973
  const ERR_UNSUPPORTED_ENCRYPTION_USDZ = "Encryption is not supported in USDZ files";
5974
+ const ERR_UNSUPPORTED_ENCRYPTION_PASS_THROUGH = "Encryption is not supported when the 'passThrough' option is set";
5849
5975
  const ERR_INVALID_EXTRAFIELD_TYPE = "Extra field type exceeds 65535";
5850
5976
  const ERR_INVALID_EXTRAFIELD_DATA = "Extra field data exceeds 64KB";
5851
5977
  const ERR_UNSUPPORTED_COMPRESSION = "Compression method not supported";
@@ -5855,6 +5981,7 @@ const MIN_NTFS_TIME = BigInt(0);
5855
5981
  const MAX_NTFS_TIME = BigInt("0x7fffffffffffffff");
5856
5982
  const ERR_UNSUPPORTED_FORMAT = "Zip64 is not supported (set the 'zip64' option to 'true')";
5857
5983
  const ERR_UNDEFINED_UNCOMPRESSED_SIZE = "Undefined uncompressed size";
5984
+ const ERR_UNDETERMINED_SIZE = "Undetermined size";
5858
5985
  const ERR_UNDEFINED_READER = "Undefined reader";
5859
5986
  const ERR_ZIP_NOT_EMPTY = "Zip file not empty";
5860
5987
  const ERR_INVALID_UID = "Invalid uid (must be integer 0..2^32-1)";
@@ -5907,6 +6034,10 @@ class ZipWriter {
5907
6034
  }
5908
6035
  reader = new GenericReader(reader);
5909
6036
  await initStream(reader);
6037
+ if (reader.size === UNDEFINED_VALUE || !reader.readUint8Array) {
6038
+ reader = new BlobReader(await streamToBlob(reader.readable));
6039
+ await initStream(reader);
6040
+ }
5910
6041
  const { ZipReader } = await Promise.resolve().then(function () { return zipReader; });
5911
6042
  const zipReader$1 = new ZipReader(reader.readable);
5912
6043
  const entries = await zipReader$1.getEntries();
@@ -6055,6 +6186,9 @@ class ZipWriter {
6055
6186
  const zipWriter = this;
6056
6187
  const { pendingAddFileCalls, writer } = this;
6057
6188
  const { writable } = writer;
6189
+ if (!(comment instanceof Uint8Array)) {
6190
+ throw new Error(ERR_INVALID_COMMENT_TYPE);
6191
+ }
6058
6192
  if (getLength(comment) > MAX_16_BITS) {
6059
6193
  throw new Error(ERR_INVALID_COMMENT);
6060
6194
  }
@@ -6062,7 +6196,7 @@ class ZipWriter {
6062
6196
  await Promise.allSettled(Array.from(pendingAddFileCalls));
6063
6197
  }
6064
6198
  await closeFile(zipWriter, comment, options);
6065
- const preventClose = getOptionValue(zipWriter, options, OPTION_PREVENT_CLOSE);
6199
+ const preventClose = !ownsWritable(writer) && getOptionValue(zipWriter, options, OPTION_PREVENT_CLOSE);
6066
6200
  if (!preventClose) {
6067
6201
  await writable.getWriter().close();
6068
6202
  }
@@ -6151,8 +6285,6 @@ async function addFile(zipWriter, name, reader, options) {
6151
6285
  const diskOffset = getDiskOffset(zipWriter.writer);
6152
6286
  const diskNumber = getDiskNumber(zipWriter.writer);
6153
6287
  options = Object.assign({}, options, attributesInfo.resolvedOptions, metadataInfo.resolvedOptions, sizesInfo.resolvedOptions, {
6154
- internalFileAttribute: metadataInfo.resolvedOptions.internalFileAttributes,
6155
- externalFileAttribute: attributesInfo.resolvedOptions.externalFileAttributes,
6156
6288
  signature: options[PROPERTY_NAME_SIGNATURE],
6157
6289
  crc32: options.crc32 === UNDEFINED_VALUE ? options[PROPERTY_NAME_SIGNATURE] : options.crc32,
6158
6290
  offset: zipWriter.offset - diskOffset,
@@ -6166,14 +6298,20 @@ async function addFile(zipWriter, name, reader, options) {
6166
6298
  zipWriter.files.delete(name);
6167
6299
  throw error;
6168
6300
  }
6169
- Object.assign(fileEntry, { name, comment, extraField });
6301
+ Object.assign(fileEntry, {
6302
+ name,
6303
+ comment,
6304
+ extraField,
6305
+ [PROPERTY_NAME_DEPRECATED_INTERNAL_FILE_ATTRIBUTES]: fileEntry.internalFileAttributes,
6306
+ [PROPERTY_NAME_DEPRECATED_EXTERNAL_FILE_ATTRIBUTES]: fileEntry.externalFileAttributes
6307
+ });
6170
6308
  return new Entry(fileEntry);
6171
6309
  }
6172
6310
 
6173
6311
  function resolveAttributes(zipWriter, name, options) {
6174
6312
  name = name.trim();
6175
6313
  let msDosCompatible = getOptionValue(zipWriter, options, PROPERTY_NAME_MS_DOS_COMPATIBLE);
6176
- let versionMadeBy = getOptionValue(zipWriter, options, PROPERTY_NAME_VERSION_MADE_BY, msDosCompatible ? 20 : 768);
6314
+ let versionMadeBy = getOptionValue(zipWriter, options, PROPERTY_NAME_VERSION_MADE_BY, msDosCompatible ? VERSION_MADE_BY_MSDOS : VERSION_MADE_BY_UNIX);
6177
6315
  const executable = getOptionValue(zipWriter, options, PROPERTY_NAME_EXECUTABLE);
6178
6316
  const uid = getNumberOptionValue(zipWriter, options, PROPERTY_NAME_UID);
6179
6317
  const gid = getNumberOptionValue(zipWriter, options, PROPERTY_NAME_GID);
@@ -6207,7 +6345,7 @@ function resolveAttributes(zipWriter, name, options) {
6207
6345
  const hasMsDosProvided = msdosAttributesRaw !== UNDEFINED_VALUE || msdosAttributes !== UNDEFINED_VALUE;
6208
6346
  if (hasUnixMetadata) {
6209
6347
  msDosCompatible = false;
6210
- versionMadeBy = (versionMadeBy & MAX_16_BITS) | (3 << 8);
6348
+ versionMadeBy = (versionMadeBy & MAX_8_BITS) | VERSION_MADE_BY_UNIX;
6211
6349
  } else if (hasMsDosProvided) {
6212
6350
  msDosCompatible = true;
6213
6351
  versionMadeBy = (versionMadeBy & MAX_8_BITS);
@@ -6221,7 +6359,7 @@ function resolveAttributes(zipWriter, name, options) {
6221
6359
  if (versionMadeBy > MAX_16_BITS) {
6222
6360
  throw new Error(ERR_INVALID_VERSION);
6223
6361
  }
6224
- let externalFileAttributes = getOptionValue(zipWriter, options, PROPERTY_NAME_EXTERNAL_FILE_ATTRIBUTES);
6362
+ let externalFileAttributes = getAliasedOptionValue(zipWriter, options, PROPERTY_NAME_EXTERNAL_FILE_ATTRIBUTES, PROPERTY_NAME_DEPRECATED_EXTERNAL_FILE_ATTRIBUTES);
6225
6363
  const externalFileAttributesProvided = externalFileAttributes !== UNDEFINED_VALUE;
6226
6364
  if (!externalFileAttributesProvided) {
6227
6365
  externalFileAttributes = 0;
@@ -6247,11 +6385,10 @@ function resolveAttributes(zipWriter, name, options) {
6247
6385
  externalFileAttributes = FILE_ATTR_UNIX_DEFAULT_MASK << 16;
6248
6386
  }
6249
6387
  }
6250
- let unixExternalUpper;
6251
6388
  if (!msDosCompatible) {
6252
6389
  const unixModeProvided = unixMode !== UNDEFINED_VALUE || Boolean(setuid || setgid || sticky);
6253
- unixExternalUpper = (externalFileAttributes >> 16) & MAX_16_BITS;
6254
- unixMode = unixMode === UNDEFINED_VALUE ? unixExternalUpper : (unixMode & MAX_16_BITS);
6390
+ const defaultUnixMode = (externalFileAttributes >> 16) & MAX_16_BITS;
6391
+ unixMode = unixMode === UNDEFINED_VALUE ? defaultUnixMode : (unixMode & MAX_16_BITS);
6255
6392
  if (setuid) {
6256
6393
  unixMode |= FILE_ATTR_UNIX_SETUID_MASK;
6257
6394
  } else {
@@ -6269,7 +6406,9 @@ function resolveAttributes(zipWriter, name, options) {
6269
6406
  }
6270
6407
  if (!externalFileAttributesProvided || unixModeProvided) {
6271
6408
  if (directory) {
6272
- unixMode |= FILE_ATTR_UNIX_TYPE_DIR;
6409
+ unixMode = (unixMode & ~FILE_ATTR_UNIX_TYPE_MASK) | FILE_ATTR_UNIX_TYPE_DIR;
6410
+ } else if (!(unixMode & FILE_ATTR_UNIX_TYPE_MASK)) {
6411
+ unixMode |= FILE_ATTR_UNIX_TYPE_FILE;
6273
6412
  }
6274
6413
  externalFileAttributes = ((unixMode & MAX_16_BITS) << 16) | (externalFileAttributes & MAX_16_BITS);
6275
6414
  }
@@ -6278,17 +6417,20 @@ function resolveAttributes(zipWriter, name, options) {
6278
6417
  if (hasMsDosProvided) {
6279
6418
  externalFileAttributes = (externalFileAttributes & MAX_32_BITS) | (msdosAttributesRaw & MAX_8_BITS);
6280
6419
  }
6420
+ const unixExternalUpper = (externalFileAttributes >> 16) & MAX_16_BITS;
6421
+ const symlink = unixMode !== UNDEFINED_VALUE && ((unixMode & FILE_ATTR_UNIX_TYPE_MASK) == FILE_ATTR_UNIX_TYPE_SYMLINK);
6281
6422
  return {
6282
6423
  name,
6283
6424
  resolvedOptions: {
6284
6425
  versionMadeBy,
6285
- msDosCompatible,
6426
+ msDosCompatible: Boolean(msDosCompatible),
6286
6427
  externalFileAttributes,
6287
6428
  unixExternalUpper,
6288
6429
  uid,
6289
6430
  gid,
6290
6431
  unixMode,
6291
6432
  unixExtraFieldType,
6433
+ symlink,
6292
6434
  setuid,
6293
6435
  setgid,
6294
6436
  sticky,
@@ -6322,15 +6464,12 @@ function resolveMetadata(zipWriter, name, options) {
6322
6464
  const lastModDate = getOptionValue(zipWriter, options, PROPERTY_NAME_LAST_MODIFICATION_DATE, new Date());
6323
6465
  const lastAccessDate = getOptionValue(zipWriter, options, PROPERTY_NAME_LAST_ACCESS_DATE);
6324
6466
  const creationDate = getOptionValue(zipWriter, options, PROPERTY_NAME_CREATION_DATE);
6325
- const internalFileAttributes = getOptionValue(zipWriter, options, PROPERTY_NAME_INTERNAL_FILE_ATTRIBUTES, 0);
6467
+ const internalFileAttributes = getAliasedOptionValue(zipWriter, options, PROPERTY_NAME_INTERNAL_FILE_ATTRIBUTES, PROPERTY_NAME_DEPRECATED_INTERNAL_FILE_ATTRIBUTES, 0);
6326
6468
  const passThrough = getOptionValue(zipWriter, options, OPTION_PASS_THROUGH);
6327
- let password, rawPassword;
6328
- if (!passThrough) {
6329
- password = getOptionValue(zipWriter, options, OPTION_PASSWORD);
6330
- rawPassword = getOptionValue(zipWriter, options, OPTION_RAW_PASSWORD);
6331
- if ((password && typeof password != STRING_TYPE) || (rawPassword && !(rawPassword instanceof Uint8Array))) {
6332
- throw new Error(ERR_INVALID_PASSWORD_TYPE);
6333
- }
6469
+ const password = getOptionValue(zipWriter, options, OPTION_PASSWORD);
6470
+ const rawPassword = getOptionValue(zipWriter, options, OPTION_RAW_PASSWORD);
6471
+ if ((password && typeof password != STRING_TYPE) || (rawPassword && !(rawPassword instanceof Uint8Array))) {
6472
+ throw new Error(ERR_INVALID_PASSWORD_TYPE);
6334
6473
  }
6335
6474
  const encryptionStrength = getNumberOptionValue(zipWriter, options, OPTION_ENCRYPTION_STRENGTH, 3);
6336
6475
  const zipCrypto = getOptionValue(zipWriter, options, PROPERTY_NAME_ZIPCRYPTO);
@@ -6443,14 +6582,24 @@ function serializeExtraField(extraField) {
6443
6582
  }
6444
6583
 
6445
6584
  async function resolveSizes(zipWriter, reader, { resolvedOptions: metadata }, options) {
6585
+ if (metadata.passThrough && !reader && !getOptionValue(zipWriter, options, PROPERTY_NAME_DIRECTORY)) {
6586
+ throw new Error(ERR_UNDEFINED_READER);
6587
+ }
6588
+ let contentSize;
6589
+ if (reader) {
6590
+ reader = new GenericReader(reader);
6591
+ await initStream(reader);
6592
+ ({ size: contentSize } = reader);
6593
+ }
6594
+ return Object.assign({ reader }, resolveEntrySizes(zipWriter, Boolean(reader), contentSize, metadata, options));
6595
+ }
6596
+
6597
+ function resolveEntrySizes(zipWriter, hasContent, contentSize, metadata, options) {
6446
6598
  const { passThrough, zipCrypto, password, rawPassword, encryptionStrength } = metadata;
6447
6599
  let { dataDescriptor, zip64, level, compressionMethod } = metadata;
6448
6600
  let maximumCompressedSize = 0;
6449
6601
  let uncompressedSize = 0;
6450
- if (passThrough) {
6451
- if (!reader) {
6452
- throw new Error(ERR_UNDEFINED_READER);
6453
- }
6602
+ if (passThrough && hasContent) {
6454
6603
  uncompressedSize = options[PROPERTY_NAME_UNCOMPRESSED_SIZE];
6455
6604
  if (uncompressedSize === UNDEFINED_VALUE) {
6456
6605
  throw new Error(ERR_UNDEFINED_UNCOMPRESSED_SIZE);
@@ -6458,29 +6607,30 @@ async function resolveSizes(zipWriter, reader, { resolvedOptions: metadata }, op
6458
6607
  }
6459
6608
  const zip64Enabled = zip64 === true;
6460
6609
  const encrypted = getOptionValue(zipWriter, options, PROPERTY_NAME_ENCRYPTED);
6461
- const encryptedEntry = Boolean(reader) && (Boolean((password && getLength(password)) || (rawPassword && getLength(rawPassword))) || (passThrough && encrypted));
6462
- if (!reader) {
6610
+ if (hasContent && passThrough && !encrypted && getLength(password, rawPassword)) {
6611
+ throw new Error(ERR_UNSUPPORTED_ENCRYPTION_PASS_THROUGH);
6612
+ }
6613
+ const encryptedEntry = hasContent && (Boolean((password && getLength(password)) || (rawPassword && getLength(rawPassword))) || (passThrough && encrypted));
6614
+ if (!hasContent) {
6463
6615
  level = 0;
6464
6616
  compressionMethod = COMPRESSION_METHOD_STORE;
6465
6617
  }
6466
6618
  const encryptionOverhead = encryptedEntry ? (zipCrypto ? 12 : 16 + encryptionStrength * 4) : 0;
6467
- if (reader) {
6468
- reader = new GenericReader(reader);
6469
- await initStream(reader);
6619
+ if (hasContent) {
6470
6620
  if (!passThrough) {
6471
- if (reader.size === UNDEFINED_VALUE) {
6621
+ if (contentSize === UNDEFINED_VALUE) {
6472
6622
  dataDescriptor = true;
6473
6623
  if (zip64 || zip64 === UNDEFINED_VALUE) {
6474
6624
  zip64 = true;
6475
6625
  uncompressedSize = maximumCompressedSize = MAX_32_BITS + 1;
6476
6626
  }
6477
6627
  } else {
6478
- options.uncompressedSize = uncompressedSize = reader.size;
6479
- maximumCompressedSize = getMaximumCompressedSize(uncompressedSize) + encryptionOverhead;
6628
+ options.uncompressedSize = uncompressedSize = contentSize;
6629
+ maximumCompressedSize = (isCompressed(compressionMethod, level) ? getMaximumCompressedSize(uncompressedSize) : uncompressedSize) + encryptionOverhead;
6480
6630
  }
6481
6631
  } else {
6482
6632
  options.uncompressedSize = uncompressedSize;
6483
- maximumCompressedSize = getMaximumCompressedSize(uncompressedSize) + encryptionOverhead;
6633
+ maximumCompressedSize = contentSize === UNDEFINED_VALUE ? getMaximumCompressedSize(uncompressedSize) + encryptionOverhead : contentSize;
6484
6634
  }
6485
6635
  }
6486
6636
  const zip64UncompressedSize = zip64Enabled || uncompressedSize >= MAX_32_BITS;
@@ -6494,7 +6644,7 @@ async function resolveSizes(zipWriter, reader, { resolvedOptions: metadata }, op
6494
6644
  }
6495
6645
  zip64 = zip64 || false;
6496
6646
  return {
6497
- reader,
6647
+ maximumCompressedSize,
6498
6648
  resolvedOptions: {
6499
6649
  dataDescriptor,
6500
6650
  zip64,
@@ -6508,6 +6658,81 @@ async function resolveSizes(zipWriter, reader, { resolvedOptions: metadata }, op
6508
6658
  };
6509
6659
  }
6510
6660
 
6661
+ async function getEntriesSize(writerOptions, entries, writeOrderGuaranteed, comment) {
6662
+ const zipWriter = { options: writerOptions, config: getConfiguration() };
6663
+ if (writerOptions[OPTION_SIGN_CENTRAL_DIRECTORY]) {
6664
+ throw new Error(ERR_UNDETERMINED_SIZE);
6665
+ }
6666
+ if (comment !== UNDEFINED_VALUE && !(comment instanceof Uint8Array)) {
6667
+ throw new Error(ERR_INVALID_COMMENT_TYPE);
6668
+ }
6669
+ const commentLength = getLength(comment);
6670
+ if (commentLength > MAX_16_BITS) {
6671
+ throw new Error(ERR_INVALID_COMMENT);
6672
+ }
6673
+ const usdz = writerOptions[OPTION_USDZ];
6674
+ const files = new Map();
6675
+ let layoutDependsOnWriteOrder = Boolean(usdz);
6676
+ let offset = 0;
6677
+ for (const entry of entries) {
6678
+ let { name } = entry;
6679
+ const { size } = entry;
6680
+ const options = Object.assign({}, entry.options);
6681
+ name = name.trim();
6682
+ if (getOptionValue(zipWriter, options, PROPERTY_NAME_DIRECTORY) && !name.endsWith(DIRECTORY_SIGNATURE)) {
6683
+ name += DIRECTORY_SIGNATURE;
6684
+ }
6685
+ const attributesInfo = resolveAttributes(zipWriter, name, options);
6686
+ ({ name } = attributesInfo);
6687
+ const { resolvedOptions: metadata } = resolveMetadata(zipWriter, name, options);
6688
+ if (metadata.level != 0 && metadata.compressionMethod === UNDEFINED_VALUE &&
6689
+ !metadata.passThrough && !(await supportsDeflate(zipWriter.config))) {
6690
+ metadata.level = 0;
6691
+ }
6692
+ const hasContent = !getOptionValue(zipWriter, options, PROPERTY_NAME_DIRECTORY);
6693
+ if (hasContent && size === UNDEFINED_VALUE) {
6694
+ throw new Error(ERR_UNDETERMINED_SIZE);
6695
+ }
6696
+ const { maximumCompressedSize, resolvedOptions: sizes } = resolveEntrySizes(zipWriter, hasContent, size, metadata, options);
6697
+ if (hasContent && !metadata.passThrough && isCompressed(sizes.compressionMethod, sizes.level)) {
6698
+ throw new Error(ERR_UNDETERMINED_SIZE);
6699
+ }
6700
+ const entryOptions = Object.assign({}, options, attributesInfo.resolvedOptions, metadata, sizes);
6701
+ const headerInfo = getHeaderInfo(entryOptions);
6702
+ const dataDescriptorInfo = getDataDescriptorInfo(entryOptions);
6703
+ const entryInfo = {
6704
+ headerInfo,
6705
+ metadataSize: getLength(headerInfo.localHeaderArray, dataDescriptorInfo.dataDescriptorArray)
6706
+ };
6707
+ if (usdz) {
6708
+ appendExtraFieldUSDZ(entryInfo, offset);
6709
+ }
6710
+ const compressedSize = hasContent ? maximumCompressedSize : 0;
6711
+ if (offset >= MAX_32_BITS) {
6712
+ layoutDependsOnWriteOrder = true;
6713
+ }
6714
+ files.set(name, Object.assign({}, entryOptions, headerInfo, {
6715
+ offset,
6716
+ diskNumberStart: 0,
6717
+ compressedSize
6718
+ }));
6719
+ offset += entryInfo.metadataSize + compressedSize;
6720
+ }
6721
+ if (layoutDependsOnWriteOrder && !writeOrderGuaranteed) {
6722
+ throw new Error(ERR_UNDETERMINED_SIZE);
6723
+ }
6724
+ const directoryDataLength = createDirectoryRecords(files);
6725
+ let zip64 = getOptionValue(zipWriter, writerOptions, PROPERTY_NAME_ZIP64);
6726
+ if (offset >= MAX_32_BITS || directoryDataLength >= MAX_32_BITS || files.size >= MAX_16_BITS) {
6727
+ if (zip64 === false) {
6728
+ throw new Error(ERR_UNSUPPORTED_FORMAT);
6729
+ } else {
6730
+ zip64 = true;
6731
+ }
6732
+ }
6733
+ return offset + directoryDataLength + commentLength + (zip64 ? ZIP64_END_OF_CENTRAL_DIR_TOTAL_LENGTH : END_OF_CENTRAL_DIR_LENGTH);
6734
+ }
6735
+
6511
6736
  async function getFileEntry(zipWriter, name, reader, entryInfo, options) {
6512
6737
  const {
6513
6738
  files,
@@ -6722,6 +6947,7 @@ async function createFileEntry(reader, writer, { diskNumberStart, lock }, entryI
6722
6947
  uid,
6723
6948
  gid,
6724
6949
  unixMode,
6950
+ symlink,
6725
6951
  setuid,
6726
6952
  setgid,
6727
6953
  sticky,
@@ -6758,6 +6984,7 @@ async function createFileEntry(reader, writer, { diskNumberStart, lock }, entryI
6758
6984
  uid,
6759
6985
  gid,
6760
6986
  unixMode,
6987
+ symlink: Boolean(symlink),
6761
6988
  setuid,
6762
6989
  setgid,
6763
6990
  sticky,
@@ -6838,8 +7065,8 @@ async function createFileEntry(reader, writer, { diskNumberStart, lock }, entryI
6838
7065
  rawLastModDate,
6839
7066
  creationDate,
6840
7067
  lastAccessDate,
6841
- encrypted,
6842
- zipCrypto,
7068
+ encrypted: Boolean(encrypted),
7069
+ zipCrypto: Boolean(zipCrypto),
6843
7070
  size: metadataSize + compressedSize,
6844
7071
  compressionMethod,
6845
7072
  version,
@@ -6879,9 +7106,7 @@ function getHeaderInfo(options) {
6879
7106
  crc32
6880
7107
  } = options;
6881
7108
  let { version, compressionMethod } = options;
6882
- const compressed = !directory && (compressionMethod === UNDEFINED_VALUE
6883
- ? (level === UNDEFINED_VALUE || level > 0)
6884
- : compressionMethod !== COMPRESSION_METHOD_STORE);
7109
+ const compressed = !directory && isCompressed(compressionMethod, level);
6885
7110
  let rawLocalExtraFieldZip64;
6886
7111
  const uncompressedFile = passThrough || !compressed;
6887
7112
  const zip64ExtraFieldComplete = zip64 && (options.bufferedWrite || !dataDescriptor || ((!zip64UncompressedSize && !zip64CompressedSize) || uncompressedFile));
@@ -7568,6 +7793,16 @@ function getOptionValue(zipWriter, options, name, defaultValue) {
7568
7793
  return result === UNDEFINED_VALUE ? defaultValue : result;
7569
7794
  }
7570
7795
 
7796
+ function getAliasedOptionValue(zipWriter, options, name, deprecatedName, defaultValue) {
7797
+ const value = getAliasedValue(options, name, deprecatedName);
7798
+ const result = value === UNDEFINED_VALUE ? getAliasedValue(zipWriter.options, name, deprecatedName) : value;
7799
+ return result === UNDEFINED_VALUE ? defaultValue : result;
7800
+ }
7801
+
7802
+ function getAliasedValue(options, name, deprecatedName) {
7803
+ return options[name] === UNDEFINED_VALUE ? options[deprecatedName] : options[name];
7804
+ }
7805
+
7571
7806
  function getNumberOptionValue(zipWriter, options, name, defaultValue) {
7572
7807
  return toNumber(getOptionValue(zipWriter, options, name, defaultValue));
7573
7808
  }
@@ -7580,6 +7815,12 @@ function getMaximumCompressedSize(uncompressedSize) {
7580
7815
  return uncompressedSize + (5 * (Math.floor(uncompressedSize / 16383) + 1));
7581
7816
  }
7582
7817
 
7818
+ function isCompressed(compressionMethod, level) {
7819
+ return compressionMethod === UNDEFINED_VALUE
7820
+ ? (level === UNDEFINED_VALUE || level > 0)
7821
+ : compressionMethod !== COMPRESSION_METHOD_STORE;
7822
+ }
7823
+
7583
7824
  function setUint8(view, offset, value) {
7584
7825
  view.setUint8(offset, value);
7585
7826
  }
@@ -8228,6 +8469,7 @@ setDefaultConfiguration({
8228
8469
 
8229
8470
  const ERR_ENTRY_EXISTS = "Entry filename already exists";
8230
8471
  const ERR_READABLE_CONSUMED = "Readable stream already consumed";
8472
+ const ERR_INVALID_PASS_THROUGH = "Invalid passThrough option (use readerOptions.passThrough or set uncompressedSize for each entry)";
8231
8473
  const ERR_ABORT_EXPORT = "zipjs-abort-export";
8232
8474
  const ERR_ABORTED = "The operation was aborted";
8233
8475
  const ABORT_ERROR_NAME = "AbortError";
@@ -8265,6 +8507,7 @@ class ZipEntry {
8265
8507
  parent,
8266
8508
  children: [],
8267
8509
  uncompressedSize: params.uncompressedSize || 0,
8510
+ undeterminedSize: params.undeterminedSize || params.uncompressedSize === UNDEFINED_VALUE,
8268
8511
  passThrough: params.passThrough
8269
8512
  });
8270
8513
  if (parent || !fs.root) {
@@ -8332,16 +8575,17 @@ class ZipFileEntry extends ZipEntry {
8332
8575
 
8333
8576
  async getData(writer, options = {}) {
8334
8577
  const zipEntry = this;
8335
- if (!writer || (writer.constructor == zipEntry.Writer && zipEntry.data)) {
8578
+ if (!writer || (writer.constructor == zipEntry.Writer && zipEntry.data && keepsContentType(writer, zipEntry.data))) {
8336
8579
  return zipEntry.data;
8337
8580
  } else {
8338
8581
  const reader = zipEntry.reader = createReader(zipEntry.Reader, zipEntry.data, options);
8339
- const uncompressedSize = zipEntry.data ? zipEntry.data.uncompressedSize : reader.size;
8340
- await Promise.all([initStream(reader), initStream(writer, uncompressedSize)]);
8341
- const { readable } = reader;
8582
+ const dataSize = zipEntry.uncompressedSize || reader.size;
8583
+ await Promise.all([initStream(reader), initStream(writer, dataSize)]);
8342
8584
  const { signal } = options;
8585
+ const readable = createProgressReadable(zipEntry, reader, options, signal);
8586
+ const preventClose = !ownsWritable(writer) && Boolean(options.preventClose);
8343
8587
  zipEntry.uncompressedSize = reader.size;
8344
- await toCompatibleReadable(readable).pipeTo(toCompatibleWritable(writer.writable), { signal });
8588
+ await toCompatibleReadable(readable).pipeTo(toCompatibleWritable(writer.writable), { signal, preventClose, preventAbort: preventClose });
8345
8589
  return writer.getData ? writer.getData() : writer.writable;
8346
8590
  }
8347
8591
  }
@@ -8472,7 +8716,7 @@ class ZipDirectoryEntry extends ZipEntry {
8472
8716
  Reader: TextReader,
8473
8717
  Writer: TextWriter,
8474
8718
  options,
8475
- uncompressedSize: text.length
8719
+ uncompressedSize: getTextSize(text)
8476
8720
  });
8477
8721
  }
8478
8722
 
@@ -8601,10 +8845,16 @@ class ZipDirectoryEntry extends ZipEntry {
8601
8845
  }
8602
8846
 
8603
8847
  async importZip(reader, options = {}) {
8604
- await initStream(reader);
8605
- const zipReader = new ZipReader(reader, options);
8848
+ let zipReader;
8849
+ if (reader && typeof reader.getEntries == FUNCTION_TYPE) {
8850
+ zipReader = reader;
8851
+ options = Object.assign({}, zipReader.options, options);
8852
+ } else {
8853
+ await initStream(reader);
8854
+ zipReader = new ZipReader(reader, options);
8855
+ }
8606
8856
  const importedEntries = [];
8607
- const entries = await zipReader.getEntries();
8857
+ const entries = await zipReader.getEntries(options);
8608
8858
  for (const entry of entries) {
8609
8859
  let parent = this;
8610
8860
  try {
@@ -8626,7 +8876,7 @@ class ZipDirectoryEntry extends ZipEntry {
8626
8876
  importedEntries.push(addChild(parent, name, {
8627
8877
  data: entry,
8628
8878
  Reader: getZipBlobReader(Object.assign({}, options)),
8629
- uncompressedSize: entry.uncompressedSize,
8879
+ uncompressedSize: options.passThrough ? entry.compressedSize : entry.uncompressedSize,
8630
8880
  passThrough: options.passThrough
8631
8881
  }));
8632
8882
  } else {
@@ -8668,11 +8918,25 @@ class ZipDirectoryEntry extends ZipEntry {
8668
8918
  }
8669
8919
  const [readers] = await Promise.all([initReaders(zipEntry, options.readerOptions), initStream(writer)]);
8670
8920
  const zipWriter = new ZipWriter(writer, options);
8671
- await exportZip(zipWriter, zipEntry, getTotalSize([zipEntry], "uncompressedSize"), options, readers);
8672
- await zipWriter.close();
8921
+ await exportZip(zipWriter, zipEntry, getTotalSize([zipEntry], getUncompressedSize), options, readers);
8922
+ await zipWriter.close(options.globalComment);
8673
8923
  return writer.getData ? writer.getData() : writer.writable;
8674
8924
  }
8675
8925
 
8926
+ getExportedSize(options = {}) {
8927
+ const zipEntry = this;
8928
+ options = Object.assign({}, options);
8929
+ if (options.bufferedWrite === UNDEFINED_VALUE) {
8930
+ options.bufferedWrite = true;
8931
+ }
8932
+ const writeOrderGuaranteed = !options.bufferedWrite ||
8933
+ (options.keepOrder !== false && zipEntry.children.every(child => !child.children.length));
8934
+ return getEntriesSize(options, Array.from(zipEntry.getChildren({ recursive: true }), child => {
8935
+ const { name, entryOptions } = getChildEntryOptions(child, zipEntry, options);
8936
+ return { name, size: child.directory ? 0 : getDeterminedSize(child, isPassThrough(child, options)), options: entryOptions };
8937
+ }), writeOrderGuaranteed, options.globalComment);
8938
+ }
8939
+
8676
8940
  getChildByName(name) {
8677
8941
  const children = this.children;
8678
8942
  for (let childIndex = 0; childIndex < children.length; childIndex++) {
@@ -8880,6 +9144,10 @@ class FS {
8880
9144
  return this.root.exportZip(writer, options);
8881
9145
  }
8882
9146
 
9147
+ getExportedSize(options) {
9148
+ return this.root.getExportedSize(options);
9149
+ }
9150
+
8883
9151
  isPasswordProtected() {
8884
9152
  return this.root.isPasswordProtected();
8885
9153
  }
@@ -8891,12 +9159,12 @@ class FS {
8891
9159
 
8892
9160
  const fs = { FS, ZipDirectoryEntry, ZipFileEntry };
8893
9161
 
8894
- function getTotalSize(entries, propertyName) {
9162
+ function getTotalSize(entries, getEntrySize) {
8895
9163
  let size = 0;
8896
9164
  const pendingEntries = Array.from(entries);
8897
9165
  while (pendingEntries.length) {
8898
9166
  const entry = pendingEntries.pop();
8899
- size += entry[propertyName] || 0;
9167
+ size += getEntrySize(entry) || 0;
8900
9168
  for (const child of entry.children) {
8901
9169
  pendingEntries.push(child);
8902
9170
  }
@@ -8904,6 +9172,15 @@ function getTotalSize(entries, propertyName) {
8904
9172
  return size;
8905
9173
  }
8906
9174
 
9175
+ function getUncompressedSize(entry) {
9176
+ return entry.uncompressedSize;
9177
+ }
9178
+
9179
+ function getExtractedSize(entry, passThrough) {
9180
+ const { data } = entry;
9181
+ return passThrough && data instanceof Entry ? data.compressedSize : entry.uncompressedSize;
9182
+ }
9183
+
8907
9184
  function getReadableReader(readable) {
8908
9185
  let consumed;
8909
9186
  return function () {
@@ -8926,10 +9203,17 @@ function getZipBlobReader(options) {
8926
9203
 
8927
9204
  async init() {
8928
9205
  const zipBlobReader = this;
8929
- zipBlobReader.size = zipBlobReader.entry.uncompressedSize;
8930
- const data = await zipBlobReader.entry.getData(new BlobWriter(), Object.assign({}, options, zipBlobReader.options));
9206
+ const readerOptions = Object.assign({}, options, zipBlobReader.options);
9207
+ const { checkOverlappingEntry, checkOverlappingEntryOnly } = readerOptions;
9208
+ const data = await zipBlobReader.entry.getData(new BlobWriter(), Object.assign(readerOptions, {
9209
+ checkPasswordOnly: false,
9210
+ checkOverlappingEntry: checkOverlappingEntryOnly || checkOverlappingEntry,
9211
+ checkOverlappingEntryOnly: false,
9212
+ preventClose: false
9213
+ }));
8931
9214
  zipBlobReader.data = data;
8932
9215
  zipBlobReader.blobReader = new BlobReader(data);
9216
+ zipBlobReader.size = data.size;
8933
9217
  super.init();
8934
9218
  }
8935
9219
 
@@ -8943,6 +9227,30 @@ function createReader(Reader, data, options) {
8943
9227
  return Reader.prototype ? new Reader(data, options) : Reader(data, options);
8944
9228
  }
8945
9229
 
9230
+ function keepsContentType(writer, data) {
9231
+ const { contentType } = writer;
9232
+ if (contentType === UNDEFINED_VALUE) {
9233
+ return true;
9234
+ } else if (writer.constructor == BlobWriter) {
9235
+ return data.type == contentType;
9236
+ } else if (writer.constructor == Data64URIWriter) {
9237
+ return data.startsWith(writer.data);
9238
+ } else {
9239
+ return true;
9240
+ }
9241
+ }
9242
+
9243
+ function createProgressReadable(zipEntry, reader, options, signal) {
9244
+ const { onstart, onprogress, onend } = options;
9245
+ const { readable } = reader;
9246
+ const coreReaderReportsProgress = zipEntry.data instanceof Entry;
9247
+ if (coreReaderReportsProgress || (!onstart && !onprogress && !onend)) {
9248
+ return readable;
9249
+ } else {
9250
+ return toCompatibleReadable(readable).pipeThrough(new ProgressWatcherStream({ onstart, onprogress, onend, size: reader.size }), { signal });
9251
+ }
9252
+ }
9253
+
8946
9254
  async function initReaders(entry, options) {
8947
9255
  const fileEntries = [];
8948
9256
  const pendingEntries = [entry];
@@ -8975,6 +9283,7 @@ async function initReaders(entry, options) {
8975
9283
  }
8976
9284
  if (reader.size !== UNDEFINED_VALUE) {
8977
9285
  child.uncompressedSize = reader.size;
9286
+ child.undeterminedSize = false;
8978
9287
  }
8979
9288
  }));
8980
9289
  return readers;
@@ -9024,6 +9333,90 @@ function aggregateEntryErrors(errors) {
9024
9333
  return error;
9025
9334
  }
9026
9335
 
9336
+ function getChildEntryOptions(child, selectedEntry, options) {
9337
+ const name = options.relativePath ? child.getRelativeName(selectedEntry) : child.getFullname();
9338
+ const childOptions = child.options || {};
9339
+ let zipEntryMetadata = {};
9340
+ let passThroughOptions = {};
9341
+ if (child.data instanceof Entry) {
9342
+ const {
9343
+ externalFileAttributes,
9344
+ versionMadeBy,
9345
+ comment,
9346
+ lastModDate,
9347
+ creationDate,
9348
+ lastAccessDate,
9349
+ uncompressedSize,
9350
+ encrypted,
9351
+ zipCrypto,
9352
+ crc32,
9353
+ compressionMethod,
9354
+ extraFieldAES,
9355
+ internalFileAttributes,
9356
+ extraField,
9357
+ uid,
9358
+ gid
9359
+ } = child.data;
9360
+ zipEntryMetadata = {
9361
+ externalFileAttributes,
9362
+ versionMadeBy,
9363
+ comment,
9364
+ lastModDate,
9365
+ creationDate,
9366
+ lastAccessDate,
9367
+ internalFileAttributes
9368
+ };
9369
+ const userExtraField = getUserExtraField(extraField);
9370
+ if (userExtraField) {
9371
+ zipEntryMetadata.extraField = userExtraField;
9372
+ }
9373
+ if (uid !== UNDEFINED_VALUE || gid !== UNDEFINED_VALUE) {
9374
+ Object.assign(zipEntryMetadata, {
9375
+ uid,
9376
+ gid,
9377
+ unixExtraFieldType: INFOZIP_EXTRA_FIELD_TYPE
9378
+ });
9379
+ }
9380
+ if (isPassThrough(child, options)) {
9381
+ let level, encryptionStrength;
9382
+ if (compressionMethod === 0) {
9383
+ level = 0;
9384
+ }
9385
+ if (extraFieldAES) {
9386
+ encryptionStrength = extraFieldAES.strength;
9387
+ }
9388
+ passThroughOptions = {
9389
+ passThrough: true,
9390
+ encrypted,
9391
+ zipCrypto,
9392
+ crc32,
9393
+ uncompressedSize,
9394
+ level,
9395
+ encryptionStrength,
9396
+ compressionMethod
9397
+ };
9398
+ }
9399
+ }
9400
+ const entryOptions = Object.assign({}, zipEntryMetadata, options, passThroughOptions, childOptions, { directory: child.directory });
9401
+ if (!child.directory && entryOptions.passThrough && entryOptions.uncompressedSize === UNDEFINED_VALUE) {
9402
+ throw new Error(ERR_INVALID_PASS_THROUGH);
9403
+ }
9404
+ return { name, entryOptions };
9405
+ }
9406
+
9407
+ function getDeterminedSize(child, passThrough) {
9408
+ const { reader } = child;
9409
+ if (reader && reader.size !== UNDEFINED_VALUE) {
9410
+ return reader.size;
9411
+ }
9412
+ return child.undeterminedSize ? UNDEFINED_VALUE : getExtractedSize(child, passThrough);
9413
+ }
9414
+
9415
+ function isPassThrough(child, options) {
9416
+ const { readerOptions } = options;
9417
+ return Boolean(!child.directory && (child.passThrough || (readerOptions && readerOptions.passThrough)));
9418
+ }
9419
+
9027
9420
  function getUserExtraField(extraField) {
9028
9421
  if (extraField) {
9029
9422
  const userExtraField = new Map();
@@ -9039,8 +9432,14 @@ function getUserExtraField(extraField) {
9039
9432
  }
9040
9433
 
9041
9434
  async function exportZip(zipWriter, entry, totalSize, options, readers) {
9435
+ const { onstart, onprogress, onend, onentryprogress } = options;
9042
9436
  const selectedEntry = entry;
9043
- const entryOffsets = new Map();
9437
+ const totalEntries = getTotalSize(entry.children, () => 1);
9438
+ let writtenSize = 0;
9439
+ let writtenEntries = 0;
9440
+ if (onstart) {
9441
+ await callHandler(onstart, totalSize);
9442
+ }
9044
9443
  if (options.bufferedWrite) {
9045
9444
  await processChildren(entry);
9046
9445
  } else {
@@ -9048,6 +9447,9 @@ async function exportZip(zipWriter, entry, totalSize, options, readers) {
9048
9447
  await addChild(child);
9049
9448
  }
9050
9449
  }
9450
+ if (onend) {
9451
+ await callHandler(onend, writtenSize);
9452
+ }
9051
9453
 
9052
9454
  async function processChildren(entry) {
9053
9455
  const results = await Promise.allSettled(entry.children.map(async child => {
@@ -9061,81 +9463,23 @@ async function exportZip(zipWriter, entry, totalSize, options, readers) {
9061
9463
  }
9062
9464
 
9063
9465
  async function addChild(child) {
9064
- const name = options.relativePath ? child.getRelativeName(selectedEntry) : child.getFullname();
9065
- const childOptions = child.options || {};
9066
- let zipEntryOptions = {};
9067
- if (child.data instanceof Entry) {
9068
- const {
9069
- externalFileAttributes,
9070
- versionMadeBy,
9071
- comment,
9072
- lastModDate,
9073
- creationDate,
9074
- lastAccessDate,
9075
- uncompressedSize,
9076
- encrypted,
9077
- zipCrypto,
9078
- crc32,
9079
- compressionMethod,
9080
- extraFieldAES,
9081
- internalFileAttributes,
9082
- extraField,
9083
- uid,
9084
- gid
9085
- } = child.data;
9086
- zipEntryOptions = {
9087
- externalFileAttributes,
9088
- versionMadeBy,
9089
- comment,
9090
- lastModDate,
9091
- creationDate,
9092
- lastAccessDate,
9093
- internalFileAttributes
9094
- };
9095
- const userExtraField = getUserExtraField(extraField);
9096
- if (userExtraField) {
9097
- zipEntryOptions.extraField = userExtraField;
9098
- }
9099
- if (uid !== UNDEFINED_VALUE || gid !== UNDEFINED_VALUE) {
9100
- Object.assign(zipEntryOptions, {
9101
- uid,
9102
- gid,
9103
- unixExtraFieldType: options.unixExtraFieldType || INFOZIP_EXTRA_FIELD_TYPE
9104
- });
9105
- }
9106
- if (child.passThrough) {
9107
- let level, encryptionStrength;
9108
- if (compressionMethod === 0) {
9109
- level = 0;
9110
- }
9111
- if (extraFieldAES) {
9112
- encryptionStrength = extraFieldAES.strength;
9113
- }
9114
- zipEntryOptions = Object.assign(zipEntryOptions, {
9115
- passThrough: true,
9116
- encrypted,
9117
- zipCrypto,
9118
- crc32,
9119
- uncompressedSize,
9120
- level,
9121
- encryptionStrength,
9122
- compressionMethod
9123
- });
9124
- }
9125
- }
9126
- await zipWriter.add(name, readers.get(child), Object.assign({}, options, zipEntryOptions, childOptions, {
9127
- directory: child.directory,
9466
+ const { name, entryOptions } = getChildEntryOptions(child, selectedEntry, options);
9467
+ let entryWrittenSize = 0;
9468
+ const entryMetadata = await zipWriter.add(name, readers.get(child), Object.assign(entryOptions, {
9469
+ onstart: UNDEFINED_VALUE,
9470
+ onend: UNDEFINED_VALUE,
9128
9471
  onprogress: async indexProgress => {
9129
- if (options.onprogress) {
9130
- entryOffsets.set(name, indexProgress);
9131
- try {
9132
- await options.onprogress(Array.from(entryOffsets.values()).reduce((previousValue, currentValue) => previousValue + currentValue), totalSize);
9133
- } catch {
9134
- // ignored
9135
- }
9472
+ writtenSize += indexProgress - entryWrittenSize;
9473
+ entryWrittenSize = indexProgress;
9474
+ if (onprogress) {
9475
+ await callHandler(onprogress, writtenSize, totalSize);
9136
9476
  }
9137
9477
  }
9138
9478
  }));
9479
+ writtenEntries++;
9480
+ if (onentryprogress) {
9481
+ await callHandler(onentryprogress, writtenEntries, totalEntries, entryMetadata);
9482
+ }
9139
9483
  }
9140
9484
  }
9141
9485
 
@@ -9163,7 +9507,7 @@ function addFileSystemHandle(zipEntry, handle, options) {
9163
9507
  })
9164
9508
  );
9165
9509
  } else if (handle.kind == "directory") {
9166
- const directoryEntry = parentEntry.addDirectory(handle.name);
9510
+ const directoryEntry = parentEntry.addDirectory(handle.name, options);
9167
9511
  addedEntries.push(directoryEntry);
9168
9512
  for await (const childHandle of handle.values()) {
9169
9513
  await addFile(directoryEntry, childHandle, addedEntries, entryName);
@@ -9185,15 +9529,29 @@ function addFileSystemHandle(zipEntry, handle, options) {
9185
9529
  }
9186
9530
 
9187
9531
  async function exportFileSystemHandle(zipEntry, directoryHandle, options) {
9188
- const totalSize = getTotalSize([zipEntry], "uncompressedSize");
9189
- const writtenSizes = new Map();
9532
+ const { onstart, onprogress, onend } = options;
9190
9533
  const abortController = new AbortController();
9191
9534
  const { signal } = abortController;
9192
9535
  const releaseSignal = forwardAbort(options.signal, abortController);
9536
+ const getDataOptions = Object.assign({}, options, options.readerOptions, {
9537
+ signal,
9538
+ onstart: UNDEFINED_VALUE,
9539
+ onprogress: UNDEFINED_VALUE,
9540
+ onend: UNDEFINED_VALUE,
9541
+ preventClose: false
9542
+ });
9543
+ const totalSize = getTotalSize([zipEntry], entry => getExtractedSize(entry, getDataOptions.passThrough));
9193
9544
  const exportedEntryNames = [];
9194
9545
  let exportAborted = false;
9546
+ let writtenSize = 0;
9195
9547
  try {
9548
+ if (onstart) {
9549
+ await callHandler(onstart, totalSize);
9550
+ }
9196
9551
  await exportChildren(zipEntry, directoryHandle);
9552
+ if (onend) {
9553
+ await callHandler(onend, writtenSize);
9554
+ }
9197
9555
  } catch (error) {
9198
9556
  try {
9199
9557
  error.exportedEntryNames = exportedEntryNames;
@@ -9206,6 +9564,25 @@ async function exportFileSystemHandle(zipEntry, directoryHandle, options) {
9206
9564
  }
9207
9565
  return directoryHandle;
9208
9566
 
9567
+ function createProgressWritable(writable) {
9568
+ const writer = writable.getWriter();
9569
+ return new WritableStream({
9570
+ async write(chunk) {
9571
+ await writer.write(chunk);
9572
+ writtenSize += chunk.length;
9573
+ if (onprogress) {
9574
+ await callHandler(onprogress, writtenSize, totalSize);
9575
+ }
9576
+ },
9577
+ close() {
9578
+ return writer.close();
9579
+ },
9580
+ abort(reason) {
9581
+ return writer.abort(reason);
9582
+ }
9583
+ });
9584
+ }
9585
+
9209
9586
  async function exportChildren(entry, parentHandle) {
9210
9587
  if (options.concurrent) {
9211
9588
  const results = await Promise.allSettled(entry.children.map(child => exportChild(child, parentHandle)));
@@ -9237,19 +9614,7 @@ async function exportFileSystemHandle(zipEntry, directoryHandle, options) {
9237
9614
  const fileHandle = await parentHandle.getFileHandle(child.name, { create: true });
9238
9615
  const writable = await fileHandle.createWritable();
9239
9616
  try {
9240
- await child.getData({ writable }, Object.assign({}, options, {
9241
- signal,
9242
- onprogress: async progress => {
9243
- if (options.onprogress) {
9244
- writtenSizes.set(child.id, progress);
9245
- try {
9246
- await options.onprogress(Array.from(writtenSizes.values()).reduce((previousValue, currentValue) => previousValue + currentValue, 0), totalSize);
9247
- } catch {
9248
- // ignored
9249
- }
9250
- }
9251
- }
9252
- }));
9617
+ await child.getData({ writable: createProgressWritable(writable) }, getDataOptions);
9253
9618
  } catch (error) {
9254
9619
  throw exportAborted ? new Error(ERR_ABORT_EXPORT) : error;
9255
9620
  }
@@ -9478,6 +9843,7 @@ exports.ERR_INVALID_AUTHENTICATION_CODE = ERR_INVALID_AUTHENTICATION_CODE;
9478
9843
  exports.ERR_INVALID_CODEC_DEFINITION = ERR_INVALID_CODEC_DEFINITION;
9479
9844
  exports.ERR_INVALID_CODEC_MODULE = ERR_INVALID_CODEC_MODULE;
9480
9845
  exports.ERR_INVALID_COMMENT = ERR_INVALID_COMMENT;
9846
+ exports.ERR_INVALID_COMMENT_TYPE = ERR_INVALID_COMMENT_TYPE;
9481
9847
  exports.ERR_INVALID_COMPRESSED_DATA = ERR_INVALID_COMPRESSED_DATA;
9482
9848
  exports.ERR_INVALID_CRC32 = ERR_INVALID_CRC32;
9483
9849
  exports.ERR_INVALID_ENCRYPTION_STRENGTH = ERR_INVALID_ENCRYPTION_STRENGTH;
@@ -9493,6 +9859,7 @@ exports.ERR_INVALID_MSDOS_ATTRIBUTES = ERR_INVALID_MSDOS_ATTRIBUTES;
9493
9859
  exports.ERR_INVALID_MSDOS_DATA = ERR_INVALID_MSDOS_DATA;
9494
9860
  exports.ERR_INVALID_PASSWORD = ERR_INVALID_PASSWORD;
9495
9861
  exports.ERR_INVALID_PASSWORD_TYPE = ERR_INVALID_PASSWORD_TYPE;
9862
+ exports.ERR_INVALID_PASS_THROUGH = ERR_INVALID_PASS_THROUGH;
9496
9863
  exports.ERR_INVALID_SIGNATURE = ERR_INVALID_SIGNATURE;
9497
9864
  exports.ERR_INVALID_SIGNATURE_DATA = ERR_INVALID_SIGNATURE_DATA;
9498
9865
  exports.ERR_INVALID_STRICTNESS = ERR_INVALID_STRICTNESS;
@@ -9510,11 +9877,13 @@ exports.ERR_RESERVED_COMPRESSION_METHOD = ERR_RESERVED_COMPRESSION_METHOD;
9510
9877
  exports.ERR_SPLIT_ZIP_FILE = ERR_SPLIT_ZIP_FILE;
9511
9878
  exports.ERR_UNDEFINED_READER = ERR_UNDEFINED_READER;
9512
9879
  exports.ERR_UNDEFINED_UNCOMPRESSED_SIZE = ERR_UNDEFINED_UNCOMPRESSED_SIZE;
9880
+ exports.ERR_UNDETERMINED_SIZE = ERR_UNDETERMINED_SIZE;
9513
9881
  exports.ERR_UNSAFE_FILENAME = ERR_UNSAFE_FILENAME;
9514
9882
  exports.ERR_UNSUPPORTED_COMPRESSION = ERR_UNSUPPORTED_COMPRESSION$1;
9515
9883
  exports.ERR_UNSUPPORTED_CONTEXT = ERR_UNSUPPORTED_CONTEXT;
9516
9884
  exports.ERR_UNSUPPORTED_CRYPTO_API = ERR_UNSUPPORTED_CRYPTO_API;
9517
9885
  exports.ERR_UNSUPPORTED_ENCRYPTION = ERR_UNSUPPORTED_ENCRYPTION;
9886
+ exports.ERR_UNSUPPORTED_ENCRYPTION_PASS_THROUGH = ERR_UNSUPPORTED_ENCRYPTION_PASS_THROUGH;
9518
9887
  exports.ERR_UNSUPPORTED_ENCRYPTION_USDZ = ERR_UNSUPPORTED_ENCRYPTION_USDZ;
9519
9888
  exports.ERR_UNSUPPORTED_FORMAT = ERR_UNSUPPORTED_FORMAT;
9520
9889
  exports.ERR_WORKER_STARTUP_TIMEOUT = ERR_WORKER_STARTUP_TIMEOUT;