@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.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() {
@@ -2759,6 +2759,7 @@ function createWebWorkerInterface(workerData, config) {
2759
2759
  worker,
2760
2760
  workerAlive: false,
2761
2761
  terminated: false,
2762
+ startupError: null,
2762
2763
  interface: {
2763
2764
  run: async () => {
2764
2765
  try {
@@ -2786,6 +2787,13 @@ function createWebWorkerInterface(workerData, config) {
2786
2787
  }
2787
2788
 
2788
2789
  async function runWebWorker(workerData, config) {
2790
+ if (!workerData.worker) {
2791
+ const { startupError } = workerData;
2792
+ workerData.startupError = null;
2793
+ const error = startupError || new Error(ERR_WORKER_STARTUP_TIMEOUT);
2794
+ error.workerStartupFailed = true;
2795
+ throw error;
2796
+ }
2789
2797
  let resolveResult, rejectResult;
2790
2798
  const result = new Promise((resolve, reject) => {
2791
2799
  resolveResult = resolve;
@@ -2999,11 +3007,12 @@ function onWorkerError(event, workerData) {
2999
3007
  if (!workerAlive) {
3000
3008
  workerData.worker = null;
3001
3009
  }
3010
+ let error = event.error || new Error(event.message || ERROR_EVENT_TYPE);
3011
+ if (!workerAlive) {
3012
+ error = Object.assign(new Error(error.message || ERROR_EVENT_TYPE), { workerStartupFailed: true });
3013
+ workerData.startupError = error;
3014
+ }
3002
3015
  if (rejectResult) {
3003
- let error = event.error || new Error(event.message || ERROR_EVENT_TYPE);
3004
- if (!workerAlive) {
3005
- error = Object.assign(new Error(error.message || ERROR_EVENT_TYPE), { workerStartupFailed: true });
3006
- }
3007
3016
  rejectResult(error);
3008
3017
  if (writer) {
3009
3018
  writer.releaseLock();
@@ -3348,8 +3357,10 @@ class Reader extends Stream {
3348
3357
  async pull(controller) {
3349
3358
  const dataSize = size === UNDEFINED_VALUE ? chunkSize : Math.min(chunkSize, size - chunkOffset);
3350
3359
  const data = await readUint8Array(reader, offset + chunkOffset, dataSize);
3351
- controller.enqueue(data);
3352
- if ((chunkOffset + chunkSize > size) || (size === UNDEFINED_VALUE && !data.length && dataSize)) {
3360
+ if (data.length) {
3361
+ controller.enqueue(data);
3362
+ }
3363
+ if ((chunkOffset + chunkSize >= size) || (size === UNDEFINED_VALUE && !data.length && dataSize)) {
3353
3364
  controller.close();
3354
3365
  } else {
3355
3366
  chunkOffset += chunkSize;
@@ -3427,6 +3438,7 @@ class Data64URIWriter extends Writer {
3427
3438
  constructor(contentType) {
3428
3439
  super();
3429
3440
  Object.assign(this, {
3441
+ contentType,
3430
3442
  data: "data:" + (contentType || "") + ";base64,",
3431
3443
  pending: []
3432
3444
  });
@@ -3528,6 +3540,7 @@ class BlobWriter extends Stream {
3528
3540
  return transformStream.writable;
3529
3541
  }
3530
3542
  });
3543
+ writer.contentType = contentType;
3531
3544
  writer.blob = streamToBlob(transformStream.readable, contentType);
3532
3545
  writer.blob.catch(() => { });
3533
3546
  }
@@ -3544,6 +3557,26 @@ class TextReader extends BlobReader {
3544
3557
  }
3545
3558
  }
3546
3559
 
3560
+ function getTextSize(text) {
3561
+ let size = 0;
3562
+ for (let indexCharacter = 0; indexCharacter < text.length; indexCharacter++) {
3563
+ const characterCode = text.charCodeAt(indexCharacter);
3564
+ if (characterCode < 0x80) {
3565
+ size += 1;
3566
+ } else if (characterCode < 0x800) {
3567
+ size += 2;
3568
+ } else if (characterCode < 0xd800 || characterCode >= 0xe000) {
3569
+ size += 3;
3570
+ } else if (characterCode < 0xdc00 && (text.charCodeAt(indexCharacter + 1) & 0xfc00) == 0xdc00) {
3571
+ size += 4;
3572
+ indexCharacter++;
3573
+ } else {
3574
+ size += 3;
3575
+ }
3576
+ }
3577
+ return size;
3578
+ }
3579
+
3547
3580
  class TextWriter extends BlobWriter {
3548
3581
 
3549
3582
  constructor(encoding) {
@@ -4028,9 +4061,8 @@ class SplitDataReader extends Reader {
4028
4061
 
4029
4062
  async init() {
4030
4063
  const reader = this;
4031
- const { readers } = reader;
4032
4064
  reader.lastDiskNumber = 0;
4033
- await Promise.all(readers.map(diskReader => initStream(diskReader)));
4065
+ const readers = reader.readers = await Promise.all(reader.readers.map(initDiskReader));
4034
4066
  reader.diskOffsets = readers.map(diskReader => {
4035
4067
  const diskOffset = reader.size;
4036
4068
  reader.size += diskReader.size;
@@ -4207,6 +4239,10 @@ class GenericWriter {
4207
4239
  }
4208
4240
  }
4209
4241
 
4242
+ function ownsWritable(writer) {
4243
+ return Boolean(writer && writer.getData);
4244
+ }
4245
+
4210
4246
  function isHttpFamily(url) {
4211
4247
  const { baseURI } = getConfiguration();
4212
4248
  const { protocol } = new URL(url, baseURI);
@@ -4221,6 +4257,16 @@ async function initStream(stream, initSize) {
4221
4257
  }
4222
4258
  }
4223
4259
 
4260
+ async function initDiskReader(diskReader) {
4261
+ diskReader = new GenericReader(diskReader);
4262
+ await initStream(diskReader);
4263
+ if (diskReader.size === UNDEFINED_VALUE || !diskReader.readUint8Array) {
4264
+ diskReader = new BlobReader(await streamToBlob(diskReader.readable));
4265
+ await initStream(diskReader);
4266
+ }
4267
+ return diskReader;
4268
+ }
4269
+
4224
4270
  function readUint8Array(reader, offset, size) {
4225
4271
  return reader.readUint8Array(offset, size);
4226
4272
  }
@@ -4351,6 +4397,8 @@ const PROPERTY_NAME_CREATION_DATE = "creationDate";
4351
4397
  const PROPERTY_NAME_RAW_CREATION_DATE = "rawCreationDate";
4352
4398
  const PROPERTY_NAME_INTERNAL_FILE_ATTRIBUTES = "internalFileAttributes";
4353
4399
  const PROPERTY_NAME_EXTERNAL_FILE_ATTRIBUTES = "externalFileAttributes";
4400
+ const PROPERTY_NAME_DEPRECATED_INTERNAL_FILE_ATTRIBUTES = "internalFileAttribute";
4401
+ const PROPERTY_NAME_DEPRECATED_EXTERNAL_FILE_ATTRIBUTES = "externalFileAttribute";
4354
4402
  const PROPERTY_NAME_MSDOS_ATTRIBUTES_RAW = "msdosAttributesRaw";
4355
4403
  const PROPERTY_NAME_MSDOS_ATTRIBUTES = "msdosAttributes";
4356
4404
  const PROPERTY_NAME_MS_DOS_COMPATIBLE = "msDosCompatible";
@@ -4361,6 +4409,7 @@ const PROPERTY_NAME_VERSION_MADE_BY = "versionMadeBy";
4361
4409
  const PROPERTY_NAME_ZIPCRYPTO = "zipCrypto";
4362
4410
  const PROPERTY_NAME_DIRECTORY = "directory";
4363
4411
  const PROPERTY_NAME_EXECUTABLE = "executable";
4412
+ const PROPERTY_NAME_SYMLINK = "symlink";
4364
4413
  const PROPERTY_NAME_COMPRESSION_METHOD = "compressionMethod";
4365
4414
  const PROPERTY_NAME_SIGNATURE = "signature";
4366
4415
  const PROPERTY_NAME_CRC32 = "crc32";
@@ -4376,6 +4425,10 @@ const PROPERTY_NAME_SETUID = "setuid";
4376
4425
  const PROPERTY_NAME_SETGID = "setgid";
4377
4426
  const PROPERTY_NAME_STICKY = "sticky";
4378
4427
  const PROPERTY_NAME_BITFLAG = "bitFlag";
4428
+ const PROPERTY_NAME_RAW_BITFLAG = "rawBitFlag";
4429
+ const PROPERTY_NAME_FILENAME_LENGTH = "filenameLength";
4430
+ const PROPERTY_NAME_EXTRA_FIELD_LENGTH = "extraFieldLength";
4431
+ const PROPERTY_NAME_UNIX_EXTERNAL_UPPER = "unixExternalUpper";
4379
4432
  const PROPERTY_NAME_FILENAME_UTF8 = "filenameUTF8";
4380
4433
  const PROPERTY_NAME_COMMENT_UTF8 = "commentUTF8";
4381
4434
  const PROPERTY_NAME_RAW_EXTRA_FIELD = "rawExtraField";
@@ -4404,6 +4457,8 @@ const PROPERTY_NAMES = [
4404
4457
  PROPERTY_NAME_DISK_NUMBER_START,
4405
4458
  PROPERTY_NAME_INTERNAL_FILE_ATTRIBUTES,
4406
4459
  PROPERTY_NAME_EXTERNAL_FILE_ATTRIBUTES,
4460
+ PROPERTY_NAME_DEPRECATED_INTERNAL_FILE_ATTRIBUTES,
4461
+ PROPERTY_NAME_DEPRECATED_EXTERNAL_FILE_ATTRIBUTES,
4407
4462
  PROPERTY_NAME_MSDOS_ATTRIBUTES_RAW,
4408
4463
  PROPERTY_NAME_MSDOS_ATTRIBUTES,
4409
4464
  PROPERTY_NAME_MS_DOS_COMPATIBLE,
@@ -4414,6 +4469,7 @@ const PROPERTY_NAMES = [
4414
4469
  PROPERTY_NAME_ZIPCRYPTO,
4415
4470
  PROPERTY_NAME_DIRECTORY,
4416
4471
  PROPERTY_NAME_EXECUTABLE,
4472
+ PROPERTY_NAME_SYMLINK,
4417
4473
  PROPERTY_NAME_COMPRESSION_METHOD,
4418
4474
  PROPERTY_NAME_SIGNATURE,
4419
4475
  PROPERTY_NAME_CRC32,
@@ -4425,10 +4481,14 @@ const PROPERTY_NAMES = [
4425
4481
  PROPERTY_NAME_UID,
4426
4482
  PROPERTY_NAME_GID,
4427
4483
  PROPERTY_NAME_UNIX_MODE,
4484
+ PROPERTY_NAME_UNIX_EXTERNAL_UPPER,
4428
4485
  PROPERTY_NAME_SETUID,
4429
4486
  PROPERTY_NAME_SETGID,
4430
4487
  PROPERTY_NAME_STICKY,
4431
4488
  PROPERTY_NAME_BITFLAG,
4489
+ PROPERTY_NAME_RAW_BITFLAG,
4490
+ PROPERTY_NAME_FILENAME_LENGTH,
4491
+ PROPERTY_NAME_EXTRA_FIELD_LENGTH,
4432
4492
  PROPERTY_NAME_FILENAME_UTF8,
4433
4493
  PROPERTY_NAME_COMMENT_UTF8,
4434
4494
  PROPERTY_NAME_RAW_EXTRA_FIELD,
@@ -4490,6 +4550,7 @@ const OPTION_CHECK_PASSWORD_ONLY = "checkPasswordOnly";
4490
4550
  const OPTION_CHECK_OVERLAPPING_ENTRY_ONLY = "checkOverlappingEntryOnly";
4491
4551
  const OPTION_CHECK_OVERLAPPING_ENTRY = "checkOverlappingEntry";
4492
4552
  const OPTION_CHECK_AMBIGUITY = "checkAmbiguity";
4553
+ const OPTION_CHECK_LOCAL_DIRECTORY = "checkLocalDirectory";
4493
4554
  const OPTION_CHECK_SIGNATURE = "checkSignature";
4494
4555
  const OPTION_CHECK_CRC32 = "checkCrc32";
4495
4556
  const OPTION_CHECK_AUTHENTICATION_CODE = "checkAuthenticationCode";
@@ -4621,7 +4682,7 @@ class ZipReader {
4621
4682
  if (reader.size < END_OF_CENTRAL_DIR_LENGTH) {
4622
4683
  throw new Error(ERR_BAD_FORMAT);
4623
4684
  }
4624
- const strictness = getStrictness(getOptionValue$1(zipReader, options, OPTION_STRICTNESS), getOptionValue$1(zipReader, options, OPTION_CHECK_AMBIGUITY));
4685
+ const strictness = getStrictness(options, zipReader.options);
4625
4686
  const checkAmbiguity = strictness == STRICTNESS_STRICT;
4626
4687
  const rejectAmbiguousEndOfDirectory = strictness != STRICTNESS_TOLERANT;
4627
4688
  const maxAppendedDataSize = getMaxAppendedDataSize(getOptionValue$1(zipReader, options, OPTION_MAX_APPENDED_DATA_SIZE), strictness);
@@ -4843,6 +4904,7 @@ class ZipReader {
4843
4904
  index: indexFile,
4844
4905
  versionMadeBy,
4845
4906
  msDosCompatible,
4907
+ zip64: false,
4846
4908
  compressedSize: 0,
4847
4909
  uncompressedSize: 0,
4848
4910
  commentLength,
@@ -4876,15 +4938,18 @@ class ZipReader {
4876
4938
  const setuid = Boolean(fileEntry.unixMode & FILE_ATTR_UNIX_SETUID_MASK);
4877
4939
  const setgid = Boolean(fileEntry.unixMode & FILE_ATTR_UNIX_SETGID_MASK);
4878
4940
  const sticky = Boolean(fileEntry.unixMode & FILE_ATTR_UNIX_STICKY_MASK);
4879
- const executable = (fileEntry.unixMode !== UNDEFINED_VALUE)
4941
+ const unixType = fileEntry.unixMode === UNDEFINED_VALUE ? unixExternalUpper : fileEntry.unixMode;
4942
+ const symlink = (unixType & FILE_ATTR_UNIX_TYPE_MASK) == FILE_ATTR_UNIX_TYPE_SYMLINK;
4943
+ const executable = !symlink && ((fileEntry.unixMode !== UNDEFINED_VALUE)
4880
4944
  ? ((fileEntry.unixMode & FILE_ATTR_UNIX_EXECUTABLE_MASK) != 0)
4881
- : (unixCompatible && ((unixExternalUpper & FILE_ATTR_UNIX_EXECUTABLE_MASK) != 0));
4945
+ : (unixCompatible && ((unixExternalUpper & FILE_ATTR_UNIX_EXECUTABLE_MASK) != 0)));
4882
4946
  const modeIsDir = fileEntry.unixMode !== UNDEFINED_VALUE && ((fileEntry.unixMode & FILE_ATTR_UNIX_TYPE_MASK) == FILE_ATTR_UNIX_TYPE_DIR);
4883
4947
  const upperIsDir = ((unixExternalUpper & FILE_ATTR_UNIX_TYPE_MASK) == FILE_ATTR_UNIX_TYPE_DIR);
4884
4948
  Object.assign(fileEntry, {
4885
4949
  setuid,
4886
4950
  setgid,
4887
4951
  sticky,
4952
+ symlink,
4888
4953
  unixExternalUpper,
4889
4954
  internalFileAttribute: fileEntry.internalFileAttributes,
4890
4955
  externalFileAttribute: fileEntry.externalFileAttributes,
@@ -4950,6 +5015,10 @@ class ZipReader {
4950
5015
  }
4951
5016
 
4952
5017
  async close() {
5018
+ const { reader } = this;
5019
+ if (!reader.readUint8Array && reader.readable && !reader.readable.locked) {
5020
+ await reader.readable.cancel();
5021
+ }
4953
5022
  }
4954
5023
  }
4955
5024
 
@@ -5046,9 +5115,12 @@ let ZipEntry$1 = class ZipEntry {
5046
5115
  extraFieldLength,
5047
5116
  filenameLength
5048
5117
  } = localDirectory;
5049
- const checkAmbiguity = getStrictness(getOptionValue$1(zipEntry, options, OPTION_STRICTNESS), getOptionValue$1(zipEntry, options, OPTION_CHECK_AMBIGUITY)) == STRICTNESS_STRICT;
5118
+ const checkLocalDirectoryOption = getOptionValue$1(zipEntry, options, OPTION_CHECK_LOCAL_DIRECTORY);
5119
+ const entryStrictness = getStrictness(options, zipEntry.options);
5120
+ const checkLocalDirectory = getCheckLocalDirectory(checkLocalDirectoryOption, entryStrictness);
5121
+ const checkLocalFilename = getCheckLocalFilename(checkLocalDirectoryOption, entryStrictness);
5050
5122
  let rawLocalFilename = EMPTY_UINT8_ARRAY;
5051
- if (checkAmbiguity && (filenameLength || extraFieldLength)) {
5123
+ if (checkLocalFilename && (filenameLength || extraFieldLength)) {
5052
5124
  const trailingDataArray = await readUint8Array(reader, localHeaderOffset + HEADER_SIZE, filenameLength + extraFieldLength);
5053
5125
  rawLocalFilename = trailingDataArray.subarray(0, filenameLength);
5054
5126
  localDirectory.rawExtraField = trailingDataArray.subarray(filenameLength);
@@ -5057,17 +5129,26 @@ let ZipEntry$1 = class ZipEntry {
5057
5129
  await readUint8Array(reader, localHeaderOffset + HEADER_SIZE + filenameLength, extraFieldLength) :
5058
5130
  EMPTY_UINT8_ARRAY;
5059
5131
  }
5132
+ if (checkLocalFilename) {
5133
+ localDirectory.rawFilename = rawLocalFilename;
5134
+ }
5060
5135
  readCommonFooter(zipEntry, localDirectory, dataView, 4, true);
5061
- if (checkAmbiguity) {
5062
- checkLocalDirectory(zipEntry, localDirectory, rawLocalFilename);
5136
+ if (checkLocalDirectory) {
5137
+ validateLocalDirectory(zipEntry, localDirectory, rawLocalFilename, checkLocalFilename);
5063
5138
  }
5064
- const { lastAccessDate, creationDate } = localDirectory;
5139
+ const { lastAccessDate, creationDate, uid, gid } = localDirectory;
5065
5140
  if (lastAccessDate) {
5066
5141
  fileEntry.lastAccessDate = lastAccessDate;
5067
5142
  }
5068
5143
  if (creationDate) {
5069
5144
  fileEntry.creationDate = creationDate;
5070
5145
  }
5146
+ if (uid !== UNDEFINED_VALUE && fileEntry.uid === UNDEFINED_VALUE) {
5147
+ fileEntry.uid = uid;
5148
+ }
5149
+ if (gid !== UNDEFINED_VALUE && fileEntry.gid === UNDEFINED_VALUE) {
5150
+ fileEntry.gid = gid;
5151
+ }
5071
5152
  const encrypted = zipEntry.encrypted && localDirectory.encrypted && !passThrough;
5072
5153
  const zipCrypto = encrypted && !extraFieldAES;
5073
5154
  if (!passThrough) {
@@ -5174,7 +5255,7 @@ let ZipEntry$1 = class ZipEntry {
5174
5255
  throw error;
5175
5256
  }
5176
5257
  } finally {
5177
- const preventClose = getOptionValue$1(zipEntry, options, OPTION_PREVENT_CLOSE);
5258
+ const preventClose = !ownsWritable(writer) && getOptionValue$1(zipEntry, options, OPTION_PREVENT_CLOSE);
5178
5259
  if (!preventClose && writable && !writable.locked) {
5179
5260
  const writableWriter = writable.getWriter();
5180
5261
  if (abortError) {
@@ -5303,10 +5384,12 @@ function readCommonFooter(fileEntry, directory, dataView, offset, localDirectory
5303
5384
  directory.extraFieldNTFS = extraFieldNTFS;
5304
5385
  }
5305
5386
  const extraFieldUnix = extraField.get(EXTRAFIELD_TYPE_UNIX);
5387
+ let unixIdsRead;
5306
5388
  if (extraFieldUnix) {
5307
- readExtraFieldUnix(extraFieldUnix, directory, false);
5389
+ unixIdsRead = readExtraFieldUnix(extraFieldUnix, directory, false);
5308
5390
  directory.extraFieldUnix = extraFieldUnix;
5309
- } else {
5391
+ }
5392
+ if (!unixIdsRead) {
5310
5393
  const extraFieldInfoZip = extraField.get(EXTRAFIELD_TYPE_INFOZIP);
5311
5394
  if (extraFieldInfoZip) {
5312
5395
  readExtraFieldUnix(extraFieldInfoZip, directory, true);
@@ -5409,7 +5492,7 @@ function readExtraFieldNTFS(extraFieldNTFS, directory) {
5409
5492
  const creationDate = getDateNTFS(rawCreationDate);
5410
5493
  const extraFieldData = { lastModDate, lastAccessDate, creationDate };
5411
5494
  Object.assign(extraFieldNTFS, extraFieldData);
5412
- Object.assign(directory, extraFieldData);
5495
+ Object.assign(directory, extraFieldData, { rawLastAccessDate, rawCreationDate });
5413
5496
  }
5414
5497
  }
5415
5498
 
@@ -5418,8 +5501,8 @@ function readExtraFieldUnixDates(extraField, directory) {
5418
5501
  return;
5419
5502
  }
5420
5503
  const extraFieldView = getDataView(extraField.data);
5421
- const lastAccessDate = new Date(getUint32(extraFieldView, 0) * 1000);
5422
- const lastModDate = new Date(getUint32(extraFieldView, 4) * 1000);
5504
+ const lastAccessDate = new Date((getUint32(extraFieldView, 0) | 0) * 1000);
5505
+ const lastModDate = new Date((getUint32(extraFieldView, 4) | 0) * 1000);
5423
5506
  const extraFieldData = { lastAccessDate, lastModDate };
5424
5507
  if (extraField.data.length >= 12) {
5425
5508
  extraFieldData.uid = getUint16(extraFieldView, 8);
@@ -5453,6 +5536,7 @@ function readExtraFieldUnix(extraField, directory, isInfoZip) {
5453
5536
  if (gid !== UNDEFINED_VALUE) {
5454
5537
  directory.gid = gid;
5455
5538
  }
5539
+ return uid !== UNDEFINED_VALUE || gid !== UNDEFINED_VALUE;
5456
5540
  } catch {
5457
5541
  // ignored
5458
5542
  }
@@ -5525,26 +5609,25 @@ async function detectOverlappingEntry({
5525
5609
  }
5526
5610
  if (dataDescriptorLength) {
5527
5611
  const dataDescriptorArray = await readUint8Array(reader, dataOffset + compressedSize, dataDescriptorLength + DATA_DESCRIPTOR_RECORD_SIGNATURE_LENGTH);
5528
- const dataDescriptorSignature = dataDescriptorArray.length == dataDescriptorLength + DATA_DESCRIPTOR_RECORD_SIGNATURE_LENGTH &&
5529
- getUint32(getDataView(dataDescriptorArray), 0) == DATA_DESCRIPTOR_RECORD_SIGNATURE;
5530
- if (dataDescriptorSignature) {
5531
- const readCrc32 = getUint32(getDataView(dataDescriptorArray), 4);
5532
- let readCompressedSize;
5533
- let readUncompressedSize;
5534
- if (extraFieldZip64) {
5535
- readCompressedSize = getBigUint64(getDataView(dataDescriptorArray), 8);
5536
- readUncompressedSize = getBigUint64(getDataView(dataDescriptorArray), 16);
5537
- } else {
5538
- readCompressedSize = getUint32(getDataView(dataDescriptorArray), 8);
5539
- readUncompressedSize = getUint32(getDataView(dataDescriptorArray), 12);
5540
- }
5541
- const matchCrc32 = (fileEntry.encrypted && !fileEntry.zipCrypto) || readCrc32 == crc32;
5612
+ const dataDescriptorView = getDataView(dataDescriptorArray);
5613
+ let signature = dataDescriptorArray.length == dataDescriptorLength + DATA_DESCRIPTOR_RECORD_SIGNATURE_LENGTH &&
5614
+ getUint32(dataDescriptorView, 0) == DATA_DESCRIPTOR_RECORD_SIGNATURE;
5615
+ if (signature) {
5616
+ const signedDataDescriptor = readDataDescriptor(dataDescriptorView, DATA_DESCRIPTOR_RECORD_SIGNATURE_LENGTH, extraFieldZip64);
5617
+ const matchCrc32 = (fileEntry.encrypted && !fileEntry.zipCrypto) || signedDataDescriptor.crc32 == crc32;
5542
5618
  if (matchCrc32 &&
5543
- readCompressedSize == compressedSize &&
5544
- readUncompressedSize == uncompressedSize) {
5619
+ signedDataDescriptor.compressedSize == compressedSize &&
5620
+ signedDataDescriptor.uncompressedSize == uncompressedSize) {
5545
5621
  dataDescriptorLength += DATA_DESCRIPTOR_RECORD_SIGNATURE_LENGTH;
5622
+ } else {
5623
+ signature = false;
5546
5624
  }
5547
5625
  }
5626
+ if (dataDescriptorArray.length >= dataDescriptorLength) {
5627
+ const localDataDescriptor = readDataDescriptor(dataDescriptorView, signature ? DATA_DESCRIPTOR_RECORD_SIGNATURE_LENGTH : 0, extraFieldZip64);
5628
+ localDataDescriptor.signature = signature;
5629
+ fileEntry.localDirectory.dataDescriptor = localDataDescriptor;
5630
+ }
5548
5631
  }
5549
5632
  const range = {
5550
5633
  start: offset,
@@ -5561,6 +5644,20 @@ async function detectOverlappingEntry({
5561
5644
  readRanges.set(index, range);
5562
5645
  }
5563
5646
 
5647
+ function readDataDescriptor(dataDescriptorView, offset, extraFieldZip64) {
5648
+ const crc32 = getUint32(dataDescriptorView, offset);
5649
+ let compressedSize;
5650
+ let uncompressedSize;
5651
+ if (extraFieldZip64) {
5652
+ compressedSize = getBigUint64(dataDescriptorView, offset + 4);
5653
+ uncompressedSize = getBigUint64(dataDescriptorView, offset + 12);
5654
+ } else {
5655
+ compressedSize = getUint32(dataDescriptorView, offset + 4);
5656
+ uncompressedSize = getUint32(dataDescriptorView, offset + 8);
5657
+ }
5658
+ return { crc32, compressedSize, uncompressedSize };
5659
+ }
5660
+
5564
5661
  function getDiskOffset$1(reader, diskNumber) {
5565
5662
  return reader.getDiskOffset ? reader.getDiskOffset(diskNumber) : 0;
5566
5663
  }
@@ -5569,14 +5666,40 @@ function isStrictnessValue(value) {
5569
5666
  return value === STRICTNESS_STRICT || value === STRICTNESS_BALANCED || value === STRICTNESS_TOLERANT;
5570
5667
  }
5571
5668
 
5572
- function getStrictness(strictness, checkAmbiguity) {
5573
- if (strictness === UNDEFINED_VALUE) {
5574
- return checkAmbiguity ? STRICTNESS_STRICT : STRICTNESS_BALANCED;
5669
+ function getStrictness(options, inheritedOptions) {
5670
+ return resolveStrictness(options, resolveStrictness(inheritedOptions, STRICTNESS_BALANCED));
5671
+ }
5672
+
5673
+ function resolveStrictness(options, inheritedStrictness) {
5674
+ const strictness = options[OPTION_STRICTNESS];
5675
+ if (strictness !== UNDEFINED_VALUE) {
5676
+ if (!isStrictnessValue(strictness)) {
5677
+ throw new Error(ERR_INVALID_STRICTNESS);
5678
+ }
5679
+ return strictness;
5575
5680
  }
5576
- if (!isStrictnessValue(strictness)) {
5577
- throw new Error(ERR_INVALID_STRICTNESS);
5681
+ const checkAmbiguity = options[OPTION_CHECK_AMBIGUITY];
5682
+ if (checkAmbiguity === UNDEFINED_VALUE) {
5683
+ return inheritedStrictness;
5578
5684
  }
5579
- return strictness;
5685
+ if (checkAmbiguity) {
5686
+ return STRICTNESS_STRICT;
5687
+ }
5688
+ return inheritedStrictness == STRICTNESS_TOLERANT ? STRICTNESS_TOLERANT : STRICTNESS_BALANCED;
5689
+ }
5690
+
5691
+ function getCheckLocalDirectory(checkLocalDirectory, strictness) {
5692
+ if (checkLocalDirectory === UNDEFINED_VALUE) {
5693
+ return strictness != STRICTNESS_TOLERANT;
5694
+ }
5695
+ return Boolean(checkLocalDirectory);
5696
+ }
5697
+
5698
+ function getCheckLocalFilename(checkLocalFilename, strictness) {
5699
+ if (checkLocalFilename === UNDEFINED_VALUE) {
5700
+ return strictness == STRICTNESS_STRICT;
5701
+ }
5702
+ return Boolean(checkLocalFilename);
5580
5703
  }
5581
5704
 
5582
5705
  function getFilenameValidation(filenameValidation, strictness) {
@@ -5724,10 +5847,11 @@ async function readSignature(reader, view, anchoredOffset, signatureOffset, size
5724
5847
  return UNDEFINED_VALUE;
5725
5848
  }
5726
5849
 
5727
- function checkLocalDirectory(zipEntry, localDirectory, rawLocalFilename) {
5850
+ function validateLocalDirectory(zipEntry, localDirectory, rawLocalFilename, checkLocalFilename) {
5728
5851
  const { rawFilename } = zipEntry;
5729
- if (rawLocalFilename.length != rawFilename.length ||
5730
- rawLocalFilename.some((byteValue, indexByte) => byteValue != rawFilename[indexByte])) {
5852
+ if (checkLocalFilename &&
5853
+ (rawLocalFilename.length != rawFilename.length ||
5854
+ rawLocalFilename.some((byteValue, indexByte) => byteValue != rawFilename[indexByte]))) {
5731
5855
  throwAmbiguousArchive("mismatched local file header (filename)");
5732
5856
  }
5733
5857
  if ((localDirectory.rawBitFlag & BITFLAG_AMBIGUITY_MASK) != (zipEntry.rawBitFlag & BITFLAG_AMBIGUITY_MASK)) {
@@ -5845,11 +5969,13 @@ var zipReader = /*#__PURE__*/Object.freeze({
5845
5969
 
5846
5970
  const ERR_DUPLICATED_NAME = "File already exists";
5847
5971
  const ERR_INVALID_COMMENT = "Zip file comment exceeds 64KB";
5972
+ const ERR_INVALID_COMMENT_TYPE = "Invalid zip file comment (must be a Uint8Array)";
5848
5973
  const ERR_INVALID_ENTRY_COMMENT = "File entry comment exceeds 64KB";
5849
5974
  const ERR_INVALID_ENTRY_NAME = "File entry name exceeds 64KB";
5850
5975
  const ERR_INVALID_VERSION = "Version exceeds 65535";
5851
5976
  const ERR_INVALID_ENCRYPTION_STRENGTH = "The strength must equal 1, 2, or 3";
5852
5977
  const ERR_UNSUPPORTED_ENCRYPTION_USDZ = "Encryption is not supported in USDZ files";
5978
+ const ERR_UNSUPPORTED_ENCRYPTION_PASS_THROUGH = "Encryption is not supported when the 'passThrough' option is set";
5853
5979
  const ERR_INVALID_EXTRAFIELD_TYPE = "Extra field type exceeds 65535";
5854
5980
  const ERR_INVALID_EXTRAFIELD_DATA = "Extra field data exceeds 64KB";
5855
5981
  const ERR_UNSUPPORTED_COMPRESSION = "Compression method not supported";
@@ -5859,6 +5985,7 @@ const MIN_NTFS_TIME = BigInt(0);
5859
5985
  const MAX_NTFS_TIME = BigInt("0x7fffffffffffffff");
5860
5986
  const ERR_UNSUPPORTED_FORMAT = "Zip64 is not supported (set the 'zip64' option to 'true')";
5861
5987
  const ERR_UNDEFINED_UNCOMPRESSED_SIZE = "Undefined uncompressed size";
5988
+ const ERR_UNDETERMINED_SIZE = "Undetermined size";
5862
5989
  const ERR_UNDEFINED_READER = "Undefined reader";
5863
5990
  const ERR_ZIP_NOT_EMPTY = "Zip file not empty";
5864
5991
  const ERR_INVALID_UID = "Invalid uid (must be integer 0..2^32-1)";
@@ -5911,6 +6038,10 @@ class ZipWriter {
5911
6038
  }
5912
6039
  reader = new GenericReader(reader);
5913
6040
  await initStream(reader);
6041
+ if (reader.size === UNDEFINED_VALUE || !reader.readUint8Array) {
6042
+ reader = new BlobReader(await streamToBlob(reader.readable));
6043
+ await initStream(reader);
6044
+ }
5914
6045
  const { ZipReader } = await Promise.resolve().then(function () { return zipReader; });
5915
6046
  const zipReader$1 = new ZipReader(reader.readable);
5916
6047
  const entries = await zipReader$1.getEntries();
@@ -6059,6 +6190,9 @@ class ZipWriter {
6059
6190
  const zipWriter = this;
6060
6191
  const { pendingAddFileCalls, writer } = this;
6061
6192
  const { writable } = writer;
6193
+ if (!(comment instanceof Uint8Array)) {
6194
+ throw new Error(ERR_INVALID_COMMENT_TYPE);
6195
+ }
6062
6196
  if (getLength(comment) > MAX_16_BITS) {
6063
6197
  throw new Error(ERR_INVALID_COMMENT);
6064
6198
  }
@@ -6066,7 +6200,7 @@ class ZipWriter {
6066
6200
  await Promise.allSettled(Array.from(pendingAddFileCalls));
6067
6201
  }
6068
6202
  await closeFile(zipWriter, comment, options);
6069
- const preventClose = getOptionValue(zipWriter, options, OPTION_PREVENT_CLOSE);
6203
+ const preventClose = !ownsWritable(writer) && getOptionValue(zipWriter, options, OPTION_PREVENT_CLOSE);
6070
6204
  if (!preventClose) {
6071
6205
  await writable.getWriter().close();
6072
6206
  }
@@ -6155,8 +6289,6 @@ async function addFile(zipWriter, name, reader, options) {
6155
6289
  const diskOffset = getDiskOffset(zipWriter.writer);
6156
6290
  const diskNumber = getDiskNumber(zipWriter.writer);
6157
6291
  options = Object.assign({}, options, attributesInfo.resolvedOptions, metadataInfo.resolvedOptions, sizesInfo.resolvedOptions, {
6158
- internalFileAttribute: metadataInfo.resolvedOptions.internalFileAttributes,
6159
- externalFileAttribute: attributesInfo.resolvedOptions.externalFileAttributes,
6160
6292
  signature: options[PROPERTY_NAME_SIGNATURE],
6161
6293
  crc32: options.crc32 === UNDEFINED_VALUE ? options[PROPERTY_NAME_SIGNATURE] : options.crc32,
6162
6294
  offset: zipWriter.offset - diskOffset,
@@ -6170,14 +6302,20 @@ async function addFile(zipWriter, name, reader, options) {
6170
6302
  zipWriter.files.delete(name);
6171
6303
  throw error;
6172
6304
  }
6173
- Object.assign(fileEntry, { name, comment, extraField });
6305
+ Object.assign(fileEntry, {
6306
+ name,
6307
+ comment,
6308
+ extraField,
6309
+ [PROPERTY_NAME_DEPRECATED_INTERNAL_FILE_ATTRIBUTES]: fileEntry.internalFileAttributes,
6310
+ [PROPERTY_NAME_DEPRECATED_EXTERNAL_FILE_ATTRIBUTES]: fileEntry.externalFileAttributes
6311
+ });
6174
6312
  return new Entry(fileEntry);
6175
6313
  }
6176
6314
 
6177
6315
  function resolveAttributes(zipWriter, name, options) {
6178
6316
  name = name.trim();
6179
6317
  let msDosCompatible = getOptionValue(zipWriter, options, PROPERTY_NAME_MS_DOS_COMPATIBLE);
6180
- let versionMadeBy = getOptionValue(zipWriter, options, PROPERTY_NAME_VERSION_MADE_BY, msDosCompatible ? 20 : 768);
6318
+ let versionMadeBy = getOptionValue(zipWriter, options, PROPERTY_NAME_VERSION_MADE_BY, msDosCompatible ? VERSION_MADE_BY_MSDOS : VERSION_MADE_BY_UNIX);
6181
6319
  const executable = getOptionValue(zipWriter, options, PROPERTY_NAME_EXECUTABLE);
6182
6320
  const uid = getNumberOptionValue(zipWriter, options, PROPERTY_NAME_UID);
6183
6321
  const gid = getNumberOptionValue(zipWriter, options, PROPERTY_NAME_GID);
@@ -6211,7 +6349,7 @@ function resolveAttributes(zipWriter, name, options) {
6211
6349
  const hasMsDosProvided = msdosAttributesRaw !== UNDEFINED_VALUE || msdosAttributes !== UNDEFINED_VALUE;
6212
6350
  if (hasUnixMetadata) {
6213
6351
  msDosCompatible = false;
6214
- versionMadeBy = (versionMadeBy & MAX_16_BITS) | (3 << 8);
6352
+ versionMadeBy = (versionMadeBy & MAX_8_BITS) | VERSION_MADE_BY_UNIX;
6215
6353
  } else if (hasMsDosProvided) {
6216
6354
  msDosCompatible = true;
6217
6355
  versionMadeBy = (versionMadeBy & MAX_8_BITS);
@@ -6225,7 +6363,7 @@ function resolveAttributes(zipWriter, name, options) {
6225
6363
  if (versionMadeBy > MAX_16_BITS) {
6226
6364
  throw new Error(ERR_INVALID_VERSION);
6227
6365
  }
6228
- let externalFileAttributes = getOptionValue(zipWriter, options, PROPERTY_NAME_EXTERNAL_FILE_ATTRIBUTES);
6366
+ let externalFileAttributes = getAliasedOptionValue(zipWriter, options, PROPERTY_NAME_EXTERNAL_FILE_ATTRIBUTES, PROPERTY_NAME_DEPRECATED_EXTERNAL_FILE_ATTRIBUTES);
6229
6367
  const externalFileAttributesProvided = externalFileAttributes !== UNDEFINED_VALUE;
6230
6368
  if (!externalFileAttributesProvided) {
6231
6369
  externalFileAttributes = 0;
@@ -6251,11 +6389,10 @@ function resolveAttributes(zipWriter, name, options) {
6251
6389
  externalFileAttributes = FILE_ATTR_UNIX_DEFAULT_MASK << 16;
6252
6390
  }
6253
6391
  }
6254
- let unixExternalUpper;
6255
6392
  if (!msDosCompatible) {
6256
6393
  const unixModeProvided = unixMode !== UNDEFINED_VALUE || Boolean(setuid || setgid || sticky);
6257
- unixExternalUpper = (externalFileAttributes >> 16) & MAX_16_BITS;
6258
- unixMode = unixMode === UNDEFINED_VALUE ? unixExternalUpper : (unixMode & MAX_16_BITS);
6394
+ const defaultUnixMode = (externalFileAttributes >> 16) & MAX_16_BITS;
6395
+ unixMode = unixMode === UNDEFINED_VALUE ? defaultUnixMode : (unixMode & MAX_16_BITS);
6259
6396
  if (setuid) {
6260
6397
  unixMode |= FILE_ATTR_UNIX_SETUID_MASK;
6261
6398
  } else {
@@ -6273,7 +6410,9 @@ function resolveAttributes(zipWriter, name, options) {
6273
6410
  }
6274
6411
  if (!externalFileAttributesProvided || unixModeProvided) {
6275
6412
  if (directory) {
6276
- unixMode |= FILE_ATTR_UNIX_TYPE_DIR;
6413
+ unixMode = (unixMode & ~FILE_ATTR_UNIX_TYPE_MASK) | FILE_ATTR_UNIX_TYPE_DIR;
6414
+ } else if (!(unixMode & FILE_ATTR_UNIX_TYPE_MASK)) {
6415
+ unixMode |= FILE_ATTR_UNIX_TYPE_FILE;
6277
6416
  }
6278
6417
  externalFileAttributes = ((unixMode & MAX_16_BITS) << 16) | (externalFileAttributes & MAX_16_BITS);
6279
6418
  }
@@ -6282,17 +6421,20 @@ function resolveAttributes(zipWriter, name, options) {
6282
6421
  if (hasMsDosProvided) {
6283
6422
  externalFileAttributes = (externalFileAttributes & MAX_32_BITS) | (msdosAttributesRaw & MAX_8_BITS);
6284
6423
  }
6424
+ const unixExternalUpper = (externalFileAttributes >> 16) & MAX_16_BITS;
6425
+ const symlink = unixMode !== UNDEFINED_VALUE && ((unixMode & FILE_ATTR_UNIX_TYPE_MASK) == FILE_ATTR_UNIX_TYPE_SYMLINK);
6285
6426
  return {
6286
6427
  name,
6287
6428
  resolvedOptions: {
6288
6429
  versionMadeBy,
6289
- msDosCompatible,
6430
+ msDosCompatible: Boolean(msDosCompatible),
6290
6431
  externalFileAttributes,
6291
6432
  unixExternalUpper,
6292
6433
  uid,
6293
6434
  gid,
6294
6435
  unixMode,
6295
6436
  unixExtraFieldType,
6437
+ symlink,
6296
6438
  setuid,
6297
6439
  setgid,
6298
6440
  sticky,
@@ -6326,15 +6468,12 @@ function resolveMetadata(zipWriter, name, options) {
6326
6468
  const lastModDate = getOptionValue(zipWriter, options, PROPERTY_NAME_LAST_MODIFICATION_DATE, new Date());
6327
6469
  const lastAccessDate = getOptionValue(zipWriter, options, PROPERTY_NAME_LAST_ACCESS_DATE);
6328
6470
  const creationDate = getOptionValue(zipWriter, options, PROPERTY_NAME_CREATION_DATE);
6329
- const internalFileAttributes = getOptionValue(zipWriter, options, PROPERTY_NAME_INTERNAL_FILE_ATTRIBUTES, 0);
6471
+ const internalFileAttributes = getAliasedOptionValue(zipWriter, options, PROPERTY_NAME_INTERNAL_FILE_ATTRIBUTES, PROPERTY_NAME_DEPRECATED_INTERNAL_FILE_ATTRIBUTES, 0);
6330
6472
  const passThrough = getOptionValue(zipWriter, options, OPTION_PASS_THROUGH);
6331
- let password, rawPassword;
6332
- if (!passThrough) {
6333
- password = getOptionValue(zipWriter, options, OPTION_PASSWORD);
6334
- rawPassword = getOptionValue(zipWriter, options, OPTION_RAW_PASSWORD);
6335
- if ((password && typeof password != STRING_TYPE) || (rawPassword && !(rawPassword instanceof Uint8Array))) {
6336
- throw new Error(ERR_INVALID_PASSWORD_TYPE);
6337
- }
6473
+ const password = getOptionValue(zipWriter, options, OPTION_PASSWORD);
6474
+ const rawPassword = getOptionValue(zipWriter, options, OPTION_RAW_PASSWORD);
6475
+ if ((password && typeof password != STRING_TYPE) || (rawPassword && !(rawPassword instanceof Uint8Array))) {
6476
+ throw new Error(ERR_INVALID_PASSWORD_TYPE);
6338
6477
  }
6339
6478
  const encryptionStrength = getNumberOptionValue(zipWriter, options, OPTION_ENCRYPTION_STRENGTH, 3);
6340
6479
  const zipCrypto = getOptionValue(zipWriter, options, PROPERTY_NAME_ZIPCRYPTO);
@@ -6447,14 +6586,24 @@ function serializeExtraField(extraField) {
6447
6586
  }
6448
6587
 
6449
6588
  async function resolveSizes(zipWriter, reader, { resolvedOptions: metadata }, options) {
6589
+ if (metadata.passThrough && !reader && !getOptionValue(zipWriter, options, PROPERTY_NAME_DIRECTORY)) {
6590
+ throw new Error(ERR_UNDEFINED_READER);
6591
+ }
6592
+ let contentSize;
6593
+ if (reader) {
6594
+ reader = new GenericReader(reader);
6595
+ await initStream(reader);
6596
+ ({ size: contentSize } = reader);
6597
+ }
6598
+ return Object.assign({ reader }, resolveEntrySizes(zipWriter, Boolean(reader), contentSize, metadata, options));
6599
+ }
6600
+
6601
+ function resolveEntrySizes(zipWriter, hasContent, contentSize, metadata, options) {
6450
6602
  const { passThrough, zipCrypto, password, rawPassword, encryptionStrength } = metadata;
6451
6603
  let { dataDescriptor, zip64, level, compressionMethod } = metadata;
6452
6604
  let maximumCompressedSize = 0;
6453
6605
  let uncompressedSize = 0;
6454
- if (passThrough) {
6455
- if (!reader) {
6456
- throw new Error(ERR_UNDEFINED_READER);
6457
- }
6606
+ if (passThrough && hasContent) {
6458
6607
  uncompressedSize = options[PROPERTY_NAME_UNCOMPRESSED_SIZE];
6459
6608
  if (uncompressedSize === UNDEFINED_VALUE) {
6460
6609
  throw new Error(ERR_UNDEFINED_UNCOMPRESSED_SIZE);
@@ -6462,29 +6611,30 @@ async function resolveSizes(zipWriter, reader, { resolvedOptions: metadata }, op
6462
6611
  }
6463
6612
  const zip64Enabled = zip64 === true;
6464
6613
  const encrypted = getOptionValue(zipWriter, options, PROPERTY_NAME_ENCRYPTED);
6465
- const encryptedEntry = Boolean(reader) && (Boolean((password && getLength(password)) || (rawPassword && getLength(rawPassword))) || (passThrough && encrypted));
6466
- if (!reader) {
6614
+ if (hasContent && passThrough && !encrypted && getLength(password, rawPassword)) {
6615
+ throw new Error(ERR_UNSUPPORTED_ENCRYPTION_PASS_THROUGH);
6616
+ }
6617
+ const encryptedEntry = hasContent && (Boolean((password && getLength(password)) || (rawPassword && getLength(rawPassword))) || (passThrough && encrypted));
6618
+ if (!hasContent) {
6467
6619
  level = 0;
6468
6620
  compressionMethod = COMPRESSION_METHOD_STORE;
6469
6621
  }
6470
6622
  const encryptionOverhead = encryptedEntry ? (zipCrypto ? 12 : 16 + encryptionStrength * 4) : 0;
6471
- if (reader) {
6472
- reader = new GenericReader(reader);
6473
- await initStream(reader);
6623
+ if (hasContent) {
6474
6624
  if (!passThrough) {
6475
- if (reader.size === UNDEFINED_VALUE) {
6625
+ if (contentSize === UNDEFINED_VALUE) {
6476
6626
  dataDescriptor = true;
6477
6627
  if (zip64 || zip64 === UNDEFINED_VALUE) {
6478
6628
  zip64 = true;
6479
6629
  uncompressedSize = maximumCompressedSize = MAX_32_BITS + 1;
6480
6630
  }
6481
6631
  } else {
6482
- options.uncompressedSize = uncompressedSize = reader.size;
6483
- maximumCompressedSize = getMaximumCompressedSize(uncompressedSize) + encryptionOverhead;
6632
+ options.uncompressedSize = uncompressedSize = contentSize;
6633
+ maximumCompressedSize = (isCompressed(compressionMethod, level) ? getMaximumCompressedSize(uncompressedSize) : uncompressedSize) + encryptionOverhead;
6484
6634
  }
6485
6635
  } else {
6486
6636
  options.uncompressedSize = uncompressedSize;
6487
- maximumCompressedSize = getMaximumCompressedSize(uncompressedSize) + encryptionOverhead;
6637
+ maximumCompressedSize = contentSize === UNDEFINED_VALUE ? getMaximumCompressedSize(uncompressedSize) + encryptionOverhead : contentSize;
6488
6638
  }
6489
6639
  }
6490
6640
  const zip64UncompressedSize = zip64Enabled || uncompressedSize >= MAX_32_BITS;
@@ -6498,7 +6648,7 @@ async function resolveSizes(zipWriter, reader, { resolvedOptions: metadata }, op
6498
6648
  }
6499
6649
  zip64 = zip64 || false;
6500
6650
  return {
6501
- reader,
6651
+ maximumCompressedSize,
6502
6652
  resolvedOptions: {
6503
6653
  dataDescriptor,
6504
6654
  zip64,
@@ -6512,6 +6662,81 @@ async function resolveSizes(zipWriter, reader, { resolvedOptions: metadata }, op
6512
6662
  };
6513
6663
  }
6514
6664
 
6665
+ async function getEntriesSize(writerOptions, entries, writeOrderGuaranteed, comment) {
6666
+ const zipWriter = { options: writerOptions, config: getConfiguration() };
6667
+ if (writerOptions[OPTION_SIGN_CENTRAL_DIRECTORY]) {
6668
+ throw new Error(ERR_UNDETERMINED_SIZE);
6669
+ }
6670
+ if (comment !== UNDEFINED_VALUE && !(comment instanceof Uint8Array)) {
6671
+ throw new Error(ERR_INVALID_COMMENT_TYPE);
6672
+ }
6673
+ const commentLength = getLength(comment);
6674
+ if (commentLength > MAX_16_BITS) {
6675
+ throw new Error(ERR_INVALID_COMMENT);
6676
+ }
6677
+ const usdz = writerOptions[OPTION_USDZ];
6678
+ const files = new Map();
6679
+ let layoutDependsOnWriteOrder = Boolean(usdz);
6680
+ let offset = 0;
6681
+ for (const entry of entries) {
6682
+ let { name } = entry;
6683
+ const { size } = entry;
6684
+ const options = Object.assign({}, entry.options);
6685
+ name = name.trim();
6686
+ if (getOptionValue(zipWriter, options, PROPERTY_NAME_DIRECTORY) && !name.endsWith(DIRECTORY_SIGNATURE)) {
6687
+ name += DIRECTORY_SIGNATURE;
6688
+ }
6689
+ const attributesInfo = resolveAttributes(zipWriter, name, options);
6690
+ ({ name } = attributesInfo);
6691
+ const { resolvedOptions: metadata } = resolveMetadata(zipWriter, name, options);
6692
+ if (metadata.level != 0 && metadata.compressionMethod === UNDEFINED_VALUE &&
6693
+ !metadata.passThrough && !(await supportsDeflate(zipWriter.config))) {
6694
+ metadata.level = 0;
6695
+ }
6696
+ const hasContent = !getOptionValue(zipWriter, options, PROPERTY_NAME_DIRECTORY);
6697
+ if (hasContent && size === UNDEFINED_VALUE) {
6698
+ throw new Error(ERR_UNDETERMINED_SIZE);
6699
+ }
6700
+ const { maximumCompressedSize, resolvedOptions: sizes } = resolveEntrySizes(zipWriter, hasContent, size, metadata, options);
6701
+ if (hasContent && !metadata.passThrough && isCompressed(sizes.compressionMethod, sizes.level)) {
6702
+ throw new Error(ERR_UNDETERMINED_SIZE);
6703
+ }
6704
+ const entryOptions = Object.assign({}, options, attributesInfo.resolvedOptions, metadata, sizes);
6705
+ const headerInfo = getHeaderInfo(entryOptions);
6706
+ const dataDescriptorInfo = getDataDescriptorInfo(entryOptions);
6707
+ const entryInfo = {
6708
+ headerInfo,
6709
+ metadataSize: getLength(headerInfo.localHeaderArray, dataDescriptorInfo.dataDescriptorArray)
6710
+ };
6711
+ if (usdz) {
6712
+ appendExtraFieldUSDZ(entryInfo, offset);
6713
+ }
6714
+ const compressedSize = hasContent ? maximumCompressedSize : 0;
6715
+ if (offset >= MAX_32_BITS) {
6716
+ layoutDependsOnWriteOrder = true;
6717
+ }
6718
+ files.set(name, Object.assign({}, entryOptions, headerInfo, {
6719
+ offset,
6720
+ diskNumberStart: 0,
6721
+ compressedSize
6722
+ }));
6723
+ offset += entryInfo.metadataSize + compressedSize;
6724
+ }
6725
+ if (layoutDependsOnWriteOrder && !writeOrderGuaranteed) {
6726
+ throw new Error(ERR_UNDETERMINED_SIZE);
6727
+ }
6728
+ const directoryDataLength = createDirectoryRecords(files);
6729
+ let zip64 = getOptionValue(zipWriter, writerOptions, PROPERTY_NAME_ZIP64);
6730
+ if (offset >= MAX_32_BITS || directoryDataLength >= MAX_32_BITS || files.size >= MAX_16_BITS) {
6731
+ if (zip64 === false) {
6732
+ throw new Error(ERR_UNSUPPORTED_FORMAT);
6733
+ } else {
6734
+ zip64 = true;
6735
+ }
6736
+ }
6737
+ return offset + directoryDataLength + commentLength + (zip64 ? ZIP64_END_OF_CENTRAL_DIR_TOTAL_LENGTH : END_OF_CENTRAL_DIR_LENGTH);
6738
+ }
6739
+
6515
6740
  async function getFileEntry(zipWriter, name, reader, entryInfo, options) {
6516
6741
  const {
6517
6742
  files,
@@ -6726,6 +6951,7 @@ async function createFileEntry(reader, writer, { diskNumberStart, lock }, entryI
6726
6951
  uid,
6727
6952
  gid,
6728
6953
  unixMode,
6954
+ symlink,
6729
6955
  setuid,
6730
6956
  setgid,
6731
6957
  sticky,
@@ -6762,6 +6988,7 @@ async function createFileEntry(reader, writer, { diskNumberStart, lock }, entryI
6762
6988
  uid,
6763
6989
  gid,
6764
6990
  unixMode,
6991
+ symlink: Boolean(symlink),
6765
6992
  setuid,
6766
6993
  setgid,
6767
6994
  sticky,
@@ -6842,8 +7069,8 @@ async function createFileEntry(reader, writer, { diskNumberStart, lock }, entryI
6842
7069
  rawLastModDate,
6843
7070
  creationDate,
6844
7071
  lastAccessDate,
6845
- encrypted,
6846
- zipCrypto,
7072
+ encrypted: Boolean(encrypted),
7073
+ zipCrypto: Boolean(zipCrypto),
6847
7074
  size: metadataSize + compressedSize,
6848
7075
  compressionMethod,
6849
7076
  version,
@@ -6883,9 +7110,7 @@ function getHeaderInfo(options) {
6883
7110
  crc32
6884
7111
  } = options;
6885
7112
  let { version, compressionMethod } = options;
6886
- const compressed = !directory && (compressionMethod === UNDEFINED_VALUE
6887
- ? (level === UNDEFINED_VALUE || level > 0)
6888
- : compressionMethod !== COMPRESSION_METHOD_STORE);
7113
+ const compressed = !directory && isCompressed(compressionMethod, level);
6889
7114
  let rawLocalExtraFieldZip64;
6890
7115
  const uncompressedFile = passThrough || !compressed;
6891
7116
  const zip64ExtraFieldComplete = zip64 && (options.bufferedWrite || !dataDescriptor || ((!zip64UncompressedSize && !zip64CompressedSize) || uncompressedFile));
@@ -7572,6 +7797,16 @@ function getOptionValue(zipWriter, options, name, defaultValue) {
7572
7797
  return result === UNDEFINED_VALUE ? defaultValue : result;
7573
7798
  }
7574
7799
 
7800
+ function getAliasedOptionValue(zipWriter, options, name, deprecatedName, defaultValue) {
7801
+ const value = getAliasedValue(options, name, deprecatedName);
7802
+ const result = value === UNDEFINED_VALUE ? getAliasedValue(zipWriter.options, name, deprecatedName) : value;
7803
+ return result === UNDEFINED_VALUE ? defaultValue : result;
7804
+ }
7805
+
7806
+ function getAliasedValue(options, name, deprecatedName) {
7807
+ return options[name] === UNDEFINED_VALUE ? options[deprecatedName] : options[name];
7808
+ }
7809
+
7575
7810
  function getNumberOptionValue(zipWriter, options, name, defaultValue) {
7576
7811
  return toNumber(getOptionValue(zipWriter, options, name, defaultValue));
7577
7812
  }
@@ -7584,6 +7819,12 @@ function getMaximumCompressedSize(uncompressedSize) {
7584
7819
  return uncompressedSize + (5 * (Math.floor(uncompressedSize / 16383) + 1));
7585
7820
  }
7586
7821
 
7822
+ function isCompressed(compressionMethod, level) {
7823
+ return compressionMethod === UNDEFINED_VALUE
7824
+ ? (level === UNDEFINED_VALUE || level > 0)
7825
+ : compressionMethod !== COMPRESSION_METHOD_STORE;
7826
+ }
7827
+
7587
7828
  function setUint8(view, offset, value) {
7588
7829
  view.setUint8(offset, value);
7589
7830
  }
@@ -8597,6 +8838,7 @@ U(setDefaultConfiguration);
8597
8838
 
8598
8839
  const ERR_ENTRY_EXISTS = "Entry filename already exists";
8599
8840
  const ERR_READABLE_CONSUMED = "Readable stream already consumed";
8841
+ const ERR_INVALID_PASS_THROUGH = "Invalid passThrough option (use readerOptions.passThrough or set uncompressedSize for each entry)";
8600
8842
  const ERR_ABORT_EXPORT = "zipjs-abort-export";
8601
8843
  const ERR_ABORTED = "The operation was aborted";
8602
8844
  const ABORT_ERROR_NAME = "AbortError";
@@ -8634,6 +8876,7 @@ class ZipEntry {
8634
8876
  parent,
8635
8877
  children: [],
8636
8878
  uncompressedSize: params.uncompressedSize || 0,
8879
+ undeterminedSize: params.undeterminedSize || params.uncompressedSize === UNDEFINED_VALUE,
8637
8880
  passThrough: params.passThrough
8638
8881
  });
8639
8882
  if (parent || !fs.root) {
@@ -8701,16 +8944,17 @@ class ZipFileEntry extends ZipEntry {
8701
8944
 
8702
8945
  async getData(writer, options = {}) {
8703
8946
  const zipEntry = this;
8704
- if (!writer || (writer.constructor == zipEntry.Writer && zipEntry.data)) {
8947
+ if (!writer || (writer.constructor == zipEntry.Writer && zipEntry.data && keepsContentType(writer, zipEntry.data))) {
8705
8948
  return zipEntry.data;
8706
8949
  } else {
8707
8950
  const reader = zipEntry.reader = createReader(zipEntry.Reader, zipEntry.data, options);
8708
- const uncompressedSize = zipEntry.data ? zipEntry.data.uncompressedSize : reader.size;
8709
- await Promise.all([initStream(reader), initStream(writer, uncompressedSize)]);
8710
- const { readable } = reader;
8951
+ const dataSize = zipEntry.uncompressedSize || reader.size;
8952
+ await Promise.all([initStream(reader), initStream(writer, dataSize)]);
8711
8953
  const { signal } = options;
8954
+ const readable = createProgressReadable(zipEntry, reader, options, signal);
8955
+ const preventClose = !ownsWritable(writer) && Boolean(options.preventClose);
8712
8956
  zipEntry.uncompressedSize = reader.size;
8713
- await toCompatibleReadable(readable).pipeTo(toCompatibleWritable(writer.writable), { signal });
8957
+ await toCompatibleReadable(readable).pipeTo(toCompatibleWritable(writer.writable), { signal, preventClose, preventAbort: preventClose });
8714
8958
  return writer.getData ? writer.getData() : writer.writable;
8715
8959
  }
8716
8960
  }
@@ -8841,7 +9085,7 @@ class ZipDirectoryEntry extends ZipEntry {
8841
9085
  Reader: TextReader,
8842
9086
  Writer: TextWriter,
8843
9087
  options,
8844
- uncompressedSize: text.length
9088
+ uncompressedSize: getTextSize(text)
8845
9089
  });
8846
9090
  }
8847
9091
 
@@ -8970,10 +9214,16 @@ class ZipDirectoryEntry extends ZipEntry {
8970
9214
  }
8971
9215
 
8972
9216
  async importZip(reader, options = {}) {
8973
- await initStream(reader);
8974
- const zipReader = new ZipReader(reader, options);
9217
+ let zipReader;
9218
+ if (reader && typeof reader.getEntries == FUNCTION_TYPE) {
9219
+ zipReader = reader;
9220
+ options = Object.assign({}, zipReader.options, options);
9221
+ } else {
9222
+ await initStream(reader);
9223
+ zipReader = new ZipReader(reader, options);
9224
+ }
8975
9225
  const importedEntries = [];
8976
- const entries = await zipReader.getEntries();
9226
+ const entries = await zipReader.getEntries(options);
8977
9227
  for (const entry of entries) {
8978
9228
  let parent = this;
8979
9229
  try {
@@ -8995,7 +9245,7 @@ class ZipDirectoryEntry extends ZipEntry {
8995
9245
  importedEntries.push(addChild(parent, name, {
8996
9246
  data: entry,
8997
9247
  Reader: getZipBlobReader(Object.assign({}, options)),
8998
- uncompressedSize: entry.uncompressedSize,
9248
+ uncompressedSize: options.passThrough ? entry.compressedSize : entry.uncompressedSize,
8999
9249
  passThrough: options.passThrough
9000
9250
  }));
9001
9251
  } else {
@@ -9037,11 +9287,25 @@ class ZipDirectoryEntry extends ZipEntry {
9037
9287
  }
9038
9288
  const [readers] = await Promise.all([initReaders(zipEntry, options.readerOptions), initStream(writer)]);
9039
9289
  const zipWriter = new ZipWriter(writer, options);
9040
- await exportZip(zipWriter, zipEntry, getTotalSize([zipEntry], "uncompressedSize"), options, readers);
9041
- await zipWriter.close();
9290
+ await exportZip(zipWriter, zipEntry, getTotalSize([zipEntry], getUncompressedSize), options, readers);
9291
+ await zipWriter.close(options.globalComment);
9042
9292
  return writer.getData ? writer.getData() : writer.writable;
9043
9293
  }
9044
9294
 
9295
+ getExportedSize(options = {}) {
9296
+ const zipEntry = this;
9297
+ options = Object.assign({}, options);
9298
+ if (options.bufferedWrite === UNDEFINED_VALUE) {
9299
+ options.bufferedWrite = true;
9300
+ }
9301
+ const writeOrderGuaranteed = !options.bufferedWrite ||
9302
+ (options.keepOrder !== false && zipEntry.children.every(child => !child.children.length));
9303
+ return getEntriesSize(options, Array.from(zipEntry.getChildren({ recursive: true }), child => {
9304
+ const { name, entryOptions } = getChildEntryOptions(child, zipEntry, options);
9305
+ return { name, size: child.directory ? 0 : getDeterminedSize(child, isPassThrough(child, options)), options: entryOptions };
9306
+ }), writeOrderGuaranteed, options.globalComment);
9307
+ }
9308
+
9045
9309
  getChildByName(name) {
9046
9310
  const children = this.children;
9047
9311
  for (let childIndex = 0; childIndex < children.length; childIndex++) {
@@ -9249,6 +9513,10 @@ class FS {
9249
9513
  return this.root.exportZip(writer, options);
9250
9514
  }
9251
9515
 
9516
+ getExportedSize(options) {
9517
+ return this.root.getExportedSize(options);
9518
+ }
9519
+
9252
9520
  isPasswordProtected() {
9253
9521
  return this.root.isPasswordProtected();
9254
9522
  }
@@ -9260,12 +9528,12 @@ class FS {
9260
9528
 
9261
9529
  const fs = { FS, ZipDirectoryEntry, ZipFileEntry };
9262
9530
 
9263
- function getTotalSize(entries, propertyName) {
9531
+ function getTotalSize(entries, getEntrySize) {
9264
9532
  let size = 0;
9265
9533
  const pendingEntries = Array.from(entries);
9266
9534
  while (pendingEntries.length) {
9267
9535
  const entry = pendingEntries.pop();
9268
- size += entry[propertyName] || 0;
9536
+ size += getEntrySize(entry) || 0;
9269
9537
  for (const child of entry.children) {
9270
9538
  pendingEntries.push(child);
9271
9539
  }
@@ -9273,6 +9541,15 @@ function getTotalSize(entries, propertyName) {
9273
9541
  return size;
9274
9542
  }
9275
9543
 
9544
+ function getUncompressedSize(entry) {
9545
+ return entry.uncompressedSize;
9546
+ }
9547
+
9548
+ function getExtractedSize(entry, passThrough) {
9549
+ const { data } = entry;
9550
+ return passThrough && data instanceof Entry ? data.compressedSize : entry.uncompressedSize;
9551
+ }
9552
+
9276
9553
  function getReadableReader(readable) {
9277
9554
  let consumed;
9278
9555
  return function () {
@@ -9295,10 +9572,17 @@ function getZipBlobReader(options) {
9295
9572
 
9296
9573
  async init() {
9297
9574
  const zipBlobReader = this;
9298
- zipBlobReader.size = zipBlobReader.entry.uncompressedSize;
9299
- const data = await zipBlobReader.entry.getData(new BlobWriter(), Object.assign({}, options, zipBlobReader.options));
9575
+ const readerOptions = Object.assign({}, options, zipBlobReader.options);
9576
+ const { checkOverlappingEntry, checkOverlappingEntryOnly } = readerOptions;
9577
+ const data = await zipBlobReader.entry.getData(new BlobWriter(), Object.assign(readerOptions, {
9578
+ checkPasswordOnly: false,
9579
+ checkOverlappingEntry: checkOverlappingEntryOnly || checkOverlappingEntry,
9580
+ checkOverlappingEntryOnly: false,
9581
+ preventClose: false
9582
+ }));
9300
9583
  zipBlobReader.data = data;
9301
9584
  zipBlobReader.blobReader = new BlobReader(data);
9585
+ zipBlobReader.size = data.size;
9302
9586
  super.init();
9303
9587
  }
9304
9588
 
@@ -9312,6 +9596,30 @@ function createReader(Reader, data, options) {
9312
9596
  return Reader.prototype ? new Reader(data, options) : Reader(data, options);
9313
9597
  }
9314
9598
 
9599
+ function keepsContentType(writer, data) {
9600
+ const { contentType } = writer;
9601
+ if (contentType === UNDEFINED_VALUE) {
9602
+ return true;
9603
+ } else if (writer.constructor == BlobWriter) {
9604
+ return data.type == contentType;
9605
+ } else if (writer.constructor == Data64URIWriter) {
9606
+ return data.startsWith(writer.data);
9607
+ } else {
9608
+ return true;
9609
+ }
9610
+ }
9611
+
9612
+ function createProgressReadable(zipEntry, reader, options, signal) {
9613
+ const { onstart, onprogress, onend } = options;
9614
+ const { readable } = reader;
9615
+ const coreReaderReportsProgress = zipEntry.data instanceof Entry;
9616
+ if (coreReaderReportsProgress || (!onstart && !onprogress && !onend)) {
9617
+ return readable;
9618
+ } else {
9619
+ return toCompatibleReadable(readable).pipeThrough(new ProgressWatcherStream({ onstart, onprogress, onend, size: reader.size }), { signal });
9620
+ }
9621
+ }
9622
+
9315
9623
  async function initReaders(entry, options) {
9316
9624
  const fileEntries = [];
9317
9625
  const pendingEntries = [entry];
@@ -9344,6 +9652,7 @@ async function initReaders(entry, options) {
9344
9652
  }
9345
9653
  if (reader.size !== UNDEFINED_VALUE) {
9346
9654
  child.uncompressedSize = reader.size;
9655
+ child.undeterminedSize = false;
9347
9656
  }
9348
9657
  }));
9349
9658
  return readers;
@@ -9393,6 +9702,90 @@ function aggregateEntryErrors(errors) {
9393
9702
  return error;
9394
9703
  }
9395
9704
 
9705
+ function getChildEntryOptions(child, selectedEntry, options) {
9706
+ const name = options.relativePath ? child.getRelativeName(selectedEntry) : child.getFullname();
9707
+ const childOptions = child.options || {};
9708
+ let zipEntryMetadata = {};
9709
+ let passThroughOptions = {};
9710
+ if (child.data instanceof Entry) {
9711
+ const {
9712
+ externalFileAttributes,
9713
+ versionMadeBy,
9714
+ comment,
9715
+ lastModDate,
9716
+ creationDate,
9717
+ lastAccessDate,
9718
+ uncompressedSize,
9719
+ encrypted,
9720
+ zipCrypto,
9721
+ crc32,
9722
+ compressionMethod,
9723
+ extraFieldAES,
9724
+ internalFileAttributes,
9725
+ extraField,
9726
+ uid,
9727
+ gid
9728
+ } = child.data;
9729
+ zipEntryMetadata = {
9730
+ externalFileAttributes,
9731
+ versionMadeBy,
9732
+ comment,
9733
+ lastModDate,
9734
+ creationDate,
9735
+ lastAccessDate,
9736
+ internalFileAttributes
9737
+ };
9738
+ const userExtraField = getUserExtraField(extraField);
9739
+ if (userExtraField) {
9740
+ zipEntryMetadata.extraField = userExtraField;
9741
+ }
9742
+ if (uid !== UNDEFINED_VALUE || gid !== UNDEFINED_VALUE) {
9743
+ Object.assign(zipEntryMetadata, {
9744
+ uid,
9745
+ gid,
9746
+ unixExtraFieldType: INFOZIP_EXTRA_FIELD_TYPE
9747
+ });
9748
+ }
9749
+ if (isPassThrough(child, options)) {
9750
+ let level, encryptionStrength;
9751
+ if (compressionMethod === 0) {
9752
+ level = 0;
9753
+ }
9754
+ if (extraFieldAES) {
9755
+ encryptionStrength = extraFieldAES.strength;
9756
+ }
9757
+ passThroughOptions = {
9758
+ passThrough: true,
9759
+ encrypted,
9760
+ zipCrypto,
9761
+ crc32,
9762
+ uncompressedSize,
9763
+ level,
9764
+ encryptionStrength,
9765
+ compressionMethod
9766
+ };
9767
+ }
9768
+ }
9769
+ const entryOptions = Object.assign({}, zipEntryMetadata, options, passThroughOptions, childOptions, { directory: child.directory });
9770
+ if (!child.directory && entryOptions.passThrough && entryOptions.uncompressedSize === UNDEFINED_VALUE) {
9771
+ throw new Error(ERR_INVALID_PASS_THROUGH);
9772
+ }
9773
+ return { name, entryOptions };
9774
+ }
9775
+
9776
+ function getDeterminedSize(child, passThrough) {
9777
+ const { reader } = child;
9778
+ if (reader && reader.size !== UNDEFINED_VALUE) {
9779
+ return reader.size;
9780
+ }
9781
+ return child.undeterminedSize ? UNDEFINED_VALUE : getExtractedSize(child, passThrough);
9782
+ }
9783
+
9784
+ function isPassThrough(child, options) {
9785
+ const { readerOptions } = options;
9786
+ return Boolean(!child.directory && (child.passThrough || (readerOptions && readerOptions.passThrough)));
9787
+ }
9788
+
9396
9789
  function getUserExtraField(extraField) {
9397
9790
  if (extraField) {
9398
9791
  const userExtraField = new Map();
@@ -9408,8 +9801,14 @@ function getUserExtraField(extraField) {
9408
9801
  }
9409
9802
 
9410
9803
  async function exportZip(zipWriter, entry, totalSize, options, readers) {
9804
+ const { onstart, onprogress, onend, onentryprogress } = options;
9411
9805
  const selectedEntry = entry;
9412
- const entryOffsets = new Map();
9806
+ const totalEntries = getTotalSize(entry.children, () => 1);
9807
+ let writtenSize = 0;
9808
+ let writtenEntries = 0;
9809
+ if (onstart) {
9810
+ await callHandler(onstart, totalSize);
9811
+ }
9413
9812
  if (options.bufferedWrite) {
9414
9813
  await processChildren(entry);
9415
9814
  } else {
@@ -9417,6 +9816,9 @@ async function exportZip(zipWriter, entry, totalSize, options, readers) {
9417
9816
  await addChild(child);
9418
9817
  }
9419
9818
  }
9819
+ if (onend) {
9820
+ await callHandler(onend, writtenSize);
9821
+ }
9420
9822
 
9421
9823
  async function processChildren(entry) {
9422
9824
  const results = await Promise.allSettled(entry.children.map(async child => {
@@ -9430,81 +9832,23 @@ async function exportZip(zipWriter, entry, totalSize, options, readers) {
9430
9832
  }
9431
9833
 
9432
9834
  async function addChild(child) {
9433
- const name = options.relativePath ? child.getRelativeName(selectedEntry) : child.getFullname();
9434
- const childOptions = child.options || {};
9435
- let zipEntryOptions = {};
9436
- if (child.data instanceof Entry) {
9437
- const {
9438
- externalFileAttributes,
9439
- versionMadeBy,
9440
- comment,
9441
- lastModDate,
9442
- creationDate,
9443
- lastAccessDate,
9444
- uncompressedSize,
9445
- encrypted,
9446
- zipCrypto,
9447
- crc32,
9448
- compressionMethod,
9449
- extraFieldAES,
9450
- internalFileAttributes,
9451
- extraField,
9452
- uid,
9453
- gid
9454
- } = child.data;
9455
- zipEntryOptions = {
9456
- externalFileAttributes,
9457
- versionMadeBy,
9458
- comment,
9459
- lastModDate,
9460
- creationDate,
9461
- lastAccessDate,
9462
- internalFileAttributes
9463
- };
9464
- const userExtraField = getUserExtraField(extraField);
9465
- if (userExtraField) {
9466
- zipEntryOptions.extraField = userExtraField;
9467
- }
9468
- if (uid !== UNDEFINED_VALUE || gid !== UNDEFINED_VALUE) {
9469
- Object.assign(zipEntryOptions, {
9470
- uid,
9471
- gid,
9472
- unixExtraFieldType: options.unixExtraFieldType || INFOZIP_EXTRA_FIELD_TYPE
9473
- });
9474
- }
9475
- if (child.passThrough) {
9476
- let level, encryptionStrength;
9477
- if (compressionMethod === 0) {
9478
- level = 0;
9479
- }
9480
- if (extraFieldAES) {
9481
- encryptionStrength = extraFieldAES.strength;
9482
- }
9483
- zipEntryOptions = Object.assign(zipEntryOptions, {
9484
- passThrough: true,
9485
- encrypted,
9486
- zipCrypto,
9487
- crc32,
9488
- uncompressedSize,
9489
- level,
9490
- encryptionStrength,
9491
- compressionMethod
9492
- });
9493
- }
9494
- }
9495
- await zipWriter.add(name, readers.get(child), Object.assign({}, options, zipEntryOptions, childOptions, {
9496
- directory: child.directory,
9835
+ const { name, entryOptions } = getChildEntryOptions(child, selectedEntry, options);
9836
+ let entryWrittenSize = 0;
9837
+ const entryMetadata = await zipWriter.add(name, readers.get(child), Object.assign(entryOptions, {
9838
+ onstart: UNDEFINED_VALUE,
9839
+ onend: UNDEFINED_VALUE,
9497
9840
  onprogress: async indexProgress => {
9498
- if (options.onprogress) {
9499
- entryOffsets.set(name, indexProgress);
9500
- try {
9501
- await options.onprogress(Array.from(entryOffsets.values()).reduce((previousValue, currentValue) => previousValue + currentValue), totalSize);
9502
- } catch {
9503
- // ignored
9504
- }
9841
+ writtenSize += indexProgress - entryWrittenSize;
9842
+ entryWrittenSize = indexProgress;
9843
+ if (onprogress) {
9844
+ await callHandler(onprogress, writtenSize, totalSize);
9505
9845
  }
9506
9846
  }
9507
9847
  }));
9848
+ writtenEntries++;
9849
+ if (onentryprogress) {
9850
+ await callHandler(onentryprogress, writtenEntries, totalEntries, entryMetadata);
9851
+ }
9508
9852
  }
9509
9853
  }
9510
9854
 
@@ -9532,7 +9876,7 @@ function addFileSystemHandle(zipEntry, handle, options) {
9532
9876
  })
9533
9877
  );
9534
9878
  } else if (handle.kind == "directory") {
9535
- const directoryEntry = parentEntry.addDirectory(handle.name);
9879
+ const directoryEntry = parentEntry.addDirectory(handle.name, options);
9536
9880
  addedEntries.push(directoryEntry);
9537
9881
  for await (const childHandle of handle.values()) {
9538
9882
  await addFile(directoryEntry, childHandle, addedEntries, entryName);
@@ -9554,15 +9898,29 @@ function addFileSystemHandle(zipEntry, handle, options) {
9554
9898
  }
9555
9899
 
9556
9900
  async function exportFileSystemHandle(zipEntry, directoryHandle, options) {
9557
- const totalSize = getTotalSize([zipEntry], "uncompressedSize");
9558
- const writtenSizes = new Map();
9901
+ const { onstart, onprogress, onend } = options;
9559
9902
  const abortController = new AbortController();
9560
9903
  const { signal } = abortController;
9561
9904
  const releaseSignal = forwardAbort(options.signal, abortController);
9905
+ const getDataOptions = Object.assign({}, options, options.readerOptions, {
9906
+ signal,
9907
+ onstart: UNDEFINED_VALUE,
9908
+ onprogress: UNDEFINED_VALUE,
9909
+ onend: UNDEFINED_VALUE,
9910
+ preventClose: false
9911
+ });
9912
+ const totalSize = getTotalSize([zipEntry], entry => getExtractedSize(entry, getDataOptions.passThrough));
9562
9913
  const exportedEntryNames = [];
9563
9914
  let exportAborted = false;
9915
+ let writtenSize = 0;
9564
9916
  try {
9917
+ if (onstart) {
9918
+ await callHandler(onstart, totalSize);
9919
+ }
9565
9920
  await exportChildren(zipEntry, directoryHandle);
9921
+ if (onend) {
9922
+ await callHandler(onend, writtenSize);
9923
+ }
9566
9924
  } catch (error) {
9567
9925
  try {
9568
9926
  error.exportedEntryNames = exportedEntryNames;
@@ -9575,6 +9933,25 @@ async function exportFileSystemHandle(zipEntry, directoryHandle, options) {
9575
9933
  }
9576
9934
  return directoryHandle;
9577
9935
 
9936
+ function createProgressWritable(writable) {
9937
+ const writer = writable.getWriter();
9938
+ return new WritableStream({
9939
+ async write(chunk) {
9940
+ await writer.write(chunk);
9941
+ writtenSize += chunk.length;
9942
+ if (onprogress) {
9943
+ await callHandler(onprogress, writtenSize, totalSize);
9944
+ }
9945
+ },
9946
+ close() {
9947
+ return writer.close();
9948
+ },
9949
+ abort(reason) {
9950
+ return writer.abort(reason);
9951
+ }
9952
+ });
9953
+ }
9954
+
9578
9955
  async function exportChildren(entry, parentHandle) {
9579
9956
  if (options.concurrent) {
9580
9957
  const results = await Promise.allSettled(entry.children.map(child => exportChild(child, parentHandle)));
@@ -9606,19 +9983,7 @@ async function exportFileSystemHandle(zipEntry, directoryHandle, options) {
9606
9983
  const fileHandle = await parentHandle.getFileHandle(child.name, { create: true });
9607
9984
  const writable = await fileHandle.createWritable();
9608
9985
  try {
9609
- await child.getData({ writable }, Object.assign({}, options, {
9610
- signal,
9611
- onprogress: async progress => {
9612
- if (options.onprogress) {
9613
- writtenSizes.set(child.id, progress);
9614
- try {
9615
- await options.onprogress(Array.from(writtenSizes.values()).reduce((previousValue, currentValue) => previousValue + currentValue, 0), totalSize);
9616
- } catch {
9617
- // ignored
9618
- }
9619
- }
9620
- }
9621
- }));
9986
+ await child.getData({ writable: createProgressWritable(writable) }, getDataOptions);
9622
9987
  } catch (error) {
9623
9988
  throw exportAborted ? new Error(ERR_ABORT_EXPORT) : error;
9624
9989
  }
@@ -9847,6 +10212,7 @@ exports.ERR_INVALID_AUTHENTICATION_CODE = ERR_INVALID_AUTHENTICATION_CODE;
9847
10212
  exports.ERR_INVALID_CODEC_DEFINITION = ERR_INVALID_CODEC_DEFINITION;
9848
10213
  exports.ERR_INVALID_CODEC_MODULE = ERR_INVALID_CODEC_MODULE;
9849
10214
  exports.ERR_INVALID_COMMENT = ERR_INVALID_COMMENT;
10215
+ exports.ERR_INVALID_COMMENT_TYPE = ERR_INVALID_COMMENT_TYPE;
9850
10216
  exports.ERR_INVALID_COMPRESSED_DATA = ERR_INVALID_COMPRESSED_DATA;
9851
10217
  exports.ERR_INVALID_CRC32 = ERR_INVALID_CRC32;
9852
10218
  exports.ERR_INVALID_ENCRYPTION_STRENGTH = ERR_INVALID_ENCRYPTION_STRENGTH;
@@ -9862,6 +10228,7 @@ exports.ERR_INVALID_MSDOS_ATTRIBUTES = ERR_INVALID_MSDOS_ATTRIBUTES;
9862
10228
  exports.ERR_INVALID_MSDOS_DATA = ERR_INVALID_MSDOS_DATA;
9863
10229
  exports.ERR_INVALID_PASSWORD = ERR_INVALID_PASSWORD;
9864
10230
  exports.ERR_INVALID_PASSWORD_TYPE = ERR_INVALID_PASSWORD_TYPE;
10231
+ exports.ERR_INVALID_PASS_THROUGH = ERR_INVALID_PASS_THROUGH;
9865
10232
  exports.ERR_INVALID_SIGNATURE = ERR_INVALID_SIGNATURE;
9866
10233
  exports.ERR_INVALID_SIGNATURE_DATA = ERR_INVALID_SIGNATURE_DATA;
9867
10234
  exports.ERR_INVALID_STRICTNESS = ERR_INVALID_STRICTNESS;
@@ -9879,11 +10246,13 @@ exports.ERR_RESERVED_COMPRESSION_METHOD = ERR_RESERVED_COMPRESSION_METHOD;
9879
10246
  exports.ERR_SPLIT_ZIP_FILE = ERR_SPLIT_ZIP_FILE;
9880
10247
  exports.ERR_UNDEFINED_READER = ERR_UNDEFINED_READER;
9881
10248
  exports.ERR_UNDEFINED_UNCOMPRESSED_SIZE = ERR_UNDEFINED_UNCOMPRESSED_SIZE;
10249
+ exports.ERR_UNDETERMINED_SIZE = ERR_UNDETERMINED_SIZE;
9882
10250
  exports.ERR_UNSAFE_FILENAME = ERR_UNSAFE_FILENAME;
9883
10251
  exports.ERR_UNSUPPORTED_COMPRESSION = ERR_UNSUPPORTED_COMPRESSION$1;
9884
10252
  exports.ERR_UNSUPPORTED_CONTEXT = ERR_UNSUPPORTED_CONTEXT;
9885
10253
  exports.ERR_UNSUPPORTED_CRYPTO_API = ERR_UNSUPPORTED_CRYPTO_API;
9886
10254
  exports.ERR_UNSUPPORTED_ENCRYPTION = ERR_UNSUPPORTED_ENCRYPTION;
10255
+ exports.ERR_UNSUPPORTED_ENCRYPTION_PASS_THROUGH = ERR_UNSUPPORTED_ENCRYPTION_PASS_THROUGH;
9887
10256
  exports.ERR_UNSUPPORTED_ENCRYPTION_USDZ = ERR_UNSUPPORTED_ENCRYPTION_USDZ;
9888
10257
  exports.ERR_UNSUPPORTED_FORMAT = ERR_UNSUPPORTED_FORMAT;
9889
10258
  exports.ERR_WORKER_STARTUP_TIMEOUT = ERR_WORKER_STARTUP_TIMEOUT;