@zip.js/zip.js 2.11.4 → 2.12.0

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 (50) hide show
  1. package/deno.json +1 -1
  2. package/dist/zip-core-external.js +427 -110
  3. package/dist/zip-core-external.min.js +1 -1
  4. package/dist/zip-core.js +437 -107
  5. package/dist/zip-core.min.js +1 -1
  6. package/dist/zip-fs-core-external.js +492 -230
  7. package/dist/zip-fs-core-external.min.js +1 -1
  8. package/dist/zip-fs-core.js +505 -227
  9. package/dist/zip-fs-core.min.js +1 -1
  10. package/dist/zip-fs-external.js +492 -230
  11. package/dist/zip-fs-external.min.js +1 -1
  12. package/dist/zip-fs-native.js +507 -229
  13. package/dist/zip-fs-native.min.js +1 -1
  14. package/dist/zip-fs.js +508 -230
  15. package/dist/zip-fs.min.js +1 -1
  16. package/dist/zip-legacy.js +439 -109
  17. package/dist/zip-legacy.min.js +1 -1
  18. package/dist/zip-native.js +439 -109
  19. package/dist/zip-native.min.js +1 -1
  20. package/dist/zip-web-worker-native.js +1 -1
  21. package/dist/zip-web-worker.js +1 -1
  22. package/dist/zip.js +440 -110
  23. package/dist/zip.min.js +1 -1
  24. package/index-native.cjs +507 -229
  25. package/index-native.min.js +1 -1
  26. package/index.cjs +508 -230
  27. package/index.d.cts +468 -59
  28. package/index.d.ts +468 -59
  29. package/index.min.js +1 -1
  30. package/lib/core/codec-worker-web.js +10 -2
  31. package/lib/core/codec-worker.js +4 -3
  32. package/lib/core/configuration.js +20 -5
  33. package/lib/core/constants.js +2 -0
  34. package/lib/core/io.js +13 -5
  35. package/lib/core/options.js +16 -0
  36. package/lib/core/streams/codec-stream.js +6 -0
  37. package/lib/core/util/warnings.js +42 -0
  38. package/lib/core/version.js +1 -1
  39. package/lib/core/web-worker-base.js +4 -3
  40. package/lib/core/web-worker-inline-native.js +1 -1
  41. package/lib/core/web-worker-inline-wasm.js +1 -1
  42. package/lib/core/zip-entry.js +49 -1
  43. package/lib/core/zip-fs.js +43 -132
  44. package/lib/core/zip-reader.js +106 -48
  45. package/lib/core/zip-writer.js +236 -54
  46. package/lib/zip-core-base.js +9 -3
  47. package/lib/zip-core-reader.js +2 -0
  48. package/lib/zip-core-writer.js +6 -1
  49. package/lib/zip-module-wasm-base.js +2 -2
  50. package/package.json +5 -3
@@ -125,6 +125,7 @@ const NUMBER_TYPE = "number";
125
125
  const BOOLEAN_TYPE = "boolean";
126
126
 
127
127
  const EMPTY_UINT8_ARRAY = new Uint8Array();
128
+ const SYMBOL_ASYNC_DISPOSE = Symbol.asyncDispose || Symbol();
128
129
 
129
130
  /*
130
131
  Copyright (c) 2022 Gildas Lormeau. All rights reserved.
@@ -169,6 +170,7 @@ const OPTION_CHECK_OVERLAPPING_ENTRY_ONLY = "checkOverlappingEntryOnly";
169
170
  const OPTION_CHECK_OVERLAPPING_ENTRY = "checkOverlappingEntry";
170
171
  const OPTION_CHECK_AMBIGUITY = "checkAmbiguity";
171
172
  const OPTION_CHECK_LOCAL_DIRECTORY = "checkLocalDirectory";
173
+ const OPTION_CHECK_LOCAL_FILENAME = "checkLocalFilename";
172
174
  const OPTION_CHECK_SIGNATURE = "checkSignature";
173
175
  const OPTION_CHECK_CRC32 = "checkCrc32";
174
176
  const OPTION_CHECK_AUTHENTICATION_CODE = "checkAuthenticationCode";
@@ -199,15 +201,18 @@ const OPTION_NORMALIZE_FILENAME = "normalizeFilename";
199
201
  const OPTION_MAX_APPENDED_DATA_SIZE = "maxAppendedDataSize";
200
202
  const OPTION_DECRYPT_CENTRAL_DIRECTORY = "decryptCentralDirectory";
201
203
  const OPTION_SIGN_CENTRAL_DIRECTORY = "signCentralDirectory";
204
+ const OPTION_ENTRY = "entry";
202
205
  const TEXT_TYPE_FILENAME = "filename";
203
206
  const TEXT_TYPE_COMMENT = "comment";
204
207
  const STRICTNESS_STRICT = "strict";
205
208
  const STRICTNESS_BALANCED = "balanced";
206
209
  const STRICTNESS_TOLERANT = "tolerant";
210
+ const PASS_THROUGH_COMPRESSED = "compressed";
207
211
 
208
212
  const ERR_INVALID_FUNCTION_OPTION = "Invalid option (must be a function)";
209
213
  const ERR_INVALID_SIGNAL = "Invalid signal (must be an AbortSignal instance)";
210
214
  const ERR_INVALID_PASSWORD_TYPE = "Invalid password (password must be a string, rawPassword must be a Uint8Array)";
215
+ const ERR_INVALID_PASS_THROUGH_VALUE = "Invalid passThrough option (must be a boolean or 'compressed')";
211
216
  const ERR_ABORTED = "The operation was aborted";
212
217
  const ABORT_ERROR_NAME = "AbortError";
213
218
 
@@ -237,6 +242,13 @@ function checkPasswordOption(password, rawPassword) {
237
242
  }
238
243
  }
239
244
 
245
+ function checkPassThroughOption(passThrough) {
246
+ if (passThrough !== UNDEFINED_VALUE && typeof passThrough != BOOLEAN_TYPE && passThrough !== PASS_THROUGH_COMPRESSED) {
247
+ throw new Error(ERR_INVALID_PASS_THROUGH_VALUE);
248
+ }
249
+ return passThrough;
250
+ }
251
+
240
252
  function checkInteger(value, maxValue, errorMessage) {
241
253
  if (!Number.isInteger(value) || value < 0 || value > maxValue) {
242
254
  throw new Error(errorMessage);
@@ -286,6 +298,8 @@ const DEFAULT_CHUNK_SIZE$1 = 64 * 1024;
286
298
  const MINIMUM_CHUNK_SIZE = 64;
287
299
  const MINIMUM_PROPERTY_VALUE = 1;
288
300
  const ERR_INVALID_MAX_WORKERS = "Invalid maxWorkers (must be an integer greater than 0)";
301
+ const ERR_INVALID_BASE_URI = "Invalid baseURI (must be a string)";
302
+ const ERR_INVALID_URI = "Invalid URI (must be a string or a function returning a string)";
289
303
  let maxWorkers = 2;
290
304
  try {
291
305
  if (typeof navigator != UNDEFINED_TYPE && navigator.hardwareConcurrency) {
@@ -310,9 +324,9 @@ const DEFAULT_CONFIGURATION = {
310
324
  };
311
325
 
312
326
  const PROPERTY_NAME_MAX_WORKERS = "maxWorkers";
327
+ const PROPERTY_NAME_BASE_URI = "baseURI";
313
328
 
314
- const STRING_PROPERTY_NAMES = [
315
- "baseURI",
329
+ const URI_PROPERTY_NAMES = [
316
330
  "wasmURI",
317
331
  "workerURI"
318
332
  ];
@@ -336,7 +350,8 @@ const FUNCTION_PROPERTY_NAMES = [
336
350
  "DecompressionStreamFallback"
337
351
  ];
338
352
  const CONFIGURABLE_PROPERTY_NAMES = [
339
- ...STRING_PROPERTY_NAMES,
353
+ PROPERTY_NAME_BASE_URI,
354
+ ...URI_PROPERTY_NAMES,
340
355
  ...BOOLEAN_PROPERTY_NAMES,
341
356
  ...NUMBER_PROPERTY_NAMES,
342
357
  ...FUNCTION_PROPERTY_NAMES
@@ -380,6 +395,14 @@ function checkPropertyValue(propertyName, propertyValue) {
380
395
  }
381
396
  } else if (FUNCTION_PROPERTY_NAMES.includes(propertyName)) {
382
397
  checkFunctionOption(propertyValue);
398
+ } else if (propertyName == PROPERTY_NAME_BASE_URI) {
399
+ if (propertyValue && typeof propertyValue != STRING_TYPE) {
400
+ throw new Error(ERR_INVALID_BASE_URI);
401
+ }
402
+ } else if (URI_PROPERTY_NAMES.includes(propertyName)) {
403
+ if (propertyValue && typeof propertyValue != STRING_TYPE && typeof propertyValue != FUNCTION_TYPE) {
404
+ throw new Error(ERR_INVALID_URI);
405
+ }
383
406
  }
384
407
  return propertyValue;
385
408
  }
@@ -2632,6 +2655,7 @@ class ChunkStream extends TransformStream {
2632
2655
  constructor(chunkSize) {
2633
2656
  const pendingChunks = [];
2634
2657
  let pendingLength = 0;
2658
+ let outputSize = 0;
2635
2659
  if (!Number.isFinite(chunkSize) || chunkSize < 1) {
2636
2660
  chunkSize = DEFAULT_CHUNK_SIZE;
2637
2661
  }
@@ -2640,15 +2664,20 @@ class ChunkStream extends TransformStream {
2640
2664
  pendingChunks.push(chunk);
2641
2665
  pendingLength += chunk.length;
2642
2666
  while (pendingLength > chunkSize) {
2667
+ outputSize += chunkSize;
2643
2668
  controller.enqueue(shiftChunk());
2644
2669
  }
2645
2670
  },
2646
2671
  flush(controller) {
2647
2672
  if (pendingLength) {
2673
+ outputSize += pendingLength;
2648
2674
  controller.enqueue(concatChunks(pendingChunks, pendingLength));
2649
2675
  }
2650
2676
  }
2651
2677
  });
2678
+ Object.defineProperty(this, "outputSize", {
2679
+ get: () => outputSize
2680
+ });
2652
2681
 
2653
2682
  function shiftChunk() {
2654
2683
  const result = new Uint8Array(chunkSize);
@@ -2853,7 +2882,7 @@ function createWorkerInterface(workerData, config) {
2853
2882
  }
2854
2883
 
2855
2884
  async function runWorker$1({ options, readable, writable, onTaskFinished }, config) {
2856
- let codecStream;
2885
+ let codecStream, chunkStream;
2857
2886
  try {
2858
2887
  if (options.compressed && !options.format) {
2859
2888
  const deflate = options.codecType.startsWith(CODEC_DEFLATE);
@@ -2876,9 +2905,10 @@ async function runWorker$1({ options, readable, writable, onTaskFinished }, conf
2876
2905
  }
2877
2906
  }
2878
2907
  codecStream = new CodecStream(options, config);
2908
+ chunkStream = new ChunkStream(getChunkSize(config));
2879
2909
  await readable
2880
2910
  .pipeThrough(codecStream)
2881
- .pipeThrough(new ChunkStream(getChunkSize(config)))
2911
+ .pipeThrough(chunkStream)
2882
2912
  .pipeTo(writable, { preventClose: true, preventAbort: true });
2883
2913
  const {
2884
2914
  crc32,
@@ -2892,7 +2922,7 @@ async function runWorker$1({ options, readable, writable, onTaskFinished }, conf
2892
2922
  };
2893
2923
  } catch (error) {
2894
2924
  if (codecStream) {
2895
- error.outputSize = codecStream.outputSize;
2925
+ error.outputSize = chunkStream ? chunkStream.outputSize : 0;
2896
2926
  }
2897
2927
  throw error;
2898
2928
  } finally {
@@ -3001,11 +3031,17 @@ async function runWebWorker(workerData, config) {
3001
3031
  let resolveResult, rejectResult;
3002
3032
  const result = new Promise((resolve, reject) => {
3003
3033
  resolveResult = resolve;
3004
- rejectResult = reject;
3034
+ rejectResult = error => {
3035
+ if (error && error.outputSize === UNDEFINED_VALUE) {
3036
+ error.outputSize = workerData.outputSize;
3037
+ }
3038
+ reject(error);
3039
+ };
3005
3040
  });
3006
3041
  Object.assign(workerData, {
3007
3042
  reader: null,
3008
3043
  writer: null,
3044
+ outputSize: 0,
3009
3045
  resolveResult,
3010
3046
  rejectResult,
3011
3047
  result
@@ -3289,8 +3325,10 @@ async function onMessage({ data }, workerData) {
3289
3325
  }
3290
3326
  }
3291
3327
  if (type == MESSAGE_DATA) {
3328
+ const chunk = new Uint8Array(value);
3292
3329
  await writer.ready;
3293
- await writer.write(new Uint8Array(value));
3330
+ await writer.write(chunk);
3331
+ workerData.outputSize += chunk.length;
3294
3332
  if (!stale()) {
3295
3333
  sendMessage({ type: MESSAGE_ACK_DATA, messageId }, workerData);
3296
3334
  }
@@ -3598,10 +3636,13 @@ function decode(value, encoding, ignoreBOM) {
3598
3636
 
3599
3637
 
3600
3638
  const ERR_HTTP_STATUS = "HTTP error ";
3639
+ const MIN_SUCCESS_HTTP_STATUS = 200;
3640
+ const MAX_SUCCESS_HTTP_STATUS = 299;
3601
3641
  const ERR_HTTP_RANGE = "HTTP Range not supported";
3602
3642
  const ERR_HTTP_RESOURCE_CHANGED = "HTTP resource changed";
3603
3643
  const ERR_ITERATOR_COMPLETED_TOO_SOON = "Writer iterator completed too soon";
3604
3644
  const ERR_WRITER_NOT_INITIALIZED = "Writer not initialized";
3645
+ const ERR_WRITER_SIZE_NOT_WRITABLE = "Invalid writer (size must be writable)";
3605
3646
 
3606
3647
  const CONTENT_TYPE_TEXT_PLAIN = "text/plain";
3607
3648
  const HTTP_HEADER_CONTENT_LENGTH = "Content-Length";
@@ -3793,6 +3834,7 @@ class BlobReader extends Reader {
3793
3834
  const reader = this;
3794
3835
  const { sourceBlob, size } = reader;
3795
3836
  const { offset = 0, size: readSize = size - offset } = options || {};
3837
+ // deno-lint-ignore valid-typeof
3796
3838
  if (typeof sourceBlob.stream == FUNCTION_TYPE) {
3797
3839
  if (!offset && readSize >= size) {
3798
3840
  return toCompatibleReadable(sourceBlob.stream());
@@ -4179,7 +4221,7 @@ async function getContentLength(httpReader, sendRequest, getRequestData) {
4179
4221
 
4180
4222
  async function sendFetchRequest(method, { fetch: fetchFunction = fetch, options, url }, headers) {
4181
4223
  const response = await fetchFunction(url, Object.assign({}, options, { method, headers }));
4182
- if (response.status < 400) {
4224
+ if (response.status >= MIN_SUCCESS_HTTP_STATUS && response.status <= MAX_SUCCESS_HTTP_STATUS) {
4183
4225
  return response;
4184
4226
  } else {
4185
4227
  throw response.status == 416 ? new Error(ERR_HTTP_RANGE) : new Error(ERR_HTTP_STATUS + (response.statusText || response.status));
@@ -4190,7 +4232,7 @@ function sendXMLHttpRequest(method, { url }, headers) {
4190
4232
  return new Promise((resolve, reject) => {
4191
4233
  const request = new XMLHttpRequest();
4192
4234
  request.addEventListener("load", () => {
4193
- if (request.status < 400) {
4235
+ if (request.status >= MIN_SUCCESS_HTTP_STATUS && request.status <= MAX_SUCCESS_HTTP_STATUS) {
4194
4236
  const headers = [];
4195
4237
  request.getAllResponseHeaders().trim().split(/[\r\n]+/).forEach(header => {
4196
4238
  const splitHeader = header.trim().split(/\s*:\s*/);
@@ -4494,8 +4536,10 @@ class GenericWriter {
4494
4536
  writable: toCompatibleWritable(writer)
4495
4537
  };
4496
4538
  }
4497
- if (writer.size === UNDEFINED_VALUE) {
4498
- writer.size = 0;
4539
+ try {
4540
+ writer.size = writer.size === UNDEFINED_VALUE ? 0 : writer.size;
4541
+ } catch {
4542
+ throw new Error(ERR_WRITER_SIZE_NOT_WRITABLE);
4499
4543
  }
4500
4544
  return writer;
4501
4545
  }
@@ -4543,6 +4587,45 @@ function createReadable(reader, options) {
4543
4587
  }
4544
4588
  }
4545
4589
 
4590
+ /*
4591
+ Copyright (c) 2026 Gildas Lormeau. All rights reserved.
4592
+
4593
+ Redistribution and use in source and binary forms, with or without
4594
+ modification, are permitted provided that the following conditions are met:
4595
+
4596
+ 1. Redistributions of source code must retain the above copyright notice,
4597
+ this list of conditions and the following disclaimer.
4598
+
4599
+ 2. Redistributions in binary form must reproduce the above copyright
4600
+ notice, this list of conditions and the following disclaimer in
4601
+ the documentation and/or other materials provided with the distribution.
4602
+
4603
+ 3. The names of the authors may not be used to endorse or promote products
4604
+ derived from this software without specific prior written permission.
4605
+
4606
+ THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
4607
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
4608
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
4609
+ INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
4610
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
4611
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
4612
+ OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
4613
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
4614
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
4615
+ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
4616
+ */
4617
+
4618
+
4619
+ function addWarning(warnings, reason, filename) {
4620
+ if (!warnings.some(warning => warning.reason == reason)) {
4621
+ const warning = { reason };
4622
+ if (filename !== UNDEFINED_VALUE) {
4623
+ warning.filename = filename;
4624
+ }
4625
+ warnings.push(warning);
4626
+ }
4627
+ }
4628
+
4546
4629
  /*
4547
4630
  Copyright (c) 2025 Gildas Lormeau. All rights reserved.
4548
4631
 
@@ -4571,6 +4654,7 @@ function createReadable(reader, options) {
4571
4654
  EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
4572
4655
  */
4573
4656
 
4657
+
4574
4658
  const PROPERTY_NAME_FILENAME = "filename";
4575
4659
  const PROPERTY_NAME_RAW_FILENAME = "rawFilename";
4576
4660
  const PROPERTY_NAME_COMMENT = "comment";
@@ -4695,6 +4779,38 @@ class Entry {
4695
4779
 
4696
4780
  }
4697
4781
 
4782
+ const INTERPRETED_EXTRA_FIELD_TYPES = new Set([
4783
+ EXTRAFIELD_TYPE_ZIP64,
4784
+ EXTRAFIELD_TYPE_AES,
4785
+ EXTRAFIELD_TYPE_NTFS,
4786
+ EXTRAFIELD_TYPE_EXTENDED_TIMESTAMP,
4787
+ EXTRAFIELD_TYPE_UNICODE_PATH,
4788
+ EXTRAFIELD_TYPE_UNICODE_COMMENT,
4789
+ EXTRAFIELD_TYPE_USDZ,
4790
+ EXTRAFIELD_TYPE_INFOZIP,
4791
+ EXTRAFIELD_TYPE_UNIX,
4792
+ EXTRAFIELD_TYPE_UNIX_TYPE1,
4793
+ EXTRAFIELD_TYPE_PKWARE_UNIX
4794
+ ]);
4795
+
4796
+ function getUserExtraField(extraField) {
4797
+ if (extraField) {
4798
+ const userExtraField = new Map();
4799
+ extraField.forEach((field, type) => {
4800
+ if (!INTERPRETED_EXTRA_FIELD_TYPES.has(type)) {
4801
+ userExtraField.set(type, field.data);
4802
+ }
4803
+ });
4804
+ if (userExtraField.size) {
4805
+ return userExtraField;
4806
+ }
4807
+ }
4808
+ }
4809
+
4810
+ function getEncryptionOverhead(encrypted, zipCrypto, encryptionStrength) {
4811
+ return encrypted ? (zipCrypto ? 12 : 16 + encryptionStrength * 4) : 0;
4812
+ }
4813
+
4698
4814
  /*
4699
4815
  Copyright (c) 2025 Gildas Lormeau. All rights reserved.
4700
4816
 
@@ -4754,6 +4870,8 @@ const WARNING_PREPENDED_CENTRAL_DIRECTORY = "prepended central directory";
4754
4870
  const WARNING_TRAILING_CENTRAL_DIRECTORY_DATA = "trailing central directory data";
4755
4871
  const WARNING_DUPLICATE_FILENAME = "duplicate filename";
4756
4872
  const WARNING_MISMATCHED_ZIP64_END_OF_CENTRAL_DIRECTORY = "mismatched zip64 end of central directory record";
4873
+ const WARNING_MULTIPLE_END_OF_CENTRAL_DIRECTORY = "multiple end of central directory records";
4874
+ const WARNING_MISMATCHED_LOCAL_FILE_HEADER_FILENAME = "mismatched local file header (filename)";
4757
4875
  const WARNING_MISMATCHED_LOCAL_FILE_HEADER_BIT_FLAG = "mismatched local file header (general purpose bit flag)";
4758
4876
  const WARNING_MISMATCHED_LOCAL_FILE_HEADER_COMPRESSION_METHOD = "mismatched local file header (compression method)";
4759
4877
  const WARNING_MISMATCHED_LOCAL_FILE_HEADER_CRC32_OR_SIZES = "mismatched local file header (crc32 or sizes)";
@@ -4824,7 +4942,7 @@ class ZipReader {
4824
4942
  }
4825
4943
  }
4826
4944
  if (rejectAmbiguousEndOfDirectory && endOfDirectoryReachingEndCount > 1) {
4827
- throwAmbiguousArchive("multiple end of central directory records");
4945
+ throwAmbiguousArchive(WARNING_MULTIPLE_END_OF_CENTRAL_DIRECTORY);
4828
4946
  }
4829
4947
  const endOfDirectoryView = getDataView(endOfDirectoryInfo);
4830
4948
  let directoryDataLength = getUint32$1(endOfDirectoryView, 12);
@@ -5122,7 +5240,8 @@ class ZipReader {
5122
5240
  const writer = new TransformStream();
5123
5241
  const arrayBufferPromise = streamToBlob(writer.readable).then(blob => blob.arrayBuffer());
5124
5242
  arrayBufferPromise.catch(() => { });
5125
- await fileEntry.getData(writer, entry, zipReader.readRanges, options);
5243
+ await fileEntry.getData(writer, entry, zipReader.readRanges,
5244
+ Object.assign({}, options, { preventClose: false }));
5126
5245
  return arrayBufferPromise;
5127
5246
  };
5128
5247
  offset = endOffset;
@@ -5203,49 +5322,101 @@ class ZipReader {
5203
5322
  await reader.readable.cancel();
5204
5323
  }
5205
5324
  }
5325
+
5326
+ [SYMBOL_ASYNC_DISPOSE]() {
5327
+ return this.close();
5328
+ }
5206
5329
  }
5207
5330
 
5208
5331
  class ZipReaderStream {
5209
5332
 
5210
5333
  constructor(options = {}) {
5211
- const { readable, writable } = new TransformStream();
5212
- const gen = new ZipReader(readable, options).getEntriesGenerator();
5334
+ let sourceController;
5335
+ const { readable, writable } = new TransformStream({
5336
+ start(controller) {
5337
+ sourceController = controller;
5338
+ }
5339
+ });
5340
+ const zipReader = new ZipReader(readable, options);
5341
+ const gen = zipReader.getEntriesGenerator();
5342
+ const pendingEntries = new Set();
5213
5343
  this.readable = new ReadableStream({
5214
5344
  async pull(controller) {
5215
5345
  const { done, value } = await gen.next();
5216
5346
  if (done)
5217
5347
  return controller.close();
5218
- const entryReadable = (function () {
5219
- const { readable, writable } = new TransformStream();
5220
- if (value.getData) {
5221
- getData();
5222
- return readable;
5223
- }
5224
-
5225
- async function getData() {
5226
- try {
5227
- await value.getData(writable);
5228
- } catch (error) {
5229
- try {
5230
- await writable.abort(error);
5231
- } catch {
5232
- // ignored
5233
- }
5234
- }
5235
- }
5236
- })();
5348
+ const entryStream = createEntryStream(value, pendingEntries);
5237
5349
  const chunk = {
5238
5350
  ...value,
5239
- readable: entryReadable
5351
+ readable: entryStream.readable
5240
5352
  };
5241
5353
  delete chunk.getData;
5354
+ Object.defineProperties(chunk, {
5355
+ localDirectory: {
5356
+ get: () => value.localDirectory,
5357
+ enumerable: true
5358
+ },
5359
+ warnings: {
5360
+ get: () => value.warnings,
5361
+ enumerable: true
5362
+ }
5363
+ });
5242
5364
  controller.enqueue(chunk);
5365
+ },
5366
+ async cancel(reason) {
5367
+ const entryStreams = Array.from(pendingEntries);
5368
+ pendingEntries.clear();
5369
+ sourceController.error(reason);
5370
+ await Promise.allSettled(entryStreams.map(entryStream => entryStream.cancel(reason)));
5371
+ await Promise.allSettled([gen.return(), zipReader.close()]);
5243
5372
  }
5244
5373
  });
5245
5374
  this.writable = writable;
5246
5375
  }
5247
5376
  }
5248
5377
 
5378
+ function createEntryStream(entry, pendingEntries) {
5379
+ const { readable, writable } = new TransformStream();
5380
+ let dataReader;
5381
+ const entryStream = {
5382
+ cancel: async reason => {
5383
+ pendingEntries.delete(entryStream);
5384
+ await (dataReader ? dataReader.cancel(reason) : readable.cancel(reason));
5385
+ }
5386
+ };
5387
+ entryStream.readable = new ReadableStream({
5388
+ async pull(controller) {
5389
+ if (!dataReader) {
5390
+ dataReader = readable.getReader();
5391
+ pendingEntries.add(entryStream);
5392
+ getData();
5393
+ }
5394
+ const { done, value } = await dataReader.read();
5395
+ if (done) {
5396
+ controller.close();
5397
+ } else {
5398
+ controller.enqueue(value);
5399
+ }
5400
+ },
5401
+ cancel: reason => entryStream.cancel(reason)
5402
+ }, { highWaterMark: 0 });
5403
+ return entryStream;
5404
+
5405
+ async function getData() {
5406
+ try {
5407
+ await entry.getData(writable, { preventClose: false });
5408
+ } catch (error) {
5409
+ try {
5410
+ await writable.abort(error);
5411
+ } catch {
5412
+ // ignored
5413
+ }
5414
+ } finally {
5415
+ pendingEntries.delete(entryStream);
5416
+ }
5417
+ }
5418
+ }
5419
+
5249
5420
  async function isZipFile(reader, options = {}) {
5250
5421
  reader = new GenericReader(reader);
5251
5422
  await initStream(reader);
@@ -5305,7 +5476,9 @@ class ZipEntry {
5305
5476
  const dataView = getDataView(dataArray);
5306
5477
  let password = getOptionValue$1(zipEntry, options, OPTION_PASSWORD);
5307
5478
  let rawPassword = getOptionValue$1(zipEntry, options, OPTION_RAW_PASSWORD);
5308
- const passThrough = getOptionValue$1(zipEntry, options, OPTION_PASS_THROUGH);
5479
+ const passThrough = checkPassThroughOption(getOptionValue$1(zipEntry, options, OPTION_PASS_THROUGH));
5480
+ const passThroughCompression = Boolean(passThrough);
5481
+ const passThroughEncryption = passThrough === true;
5309
5482
  checkPasswordOption(password, rawPassword);
5310
5483
  password = password && password.length && password;
5311
5484
  rawPassword = rawPassword && rawPassword.length && rawPassword;
@@ -5326,7 +5499,9 @@ class ZipEntry {
5326
5499
  const checkLocalDirectoryOption = getOptionValue$1(zipEntry, options, OPTION_CHECK_LOCAL_DIRECTORY);
5327
5500
  const entryStrictness = getStrictness(options, zipEntry.options);
5328
5501
  const checkLocalDirectory = getCheckLocalDirectory(checkLocalDirectoryOption, entryStrictness);
5329
- const checkLocalFilename = getCheckLocalFilename(checkLocalDirectoryOption, entryStrictness);
5502
+ const checkLocalFilenameOption = getOptionValue$1(zipEntry, options, OPTION_CHECK_LOCAL_FILENAME);
5503
+ const checkLocalFilename = getCheckLocalFilename(
5504
+ checkLocalFilenameOption === UNDEFINED_VALUE ? checkLocalDirectoryOption : checkLocalFilenameOption, entryStrictness);
5330
5505
  let rawLocalFilename = EMPTY_UINT8_ARRAY;
5331
5506
  if (checkLocalFilename && (filenameLength || extraFieldLength)) {
5332
5507
  const trailingDataArray = await readUint8Array(reader, localHeaderOffset + HEADER_SIZE, filenameLength + extraFieldLength);
@@ -5357,16 +5532,17 @@ class ZipEntry {
5357
5532
  if (gid !== UNDEFINED_VALUE && fileEntry.gid === UNDEFINED_VALUE) {
5358
5533
  fileEntry.gid = gid;
5359
5534
  }
5360
- const encrypted = zipEntry.encrypted && localDirectory.encrypted && !passThrough;
5535
+ const checkPasswordOnly = getOptionValue$1(zipEntry, options, OPTION_CHECK_PASSWORD_ONLY);
5536
+ const encrypted = zipEntry.encrypted && localDirectory.encrypted && (!passThroughEncryption || checkPasswordOnly);
5361
5537
  const zipCrypto = encrypted && !extraFieldAES;
5362
- if (!passThrough) {
5538
+ if (!passThroughEncryption) {
5363
5539
  fileEntry.zipCrypto = zipCrypto;
5364
5540
  }
5365
5541
  if (encrypted && (localDirectory.rawBitFlag & BITFLAG_STRONG_ENCRYPTION) == BITFLAG_STRONG_ENCRYPTION) {
5366
5542
  throw new Error(ERR_UNSUPPORTED_ENCRYPTION);
5367
5543
  }
5368
- const registeredCodec = passThrough ? UNDEFINED_VALUE : getRegisteredCodec(compressionMethod);
5369
- if (compressionMethod != COMPRESSION_METHOD_STORE && compressionMethod != COMPRESSION_METHOD_DEFLATE && compressionMethod != COMPRESSION_METHOD_DEFLATE_64 && !registeredCodec && !passThrough) {
5544
+ const registeredCodec = passThroughCompression ? UNDEFINED_VALUE : getRegisteredCodec(compressionMethod);
5545
+ if (compressionMethod != COMPRESSION_METHOD_STORE && compressionMethod != COMPRESSION_METHOD_DEFLATE && compressionMethod != COMPRESSION_METHOD_DEFLATE_64 && !registeredCodec && !passThroughCompression) {
5370
5546
  throw new Error(ERR_UNSUPPORTED_COMPRESSION);
5371
5547
  }
5372
5548
  if (encrypted) {
@@ -5383,15 +5559,16 @@ class ZipEntry {
5383
5559
  const readable = toCompatibleReadable(reader.createReadable({ offset: dataOffset, size }));
5384
5560
  const signal = checkSignalOption(getOptionValue$1(zipEntry, options, OPTION_SIGNAL));
5385
5561
  throwIfAborted(signal);
5386
- const checkPasswordOnly = getOptionValue$1(zipEntry, options, OPTION_CHECK_PASSWORD_ONLY);
5387
5562
  let checkOverlappingEntry = getOptionValue$1(zipEntry, options, OPTION_CHECK_OVERLAPPING_ENTRY);
5388
5563
  const checkOverlappingEntryOnly = getOptionValue$1(zipEntry, options, OPTION_CHECK_OVERLAPPING_ENTRY_ONLY);
5389
5564
  if (checkOverlappingEntryOnly) {
5390
5565
  checkOverlappingEntry = true;
5391
5566
  }
5392
5567
  const { onstart, onprogress, onend } = options;
5393
- const compressed = compressionMethod != COMPRESSION_METHOD_STORE && !passThrough;
5394
- const outputSize = passThrough ? compressedSize : uncompressedSize;
5568
+ const compressed = compressionMethod != COMPRESSION_METHOD_STORE && !passThroughCompression;
5569
+ const outputSize = passThroughCompression ?
5570
+ compressedSize - getEncryptionOverhead(encrypted, zipCrypto, extraFieldAES && extraFieldAES.strength) :
5571
+ uncompressedSize;
5395
5572
  const deflate64 = compressionMethod == COMPRESSION_METHOD_DEFLATE_64;
5396
5573
  let useCompressionStream = getOptionValue$1(zipEntry, options, OPTION_USE_COMPRESSION_STREAM);
5397
5574
  if (deflate64) {
@@ -5400,7 +5577,7 @@ class ZipEntry {
5400
5577
  const checkCrc32Option = getOptionValue$1(zipEntry, options, OPTION_CHECK_CRC32);
5401
5578
  const checkCrc32 = (checkCrc32Option === UNDEFINED_VALUE ?
5402
5579
  getOptionValue$1(zipEntry, options, OPTION_CHECK_SIGNATURE) :
5403
- checkCrc32Option) && !passThrough &&
5580
+ checkCrc32Option) && !passThroughCompression &&
5404
5581
  (!encrypted || zipCrypto || (extraFieldAES && extraFieldAES.vendorVersion == VENDOR_VERSION_AE_1$1));
5405
5582
  const workerOptions = {
5406
5583
  options: {
@@ -5454,10 +5631,10 @@ class ZipEntry {
5454
5631
  await initStream(writer, getDecodableOutputSize(outputSize, compressedSize, compressed));
5455
5632
  ({ writable } = writer);
5456
5633
  const { outputSize: writtenSize } = await runWorker({ readable, writable }, workerOptions);
5457
- writer.size += writtenSize;
5458
5634
  if (writtenSize != outputSize) {
5459
- throw new Error(ERR_INVALID_UNCOMPRESSED_SIZE);
5635
+ throw Object.assign(new Error(ERR_INVALID_UNCOMPRESSED_SIZE), { outputSize: writtenSize });
5460
5636
  }
5637
+ writer.size += writtenSize;
5461
5638
  }
5462
5639
  } catch (error) {
5463
5640
  if (error.outputSize !== UNDEFINED_VALUE) {
@@ -6123,7 +6300,7 @@ function validateLocalDirectory(zipEntry, localDirectory, rawLocalFilename, chec
6123
6300
  if (checkLocalFilename && !maskedLocalDirectory &&
6124
6301
  (rawLocalFilename.length != rawFilename.length ||
6125
6302
  rawLocalFilename.some((byteValue, indexByte) => byteValue != rawFilename[indexByte]))) {
6126
- reportAmbiguity(reject, warnings, "mismatched local file header (filename)");
6303
+ reportAmbiguity(reject, warnings, WARNING_MISMATCHED_LOCAL_FILE_HEADER_FILENAME);
6127
6304
  }
6128
6305
  if ((localDirectory.rawBitFlag & BITFLAG_AMBIGUITY_MASK) != (zipEntry.rawBitFlag & BITFLAG_AMBIGUITY_MASK)) {
6129
6306
  reportAmbiguity(reject, warnings, WARNING_MISMATCHED_LOCAL_FILE_HEADER_BIT_FLAG);
@@ -6148,16 +6325,6 @@ function reportAmbiguity(reject, warnings, reason) {
6148
6325
  }
6149
6326
  }
6150
6327
 
6151
- function addWarning(warnings, reason, filename) {
6152
- if (!warnings.some(warning => warning.reason == reason)) {
6153
- const warning = { reason };
6154
- if (filename !== UNDEFINED_VALUE) {
6155
- warning.filename = filename;
6156
- }
6157
- warnings.push(warning);
6158
- }
6159
- }
6160
-
6161
6328
  function throwAmbiguousArchive(reason) {
6162
6329
  const error = new Error(ERR_AMBIGUOUS_ARCHIVE);
6163
6330
  error.reason = reason;
@@ -6237,7 +6404,9 @@ var zipReader = /*#__PURE__*/Object.freeze({
6237
6404
  WARNING_MISMATCHED_LOCAL_FILE_HEADER_BIT_FLAG: WARNING_MISMATCHED_LOCAL_FILE_HEADER_BIT_FLAG,
6238
6405
  WARNING_MISMATCHED_LOCAL_FILE_HEADER_COMPRESSION_METHOD: WARNING_MISMATCHED_LOCAL_FILE_HEADER_COMPRESSION_METHOD,
6239
6406
  WARNING_MISMATCHED_LOCAL_FILE_HEADER_CRC32_OR_SIZES: WARNING_MISMATCHED_LOCAL_FILE_HEADER_CRC32_OR_SIZES,
6407
+ WARNING_MISMATCHED_LOCAL_FILE_HEADER_FILENAME: WARNING_MISMATCHED_LOCAL_FILE_HEADER_FILENAME,
6240
6408
  WARNING_MISMATCHED_ZIP64_END_OF_CENTRAL_DIRECTORY: WARNING_MISMATCHED_ZIP64_END_OF_CENTRAL_DIRECTORY,
6409
+ WARNING_MULTIPLE_END_OF_CENTRAL_DIRECTORY: WARNING_MULTIPLE_END_OF_CENTRAL_DIRECTORY,
6241
6410
  WARNING_PREPENDED_CENTRAL_DIRECTORY: WARNING_PREPENDED_CENTRAL_DIRECTORY,
6242
6411
  WARNING_PREPENDED_DATA: WARNING_PREPENDED_DATA,
6243
6412
  WARNING_TRAILING_CENTRAL_DIRECTORY_DATA: WARNING_TRAILING_CENTRAL_DIRECTORY_DATA,
@@ -6290,7 +6459,7 @@ const ERR_INVALID_VERSION = "Version exceeds 65535";
6290
6459
  const ERR_INVALID_ENCRYPTION_STRENGTH = "The strength must equal 1, 2, or 3";
6291
6460
  const ERR_UNSUPPORTED_ENCRYPTION_USDZ = "Encryption is not supported in USDZ files";
6292
6461
  const ERR_UNSUPPORTED_SPLIT_USDZ = "Split zip files are not supported in USDZ files";
6293
- const ERR_UNSUPPORTED_ENCRYPTION_PASS_THROUGH = "Encryption is not supported when the 'passThrough' option is set";
6462
+ const ERR_UNSUPPORTED_ENCRYPTION_PASS_THROUGH = "Encryption is not supported when the 'passThrough' option is set to true (use 'compressed' instead)";
6294
6463
  const ERR_INVALID_EXTRAFIELD = "Invalid extra field (must be a Map)";
6295
6464
  const ERR_INVALID_EXTRAFIELD_TYPE = "Invalid extra field type (must be integer 0..65535)";
6296
6465
  const ERR_INVALID_EXTRAFIELD_DATA_TYPE = "Invalid extra field data (must be a Uint8Array)";
@@ -6302,6 +6471,7 @@ const MAX_NTFS_TIME = BigInt("0x7fffffffffffffff");
6302
6471
  const ERR_UNSUPPORTED_FORMAT = "Zip64 is not supported (set the 'zip64' option to 'true')";
6303
6472
  const ERR_UNDEFINED_UNCOMPRESSED_SIZE = "Undefined uncompressed size";
6304
6473
  const ERR_UNDEFINED_COMPRESSION_METHOD = "Undefined compression method";
6474
+ const ERR_UNDEFINED_CRC32 = "Undefined CRC32";
6305
6475
  const ERR_UNDETERMINED_SIZE = "Undetermined size";
6306
6476
  const ERR_UNDEFINED_READER = "Undefined reader";
6307
6477
  const ERR_INVALID_READER = "Invalid reader (must be a Reader instance, a ReadableStream instance, or an object with a 'readable' property)";
@@ -6315,14 +6485,21 @@ const ERR_INVALID_MSDOS_ATTRIBUTES = "Invalid msdosAttributesRaw (must be intege
6315
6485
  const ERR_INVALID_MSDOS_DATA = "Invalid msdosAttributes (must be an object with boolean flags)";
6316
6486
  const ERR_INVALID_LEVEL = "Invalid level (must be integer 0..9)";
6317
6487
  const ERR_INVALID_SIGNATURE_DATA = "Signature data exceeds 64KB";
6488
+ const ERR_INVALID_ENTRY = "Invalid entry option (must be an entry returned by ZipReader#getEntries())";
6489
+ const ERR_ZIP_CRYPTO_LAST_MOD_DATE = "The last modification date of an entry encrypted with ZipCrypto cannot be changed when passThrough is set";
6490
+ const WARNING_COMPRESSION_UNAVAILABLE = "compression unavailable";
6491
+ const WARNING_CLAMPED_LAST_MODIFICATION_DATE = "clamped last modification date";
6318
6492
 
6319
6493
  const EXTRAFIELD_DATA_AES = new Uint8Array([0x07, 0x00, 0x02, 0x00, 0x41, 0x45, 0x03, 0x00, 0x00]);
6320
6494
  const EXTRAFIELD_OFFSET_AES_VENDOR_VERSION = 4;
6321
6495
  const EXTRAFIELD_OFFSET_AES_COMPRESSION_METHOD = 9;
6322
6496
  const EXTRAFIELD_USDZ_MAX_LENGTH = 67;
6497
+ const MIN_PRINTABLE_ASCII_CHARACTER_CODE = 0x20;
6498
+ const MAX_PRINTABLE_ASCII_CHARACTER_CODE = 0x7e;
6323
6499
  const VENDOR_VERSION_AE_1 = 1;
6324
6500
  const INFOZIP_EXTRA_FIELD_TYPE = "infozip";
6325
6501
  const UNIX_EXTRA_FIELD_TYPE = "unix";
6502
+ const LEVEL_BY_BITFLAG_LEVEL = [8, 9, 5, 3];
6326
6503
  const MAX_LEVEL = 9;
6327
6504
 
6328
6505
  let workers = 0;
@@ -6349,9 +6526,11 @@ class ZipWriter {
6349
6526
  initialOffset: options[OPTION_OFFSET] === UNDEFINED_VALUE ? 0 : options[OPTION_OFFSET] - (writer.size || writer.writable.size || 0),
6350
6527
  pendingAddFileCalls: new Set(),
6351
6528
  pendingErrors: [],
6529
+ warnings: [],
6352
6530
  bufferedWrites: 0,
6353
6531
  directWrites: 0,
6354
- lastFileEntry: UNDEFINED_VALUE
6532
+ lastFileEntry: UNDEFINED_VALUE,
6533
+ archiveClosed: false
6355
6534
  });
6356
6535
  }
6357
6536
 
@@ -6516,6 +6695,9 @@ class ZipWriter {
6516
6695
  const zipWriter = this;
6517
6696
  const { pendingAddFileCalls, writer } = this;
6518
6697
  const { writable } = writer;
6698
+ if (zipWriter.archiveClosed) {
6699
+ return getWriterData(writer);
6700
+ }
6519
6701
  if (!(comment instanceof Uint8Array)) {
6520
6702
  throw new Error(ERR_INVALID_COMMENT_TYPE);
6521
6703
  }
@@ -6539,11 +6721,16 @@ class ZipWriter {
6539
6721
  throw error;
6540
6722
  }
6541
6723
  await closeFile(zipWriter, comment, options);
6724
+ zipWriter.archiveClosed = true;
6542
6725
  const preventClose = !ownsWritable(writer) && getOptionValue(zipWriter, options, OPTION_PREVENT_CLOSE);
6543
6726
  if (!preventClose) {
6544
6727
  await writable.getWriter().close();
6545
6728
  }
6546
- return writer.getData ? writer.getData() : writable;
6729
+ return getWriterData(writer);
6730
+ }
6731
+
6732
+ [SYMBOL_ASYNC_DISPOSE]() {
6733
+ return this.close();
6547
6734
  }
6548
6735
  }
6549
6736
 
@@ -6622,6 +6809,10 @@ class WatchedPromise extends Promise {
6622
6809
  }
6623
6810
  }
6624
6811
 
6812
+ function getWriterData(writer) {
6813
+ return writer.getData ? writer.getData() : writer.writable;
6814
+ }
6815
+
6625
6816
  function watchPromiseError(zipWriter, promise) {
6626
6817
  const watchedPromise = new WatchedPromise((resolve, reject) => Promise.prototype.then.call(promise, resolve, reject));
6627
6818
  const watcher = {};
@@ -6640,6 +6831,14 @@ async function prependZipEntries(zipWriter, reader) {
6640
6831
 
6641
6832
  async function addFileEntry(zipWriter, name, reader, options) {
6642
6833
  options = Object.assign({}, options);
6834
+ const entry = options[OPTION_ENTRY];
6835
+ if (entry !== UNDEFINED_VALUE) {
6836
+ const { entryOptions, passThroughOptions } = getSourceEntryOptions(entry,
6837
+ checkPassThroughOption(getOptionValue(zipWriter, options, OPTION_PASS_THROUGH)),
6838
+ getOptionValue(zipWriter, options, PROPERTY_NAME_LAST_MODIFICATION_DATE));
6839
+ delete options[OPTION_ENTRY];
6840
+ options = Object.assign(entryOptions, passThroughOptions, options);
6841
+ }
6643
6842
  if (getOptionValue(zipWriter, options, PROPERTY_NAME_DIRECTORY) && !name.endsWith(DIRECTORY_SIGNATURE)) {
6644
6843
  name += DIRECTORY_SIGNATURE;
6645
6844
  }
@@ -6704,21 +6903,33 @@ async function addFile(zipWriter, name, reader, options) {
6704
6903
  try {
6705
6904
  const { resolvedOptions } = metadataInfo;
6706
6905
  if (resolvedOptions.level != 0 && resolvedOptions.compressionMethod === UNDEFINED_VALUE &&
6707
- !resolvedOptions.passThrough && !(await supportsDeflate(getConfiguration()))) {
6906
+ !resolvedOptions.passThroughCompression && !(await supportsDeflate(getConfiguration()))) {
6708
6907
  resolvedOptions.level = 0;
6908
+ addWarning(zipWriter.warnings, WARNING_COMPRESSION_UNAVAILABLE, name);
6709
6909
  }
6710
6910
  const sizesInfo = await resolveSizes(zipWriter, reader, metadataInfo, options);
6711
6911
  ({ reader } = sizesInfo);
6712
6912
  const diskOffset = getDiskOffset(zipWriter.writer);
6713
6913
  const diskNumber = getDiskNumber(zipWriter.writer);
6914
+ let crc32 = options.crc32 === UNDEFINED_VALUE ? options[PROPERTY_NAME_SIGNATURE] : options.crc32;
6915
+ const storesAE2 = sizesInfo.resolvedOptions.encrypted && !resolvedOptions.zipCrypto;
6916
+ if (resolvedOptions.passThroughCompression && !resolvedOptions.passThroughEncryption && storesAE2) {
6917
+ crc32 = UNDEFINED_VALUE;
6918
+ }
6919
+ if (resolvedOptions.passThroughCompression && reader && !storesAE2 && crc32 === UNDEFINED_VALUE) {
6920
+ throw new Error(ERR_UNDEFINED_CRC32);
6921
+ }
6714
6922
  options = Object.assign({}, options, attributesInfo.resolvedOptions, metadataInfo.resolvedOptions, sizesInfo.resolvedOptions, {
6715
6923
  signature: options[PROPERTY_NAME_SIGNATURE],
6716
- crc32: options.crc32 === UNDEFINED_VALUE ? options[PROPERTY_NAME_SIGNATURE] : options.crc32,
6924
+ crc32,
6717
6925
  offset: zipWriter.offset - diskOffset,
6718
6926
  diskNumberStart: diskNumber,
6719
6927
  [OPTION_USDZ]: zipWriter.options[OPTION_USDZ]
6720
6928
  });
6721
6929
  const headerInfo = getHeaderInfo(options);
6930
+ if (headerInfo.lastModDateClamped) {
6931
+ addWarning(zipWriter.warnings, WARNING_CLAMPED_LAST_MODIFICATION_DATE, name);
6932
+ }
6722
6933
  const dataDescriptorInfo = getDataDescriptorInfo(options);
6723
6934
  const metadataSize = getLength(headerInfo.localHeaderArray, dataDescriptorInfo.dataDescriptorArray);
6724
6935
  fileEntry = await getFileEntry(zipWriter, name, reader, {
@@ -6745,6 +6956,95 @@ async function addFile(zipWriter, name, reader, options) {
6745
6956
  return new Entry(fileEntry);
6746
6957
  }
6747
6958
 
6959
+ function getSourceEntryOptions(entry, passThrough, lastModDateOverride) {
6960
+ if (entry === null || typeof entry != OBJECT_TYPE || Array.isArray(entry)) {
6961
+ throw new Error(ERR_INVALID_ENTRY);
6962
+ }
6963
+ const {
6964
+ externalFileAttributes,
6965
+ versionMadeBy,
6966
+ comment,
6967
+ lastModDate,
6968
+ rawLastModDate,
6969
+ creationDate,
6970
+ lastAccessDate,
6971
+ uncompressedSize,
6972
+ encrypted,
6973
+ zipCrypto,
6974
+ crc32,
6975
+ compressionMethod,
6976
+ extraFieldAES,
6977
+ extraFieldUnix,
6978
+ internalFileAttributes,
6979
+ extraField,
6980
+ bitFlag,
6981
+ directory,
6982
+ uid,
6983
+ gid
6984
+ } = entry;
6985
+ const entryOptions = {
6986
+ externalFileAttributes,
6987
+ versionMadeBy,
6988
+ comment,
6989
+ lastModDate,
6990
+ creationDate,
6991
+ lastAccessDate,
6992
+ internalFileAttributes,
6993
+ directory
6994
+ };
6995
+ if (bitFlag && bitFlag.languageEncodingFlag) {
6996
+ entryOptions[OPTION_USE_UNICODE_FILE_NAMES] = true;
6997
+ }
6998
+ const userExtraField = getUserExtraField(extraField);
6999
+ if (userExtraField) {
7000
+ entryOptions[PROPERTY_NAME_EXTRA_FIELD] = userExtraField;
7001
+ }
7002
+ if (uid !== UNDEFINED_VALUE || gid !== UNDEFINED_VALUE) {
7003
+ Object.assign(entryOptions, {
7004
+ uid,
7005
+ gid,
7006
+ unixExtraFieldType: extraFieldUnix ? UNIX_EXTRA_FIELD_TYPE : INFOZIP_EXTRA_FIELD_TYPE
7007
+ });
7008
+ }
7009
+ const passThroughOptions = {};
7010
+ if (passThrough && !directory) {
7011
+ Object.assign(passThroughOptions, {
7012
+ uncompressedSize,
7013
+ crc32,
7014
+ compressionMethod
7015
+ });
7016
+ if (passThrough !== PASS_THROUGH_COMPRESSED) {
7017
+ Object.assign(passThroughOptions, {
7018
+ encrypted,
7019
+ zipCrypto,
7020
+ encryptionStrength: extraFieldAES ? extraFieldAES.strength : UNDEFINED_VALUE
7021
+ });
7022
+ }
7023
+ if (bitFlag) {
7024
+ passThroughOptions.dataDescriptor = bitFlag.dataDescriptor;
7025
+ passThroughOptions[OPTION_LEVEL] = LEVEL_BY_BITFLAG_LEVEL[bitFlag.level];
7026
+ }
7027
+ if (lastModDateOverride === UNDEFINED_VALUE) {
7028
+ passThroughOptions.rawLastModDate = rawLastModDate;
7029
+ } else if (passThrough !== PASS_THROUGH_COMPRESSED && zipCrypto && (!bitFlag || bitFlag.dataDescriptor) &&
7030
+ lastModDateOverride instanceof Date &&
7031
+ getDosTimeHighByte(lastModDateOverride) != ((rawLastModDate >>> 8) & MAX_8_BITS)) {
7032
+ throw new Error(ERR_ZIP_CRYPTO_LAST_MOD_DATE);
7033
+ }
7034
+ }
7035
+ return { entryOptions, passThroughOptions };
7036
+ }
7037
+
7038
+ function getDosTimeHighByte(lastModDate) {
7039
+ let dosLastModDate = new Date(Math.ceil(Math.floor(lastModDate.getTime() / 1000) / 2) * 2000);
7040
+ if (dosLastModDate < MIN_DATE) {
7041
+ dosLastModDate = MIN_DATE;
7042
+ } else if (dosLastModDate > MAX_DATE) {
7043
+ dosLastModDate = MAX_DATE;
7044
+ }
7045
+ return ((dosLastModDate.getHours() << 3) | (dosLastModDate.getMinutes() >> 3)) & MAX_8_BITS;
7046
+ }
7047
+
6748
7048
  function resolveAttributes(zipWriter, name, options) {
6749
7049
  let msDosCompatible = getOptionValue(zipWriter, options, PROPERTY_NAME_MS_DOS_COMPATIBLE);
6750
7050
  let versionMadeBy = getOptionValue(zipWriter, options, PROPERTY_NAME_VERSION_MADE_BY, msDosCompatible ? VERSION_MADE_BY_MSDOS : VERSION_MADE_BY_UNIX);
@@ -6898,7 +7198,9 @@ function resolveMetadata(zipWriter, name, options) {
6898
7198
  const lastAccessDate = getDateOptionValue(zipWriter, options, PROPERTY_NAME_LAST_ACCESS_DATE);
6899
7199
  const creationDate = getDateOptionValue(zipWriter, options, PROPERTY_NAME_CREATION_DATE);
6900
7200
  const internalFileAttributes = getOptionValue(zipWriter, options, PROPERTY_NAME_INTERNAL_FILE_ATTRIBUTES, 0);
6901
- const passThrough = getOptionValue(zipWriter, options, OPTION_PASS_THROUGH);
7201
+ const passThrough = checkPassThroughOption(getOptionValue(zipWriter, options, OPTION_PASS_THROUGH));
7202
+ const passThroughCompression = Boolean(passThrough);
7203
+ const passThroughEncryption = passThrough === true;
6902
7204
  const password = getOptionValue(zipWriter, options, OPTION_PASSWORD);
6903
7205
  const rawPassword = getOptionValue(zipWriter, options, OPTION_RAW_PASSWORD);
6904
7206
  checkPasswordOption(password, rawPassword);
@@ -6914,10 +7216,11 @@ function resolveMetadata(zipWriter, name, options) {
6914
7216
  const dataDescriptorSignature = getOptionValue(zipWriter, options, OPTION_DATA_DESCRIPTOR_SIGNATURE, true);
6915
7217
  const signal = checkSignalOption(getOptionValue(zipWriter, options, OPTION_SIGNAL));
6916
7218
  throwIfAborted(signal);
6917
- const useUnicodeFileNames = getOptionValue(zipWriter, options, OPTION_USE_UNICODE_FILE_NAMES, true);
7219
+ const useUnicodeFileNames = getOptionValue(zipWriter, options, OPTION_USE_UNICODE_FILE_NAMES,
7220
+ !isPrintableASCIIText(rawFilename) || !isPrintableASCIIText(rawComment));
6918
7221
  const compressionMethod = getOptionValue(zipWriter, options, PROPERTY_NAME_COMPRESSION_METHOD);
6919
- const registeredCodec = passThrough || compressionMethod === UNDEFINED_VALUE ? UNDEFINED_VALUE : getRegisteredCodec(compressionMethod);
6920
- if (!passThrough && compressionMethod !== UNDEFINED_VALUE &&
7222
+ const registeredCodec = passThroughCompression || compressionMethod === UNDEFINED_VALUE ? UNDEFINED_VALUE : getRegisteredCodec(compressionMethod);
7223
+ if (!passThroughCompression && compressionMethod !== UNDEFINED_VALUE &&
6921
7224
  compressionMethod !== COMPRESSION_METHOD_STORE && compressionMethod !== COMPRESSION_METHOD_DEFLATE && !registeredCodec) {
6922
7225
  throw new Error(ERR_UNSUPPORTED_COMPRESSION);
6923
7226
  }
@@ -6931,15 +7234,15 @@ function resolveMetadata(zipWriter, name, options) {
6931
7234
  level = 0;
6932
7235
  }
6933
7236
  }
6934
- if (passThrough) {
6935
- level = UNDEFINED_VALUE;
7237
+ if (passThroughCompression) {
7238
+ level = toNumber(options[OPTION_LEVEL]);
6936
7239
  }
6937
7240
  let useCompressionStream = getOptionValue(zipWriter, options, OPTION_USE_COMPRESSION_STREAM);
6938
7241
  let dataDescriptor = getOptionValue(zipWriter, options, OPTION_DATA_DESCRIPTOR);
6939
7242
  if (bufferedWrite && dataDescriptor === UNDEFINED_VALUE) {
6940
7243
  dataDescriptor = false;
6941
7244
  }
6942
- if (dataDescriptor === UNDEFINED_VALUE || (zipCrypto && !passThrough)) {
7245
+ if (dataDescriptor === UNDEFINED_VALUE || (zipCrypto && !passThroughEncryption)) {
6943
7246
  dataDescriptor = true;
6944
7247
  }
6945
7248
  if (level !== UNDEFINED_VALUE && level != 6) {
@@ -6963,7 +7266,8 @@ function resolveMetadata(zipWriter, name, options) {
6963
7266
  lastAccessDate,
6964
7267
  creationDate,
6965
7268
  internalFileAttributes,
6966
- passThrough,
7269
+ passThroughCompression,
7270
+ passThroughEncryption,
6967
7271
  password,
6968
7272
  rawPassword,
6969
7273
  encryptionStrength,
@@ -7024,7 +7328,7 @@ function serializeExtraField(extraField) {
7024
7328
  }
7025
7329
 
7026
7330
  async function resolveSizes(zipWriter, reader, { resolvedOptions: metadata }, options) {
7027
- if (metadata.passThrough && !reader && !getOptionValue(zipWriter, options, PROPERTY_NAME_DIRECTORY)) {
7331
+ if (metadata.passThroughCompression && !reader && !getOptionValue(zipWriter, options, PROPERTY_NAME_DIRECTORY)) {
7028
7332
  throw new Error(ERR_UNDEFINED_READER);
7029
7333
  }
7030
7334
  let contentSize;
@@ -7040,12 +7344,12 @@ async function resolveSizes(zipWriter, reader, { resolvedOptions: metadata }, op
7040
7344
  }
7041
7345
 
7042
7346
  function resolveEntrySizes(zipWriter, hasContent, contentSize, metadata, options) {
7043
- const { passThrough, zipCrypto, password, rawPassword, encryptionStrength } = metadata;
7347
+ const { passThroughCompression, passThroughEncryption, zipCrypto, password, rawPassword, encryptionStrength } = metadata;
7044
7348
  let { dataDescriptor, zip64, level, compressionMethod } = metadata;
7045
7349
  let maximumCompressedSize = 0;
7046
7350
  let uncompressedSize = 0;
7047
7351
  let unknownSize = false;
7048
- if (passThrough && hasContent) {
7352
+ if (passThroughCompression && hasContent) {
7049
7353
  uncompressedSize = options[PROPERTY_NAME_UNCOMPRESSED_SIZE];
7050
7354
  if (uncompressedSize === UNDEFINED_VALUE) {
7051
7355
  throw new Error(ERR_UNDEFINED_UNCOMPRESSED_SIZE);
@@ -7056,17 +7360,17 @@ function resolveEntrySizes(zipWriter, hasContent, contentSize, metadata, options
7056
7360
  }
7057
7361
  const zip64Enabled = zip64 === true;
7058
7362
  const encrypted = getOptionValue(zipWriter, options, PROPERTY_NAME_ENCRYPTED);
7059
- if (hasContent && passThrough && !encrypted && getLength(password, rawPassword)) {
7363
+ if (hasContent && passThroughEncryption && !encrypted && getLength(password, rawPassword)) {
7060
7364
  throw new Error(ERR_UNSUPPORTED_ENCRYPTION_PASS_THROUGH);
7061
7365
  }
7062
- const encryptedEntry = hasContent && (Boolean((password && getLength(password)) || (rawPassword && getLength(rawPassword))) || (passThrough && encrypted));
7366
+ const encryptedEntry = hasContent && (Boolean((password && getLength(password)) || (rawPassword && getLength(rawPassword))) || (passThroughEncryption && encrypted));
7063
7367
  if (!hasContent) {
7064
7368
  level = 0;
7065
7369
  compressionMethod = COMPRESSION_METHOD_STORE;
7066
7370
  }
7067
- const encryptionOverhead = encryptedEntry ? (zipCrypto ? 12 : 16 + encryptionStrength * 4) : 0;
7371
+ const encryptionOverhead = getEncryptionOverhead(encryptedEntry, zipCrypto, encryptionStrength);
7068
7372
  if (hasContent) {
7069
- if (!passThrough) {
7373
+ if (!passThroughCompression) {
7070
7374
  if (contentSize === UNDEFINED_VALUE) {
7071
7375
  dataDescriptor = true;
7072
7376
  if (zip64 || zip64 === UNDEFINED_VALUE) {
@@ -7079,10 +7383,12 @@ function resolveEntrySizes(zipWriter, hasContent, contentSize, metadata, options
7079
7383
  }
7080
7384
  } else {
7081
7385
  options.uncompressedSize = uncompressedSize;
7082
- maximumCompressedSize = contentSize === UNDEFINED_VALUE ? getMaximumCompressedSize(uncompressedSize) + encryptionOverhead : contentSize;
7386
+ maximumCompressedSize = contentSize === UNDEFINED_VALUE ?
7387
+ getMaximumCompressedSize(uncompressedSize) + encryptionOverhead :
7388
+ contentSize + (passThroughEncryption ? 0 : encryptionOverhead);
7083
7389
  }
7084
7390
  }
7085
- const emptyEntry = !encryptedEntry && (!hasContent || (contentSize === 0 && !passThrough)) && !isCompressed(compressionMethod, level);
7391
+ const emptyEntry = !encryptedEntry && (!hasContent || (contentSize === 0 && !passThroughCompression)) && !isCompressed(compressionMethod, level);
7086
7392
  if (emptyEntry && !zipCrypto && getOptionValue(zipWriter, options, OPTION_DATA_DESCRIPTOR) === UNDEFINED_VALUE) {
7087
7393
  dataDescriptor = false;
7088
7394
  }
@@ -7289,6 +7595,7 @@ async function createFileEntry(reader, writer, { diskNumberStart, lockFileEntry
7289
7595
  localExtraFieldZip64Length,
7290
7596
  rawExtraFieldExtendedTimestamp,
7291
7597
  extraFieldExtendedTimestampFlag,
7598
+ extraFieldExtendedTimestampTime,
7292
7599
  rawExtraFieldNTFS,
7293
7600
  rawExtraFieldUnix,
7294
7601
  rawExtraFieldAES,
@@ -7301,6 +7608,7 @@ async function createFileEntry(reader, writer, { diskNumberStart, lockFileEntry
7301
7608
  password,
7302
7609
  rawPassword,
7303
7610
  level,
7611
+ useUnicodeFileNames,
7304
7612
  zip64,
7305
7613
  zip64Enabled,
7306
7614
  zip64UncompressedSize,
@@ -7335,7 +7643,8 @@ async function createFileEntry(reader, writer, { diskNumberStart, lockFileEntry
7335
7643
  msdosAttributesRaw,
7336
7644
  msdosAttributes,
7337
7645
  useCompressionStream,
7338
- passThrough,
7646
+ passThroughCompression,
7647
+ passThroughEncryption,
7339
7648
  format,
7340
7649
  codecURI
7341
7650
  } = options;
@@ -7346,9 +7655,9 @@ async function createFileEntry(reader, writer, { diskNumberStart, lockFileEntry
7346
7655
  zip64Enabled,
7347
7656
  directory: Boolean(directory),
7348
7657
  executable: Boolean(executable),
7349
- filenameUTF8: true,
7658
+ filenameUTF8: Boolean(useUnicodeFileNames),
7350
7659
  rawFilename,
7351
- commentUTF8: true,
7660
+ commentUTF8: Boolean(useUnicodeFileNames),
7352
7661
  rawComment,
7353
7662
  rawExtraFieldZip64,
7354
7663
  localExtraFieldZip64Length,
@@ -7379,7 +7688,7 @@ async function createFileEntry(reader, writer, { diskNumberStart, lockFileEntry
7379
7688
  uncompressedSize
7380
7689
  } = options;
7381
7690
  let compressedSize = 0;
7382
- if (!passThrough) {
7691
+ if (!passThroughCompression) {
7383
7692
  uncompressedSize = 0;
7384
7693
  }
7385
7694
  const { writable } = writer;
@@ -7396,9 +7705,9 @@ async function createFileEntry(reader, writer, { diskNumberStart, lockFileEntry
7396
7705
  encryptionStrength,
7397
7706
  zipCrypto: encrypted && zipCrypto,
7398
7707
  passwordVerification: encrypted && zipCrypto && (rawLastModDate >> 8) & MAX_8_BITS,
7399
- computeCrc32: !passThrough,
7400
- compressed: compressed && !passThrough,
7401
- encrypted: encrypted && !passThrough,
7708
+ computeCrc32: !passThroughCompression,
7709
+ compressed: compressed && !passThroughCompression,
7710
+ encrypted: encrypted && !passThroughEncryption,
7402
7711
  useWebWorkers,
7403
7712
  useCompressionStream,
7404
7713
  transferStreams,
@@ -7413,7 +7722,7 @@ async function createFileEntry(reader, writer, { diskNumberStart, lockFileEntry
7413
7722
  const result = await runWorker({ readable, writable }, workerOptions);
7414
7723
  compressedSize = result.outputSize;
7415
7724
  writer.size += compressedSize;
7416
- if (!passThrough) {
7725
+ if (!passThroughCompression) {
7417
7726
  uncompressedSize = result.inputSize;
7418
7727
  if (!encrypted || zipCrypto) {
7419
7728
  crc32 = result.crc32;
@@ -7456,8 +7765,9 @@ async function createFileEntry(reader, writer, { diskNumberStart, lockFileEntry
7456
7765
  headerArray,
7457
7766
  headerView,
7458
7767
  signature: crc32,
7459
- crc32: encrypted && !zipCrypto && !passThrough ? UNDEFINED_VALUE : crc32,
7768
+ crc32: encrypted && !zipCrypto && !passThroughCompression ? UNDEFINED_VALUE : crc32,
7460
7769
  extraFieldExtendedTimestampFlag,
7770
+ extraFieldExtendedTimestampTime,
7461
7771
  zip64UncompressedSize,
7462
7772
  zip64CompressedSize
7463
7773
  });
@@ -7482,7 +7792,7 @@ function getHeaderInfo(options) {
7482
7792
  encryptionStrength,
7483
7793
  extendedTimestamp,
7484
7794
  ntfsTimestamp,
7485
- passThrough,
7795
+ passThroughCompression,
7486
7796
  encrypted,
7487
7797
  zip64UncompressedSize,
7488
7798
  zip64CompressedSize,
@@ -7493,7 +7803,7 @@ function getHeaderInfo(options) {
7493
7803
  let { version, compressionMethod } = options;
7494
7804
  const compressed = !directory && isCompressed(compressionMethod, level);
7495
7805
  let rawLocalExtraFieldZip64;
7496
- const uncompressedFile = passThrough || !compressed;
7806
+ const uncompressedFile = passThroughCompression || !compressed;
7497
7807
  const zip64ExtraFieldComplete = zip64 && (options.bufferedWrite || !dataDescriptor || ((!zip64UncompressedSize && !zip64CompressedSize) || (uncompressedFile && !unknownSize)));
7498
7808
  const writeLocalExtraFieldZip64 = zip64ExtraFieldComplete || (zip64 && dataDescriptor && (zip64UncompressedSize || zip64CompressedSize));
7499
7809
  if (zip64 && (zip64UncompressedSize || zip64CompressedSize)) {
@@ -7505,8 +7815,8 @@ function getHeaderInfo(options) {
7505
7815
  if (zip64ExtraFieldComplete) {
7506
7816
  extraFieldZip64.writeUint64(uncompressedSize);
7507
7817
  if (uncompressedFile) {
7508
- const encryptionOverhead = encrypted ? (zipCrypto ? 12 : 16 + encryptionStrength * 4) : 0;
7509
- extraFieldZip64.writeUint64(passThrough ? 0 : uncompressedSize + encryptionOverhead);
7818
+ const encryptionOverhead = getEncryptionOverhead(encrypted, zipCrypto, encryptionStrength);
7819
+ extraFieldZip64.writeUint64(passThroughCompression ? 0 : uncompressedSize + encryptionOverhead);
7510
7820
  }
7511
7821
  }
7512
7822
  } else {
@@ -7525,6 +7835,7 @@ function getHeaderInfo(options) {
7525
7835
  let rawExtraFieldNTFS;
7526
7836
  let rawExtraFieldExtendedTimestamp;
7527
7837
  let extraFieldExtendedTimestampFlag;
7838
+ let extraFieldExtendedTimestampTime;
7528
7839
  if (extendedTimestamp) {
7529
7840
  const lastModTimeUnix = getTimeUnix(lastModDate);
7530
7841
  const lastModTimeUnixInRange = inUnixTimeRange(lastModTimeUnix);
@@ -7532,6 +7843,7 @@ function getHeaderInfo(options) {
7532
7843
  const extraFieldTimestampLength = 9 + (lastAccessDate ? 4 : 0) + (creationDate ? 4 : 0);
7533
7844
  const extraFieldTimestamp = createRecordWriter(extraFieldTimestampLength);
7534
7845
  extraFieldExtendedTimestampFlag = 0x1 + (lastAccessDate ? 0x2 : 0) + (creationDate ? 0x4 : 0);
7846
+ extraFieldExtendedTimestampTime = lastModTimeUnix;
7535
7847
  extraFieldTimestamp.writeUint16(EXTRAFIELD_TYPE_EXTENDED_TIMESTAMP);
7536
7848
  extraFieldTimestamp.writeUint16(extraFieldTimestampLength - 4);
7537
7849
  extraFieldTimestamp.writeUint8(extraFieldExtendedTimestampFlag);
@@ -7615,7 +7927,7 @@ function getHeaderInfo(options) {
7615
7927
  }
7616
7928
  if (encrypted && !zipCrypto) {
7617
7929
  version = version > VERSION_AES ? version : VERSION_AES;
7618
- if (passThrough && crc32 !== UNDEFINED_VALUE) {
7930
+ if (passThroughCompression && crc32 !== UNDEFINED_VALUE) {
7619
7931
  rawExtraFieldAES[EXTRAFIELD_OFFSET_AES_VENDOR_VERSION] = VENDOR_VERSION_AE_1;
7620
7932
  }
7621
7933
  setUint16(getDataView(rawExtraFieldAES), EXTRAFIELD_OFFSET_AES_COMPRESSION_METHOD, compressionMethod);
@@ -7677,12 +7989,14 @@ function getHeaderInfo(options) {
7677
7989
  headerArray,
7678
7990
  headerView,
7679
7991
  lastModDate: storedLastModDate,
7992
+ lastModDateClamped: storedLastModDate === clampedLastModDate && dosLastModDate.getTime() != clampedLastModDate.getTime(),
7680
7993
  rawLastModDate,
7681
7994
  encrypted,
7682
7995
  compressed,
7683
7996
  version,
7684
7997
  compressionMethod,
7685
7998
  extraFieldExtendedTimestampFlag,
7999
+ extraFieldExtendedTimestampTime,
7686
8000
  rawExtraFieldZip64: EMPTY_UINT8_ARRAY,
7687
8001
  localExtraFieldZip64Length,
7688
8002
  rawExtraFieldExtendedTimestamp,
@@ -7785,7 +8099,7 @@ function setEntryInfo({
7785
8099
  }, {
7786
8100
  zip64,
7787
8101
  zipCrypto,
7788
- passThrough,
8102
+ passThroughCompression,
7789
8103
  dataDescriptor
7790
8104
  }) {
7791
8105
  const {
@@ -7796,7 +8110,7 @@ function setEntryInfo({
7796
8110
  dataDescriptorView,
7797
8111
  dataDescriptorOffset
7798
8112
  } = dataDescriptorInfo;
7799
- if ((!encrypted || zipCrypto || passThrough) && crc32 !== UNDEFINED_VALUE) {
8113
+ if ((!encrypted || zipCrypto || passThroughCompression) && crc32 !== UNDEFINED_VALUE) {
7800
8114
  setUint32(headerView, HEADER_OFFSET_SIGNATURE, crc32);
7801
8115
  if (dataDescriptor) {
7802
8116
  setUint32(dataDescriptorView, dataDescriptorOffset, crc32);
@@ -7827,9 +8141,9 @@ function updateLocalHeader({
7827
8141
  uncompressedSize,
7828
8142
  zip64UncompressedSize,
7829
8143
  zip64CompressedSize
7830
- }, localHeaderView, { dataDescriptor, passThrough }) {
8144
+ }, localHeaderView, { dataDescriptor, passThroughCompression }) {
7831
8145
  if (!dataDescriptor) {
7832
- if (!encrypted || (passThrough && crc32 !== UNDEFINED_VALUE)) {
8146
+ if (!encrypted || (passThroughCompression && crc32 !== UNDEFINED_VALUE)) {
7833
8147
  setUint32(localHeaderView, HEADER_OFFSET_SIGNATURE + LOCAL_HEADER_COMMON_OFFSET, crc32);
7834
8148
  }
7835
8149
  if (!zip64CompressedSize) {
@@ -7866,9 +8180,8 @@ function createDirectoryRecords(files) {
7866
8180
  rawExtraFieldUnix,
7867
8181
  rawExtraField,
7868
8182
  rawCentralExtraField,
7869
- extendedTimestamp,
7870
8183
  extraFieldExtendedTimestampFlag,
7871
- lastModDate,
8184
+ extraFieldExtendedTimestampTime,
7872
8185
  zip64Enabled,
7873
8186
  uncompressedSize,
7874
8187
  compressedSize
@@ -7911,16 +8224,15 @@ function createDirectoryRecords(files) {
7911
8224
  fileEntry.zip64Offset = zip64Offset;
7912
8225
  fileEntry.zip64DiskNumberStart = zip64DiskNumberStart;
7913
8226
  let rawExtraFieldTimestamp;
7914
- const lastModTimeUnix = getTimeUnix(lastModDate);
7915
- if (extendedTimestamp && inUnixTimeRange(lastModTimeUnix)) {
8227
+ if (extraFieldExtendedTimestampTime === UNDEFINED_VALUE) {
8228
+ rawExtraFieldTimestamp = EMPTY_UINT8_ARRAY;
8229
+ } else {
7916
8230
  const extraFieldTimestamp = createRecordWriter(9);
7917
8231
  extraFieldTimestamp.writeUint16(EXTRAFIELD_TYPE_EXTENDED_TIMESTAMP);
7918
8232
  extraFieldTimestamp.writeUint16(5);
7919
8233
  extraFieldTimestamp.writeUint8(extraFieldExtendedTimestampFlag);
7920
- extraFieldTimestamp.writeUint32(lastModTimeUnix);
8234
+ extraFieldTimestamp.writeUint32(extraFieldExtendedTimestampTime);
7921
8235
  rawExtraFieldTimestamp = extraFieldTimestamp.array;
7922
- } else {
7923
- rawExtraFieldTimestamp = EMPTY_UINT8_ARRAY;
7924
8236
  }
7925
8237
  fileEntry.rawExtraFieldExtendedTimestamp = rawExtraFieldTimestamp;
7926
8238
  const extraFieldLength = getLength(
@@ -8420,6 +8732,11 @@ function getHeaderArrayData({
8420
8732
  };
8421
8733
  }
8422
8734
 
8735
+ function isPrintableASCIIText(rawText) {
8736
+ return rawText.every(characterCode =>
8737
+ characterCode >= MIN_PRINTABLE_ASCII_CHARACTER_CODE && characterCode <= MAX_PRINTABLE_ASCII_CHARACTER_CODE);
8738
+ }
8739
+
8423
8740
  function getBitFlag(level, useUnicodeFileNames, dataDescriptor, encrypted, compressionMethod) {
8424
8741
  let bitFlag = 0;
8425
8742
  if (useUnicodeFileNames) {
@@ -8581,7 +8898,7 @@ function formatSupported(StreamClass, format) {
8581
8898
  EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
8582
8899
  */
8583
8900
 
8584
- const VERSION = "2.11.4";
8901
+ const VERSION = "2.12.0";
8585
8902
 
8586
8903
  /*
8587
8904
  Copyright (c) 2025 Gildas Lormeau. All rights reserved.
@@ -9401,9 +9718,9 @@ setDefaultConfiguration({
9401
9718
  DecompressionStreamFallback: DecompressionStreamZlib
9402
9719
  });
9403
9720
 
9404
- function terminateWorkersAndModule() {
9721
+ async function terminateWorkersAndModule() {
9722
+ await terminateWorkers();
9405
9723
  modulePromise = null;
9406
- terminateWorkers();
9407
9724
  resetWasmModule();
9408
9725
  }
9409
9726
 
@@ -9412,4 +9729,4 @@ function terminateWorkersAndModule() {
9412
9729
 
9413
9730
  configureExternalAssets();
9414
9731
 
9415
- export { BlobReader, BlobWriter, Data64URIReader, Data64URIWriter, ERR_AMBIGUOUS_ARCHIVE, ERR_BAD_FORMAT, ERR_CENTRAL_DIRECTORY_NOT_FOUND, ERR_DUPLICATED_NAME, ERR_ENCRYPTED, ERR_ENCRYPTED_CENTRAL_DIRECTORY, ERR_ENTRY_DATA_OUT_OF_BOUNDS, ERR_EOCDR_LOCATOR_ZIP64_NOT_FOUND, ERR_EOCDR_NOT_FOUND, ERR_EXTRAFIELD_ZIP64_NOT_FOUND, ERR_HTTP_RANGE, ERR_HTTP_RESOURCE_CHANGED, ERR_INVALID_AUTHENTICATION_CODE, ERR_INVALID_CODEC_DEFINITION, ERR_INVALID_CODEC_MODULE, ERR_INVALID_COMMENT, ERR_INVALID_COMMENT_TYPE, ERR_INVALID_COMPRESSED_DATA, ERR_INVALID_CRC32, ERR_INVALID_DATE, ERR_INVALID_ENCRYPTION_STRENGTH, ERR_INVALID_ENTRY_COMMENT, ERR_INVALID_ENTRY_COMMENT_TYPE, ERR_INVALID_ENTRY_NAME, ERR_INVALID_EXTRAFIELD, ERR_INVALID_EXTRAFIELD_DATA, ERR_INVALID_EXTRAFIELD_DATA_TYPE, ERR_INVALID_EXTRAFIELD_TYPE, ERR_INVALID_FILENAME_VALIDATION, ERR_INVALID_FUNCTION_OPTION, ERR_INVALID_GID, ERR_INVALID_LEVEL, ERR_INVALID_MAX_APPENDED_DATA_SIZE, ERR_INVALID_MAX_WORKERS, ERR_INVALID_MSDOS_ATTRIBUTES, ERR_INVALID_MSDOS_DATA, ERR_INVALID_PASSWORD, ERR_INVALID_PASSWORD_TYPE, ERR_INVALID_READER, ERR_INVALID_SIGNAL, ERR_INVALID_SIGNATURE_DATA, ERR_INVALID_STRICTNESS, ERR_INVALID_UID, ERR_INVALID_UNCOMPRESSED_SIZE, ERR_INVALID_UNIX_EXTRA_FIELD_TYPE, ERR_INVALID_UNIX_ID_SIZE, ERR_INVALID_UNIX_MODE, ERR_INVALID_VERSION, ERR_ITERATOR_COMPLETED_TOO_SOON, ERR_LOCAL_FILE_HEADER_NOT_FOUND, ERR_OVERLAPPING_ENTRY, ERR_RESERVED_COMPRESSION_METHOD, ERR_SPLIT_ZIP_FILE, ERR_UNDEFINED_COMPRESSION_METHOD, ERR_UNDEFINED_READER, ERR_UNDEFINED_UNCOMPRESSED_SIZE, ERR_UNDETERMINED_SIZE, ERR_UNSAFE_FILENAME, ERR_UNSUPPORTED_COMPRESSION, ERR_UNSUPPORTED_CONTEXT, ERR_UNSUPPORTED_CRYPTO_API, ERR_UNSUPPORTED_ENCRYPTION, ERR_UNSUPPORTED_ENCRYPTION_PASS_THROUGH, ERR_UNSUPPORTED_ENCRYPTION_USDZ, ERR_UNSUPPORTED_FORMAT, ERR_UNSUPPORTED_SPLIT_USDZ, ERR_UNSUPPORTED_UINT64, ERR_WORKER_STARTUP_TIMEOUT, ERR_WRITER_NOT_INITIALIZED, ERR_ZIP_NOT_EMPTY, HttpRangeReader, HttpReader, Reader, SplitDataReader, SplitDataWriter, TextReader, TextWriter, Uint8ArrayReader, Uint8ArrayWriter, VERSION, WARNING_APPENDED_DATA, WARNING_COMPRESSED_PATCHED_DATA, WARNING_DUPLICATE_FILENAME, WARNING_MALFORMED_EXTRA_FIELD, WARNING_MISMATCHED_LOCAL_FILE_HEADER_BIT_FLAG, WARNING_MISMATCHED_LOCAL_FILE_HEADER_COMPRESSION_METHOD, WARNING_MISMATCHED_LOCAL_FILE_HEADER_CRC32_OR_SIZES, WARNING_MISMATCHED_ZIP64_END_OF_CENTRAL_DIRECTORY, WARNING_PREPENDED_CENTRAL_DIRECTORY, WARNING_PREPENDED_DATA, WARNING_TRAILING_CENTRAL_DIRECTORY_DATA, WARNING_UNKNOWN_VERSION, WARNING_UNKNOWN_ZIP64_EXTENSIBLE_DATA, WARNING_UNSORTED_CENTRAL_DIRECTORY, WARNING_WRAPPED_ENTRIES_COUNT, Writer, ZipReader, ZipReaderStream, ZipWriter, ZipWriterStream, configure, createBlobTempStream, createOPFSTempStream, createSyncAccessHandleTempStream, getMimeType, getRegisteredCodecs, getSupportedCompressionMethods, isZipFile, registerCodec, resetConfiguration, terminateWorkersAndModule as terminateWorkers, unregisterCodec };
9732
+ export { BlobReader, BlobWriter, Data64URIReader, Data64URIWriter, ERR_ABORTED, ERR_AMBIGUOUS_ARCHIVE, ERR_BAD_FORMAT, ERR_CENTRAL_DIRECTORY_NOT_FOUND, ERR_DUPLICATED_NAME, ERR_ENCRYPTED, ERR_ENCRYPTED_CENTRAL_DIRECTORY, ERR_ENTRY_DATA_OUT_OF_BOUNDS, ERR_EOCDR_LOCATOR_ZIP64_NOT_FOUND, ERR_EOCDR_NOT_FOUND, ERR_EXTRAFIELD_ZIP64_NOT_FOUND, ERR_HTTP_RANGE, ERR_HTTP_RESOURCE_CHANGED, ERR_HTTP_STATUS, ERR_INVALID_AUTHENTICATION_CODE, ERR_INVALID_BASE_URI, ERR_INVALID_CODEC_DEFINITION, ERR_INVALID_CODEC_MODULE, ERR_INVALID_COMMENT, ERR_INVALID_COMMENT_TYPE, ERR_INVALID_COMPRESSED_DATA, ERR_INVALID_CRC32, ERR_INVALID_DATE, ERR_INVALID_ENCRYPTION_STRENGTH, ERR_INVALID_ENTRY, ERR_INVALID_ENTRY_COMMENT, ERR_INVALID_ENTRY_COMMENT_TYPE, ERR_INVALID_ENTRY_NAME, ERR_INVALID_EXTRAFIELD, ERR_INVALID_EXTRAFIELD_DATA, ERR_INVALID_EXTRAFIELD_DATA_TYPE, ERR_INVALID_EXTRAFIELD_TYPE, ERR_INVALID_FILENAME_VALIDATION, ERR_INVALID_FUNCTION_OPTION, ERR_INVALID_GID, ERR_INVALID_LEVEL, ERR_INVALID_MAX_APPENDED_DATA_SIZE, ERR_INVALID_MAX_WORKERS, ERR_INVALID_MSDOS_ATTRIBUTES, ERR_INVALID_MSDOS_DATA, ERR_INVALID_PASSWORD, ERR_INVALID_PASSWORD_TYPE, ERR_INVALID_PASS_THROUGH_VALUE, ERR_INVALID_READER, ERR_INVALID_SIGNAL, ERR_INVALID_SIGNATURE_DATA, ERR_INVALID_STRICTNESS, ERR_INVALID_UID, ERR_INVALID_UNCOMPRESSED_SIZE, ERR_INVALID_UNIX_EXTRA_FIELD_TYPE, ERR_INVALID_UNIX_ID_SIZE, ERR_INVALID_UNIX_MODE, ERR_INVALID_URI, ERR_INVALID_VERSION, ERR_ITERATOR_COMPLETED_TOO_SOON, ERR_LOCAL_FILE_HEADER_NOT_FOUND, ERR_OVERLAPPING_ENTRY, ERR_RESERVED_COMPRESSION_METHOD, ERR_SPLIT_ZIP_FILE, ERR_UNDEFINED_COMPRESSION_METHOD, ERR_UNDEFINED_CRC32, ERR_UNDEFINED_READER, ERR_UNDEFINED_UNCOMPRESSED_SIZE, ERR_UNDETERMINED_SIZE, ERR_UNSAFE_FILENAME, ERR_UNSUPPORTED_COMPRESSION, ERR_UNSUPPORTED_CONTEXT, ERR_UNSUPPORTED_CRYPTO_API, ERR_UNSUPPORTED_ENCRYPTION, ERR_UNSUPPORTED_ENCRYPTION_PASS_THROUGH, ERR_UNSUPPORTED_ENCRYPTION_USDZ, ERR_UNSUPPORTED_FORMAT, ERR_UNSUPPORTED_SPLIT_USDZ, ERR_UNSUPPORTED_UINT64, ERR_WORKER_STARTUP_TIMEOUT, ERR_WRITER_NOT_INITIALIZED, ERR_WRITER_SIZE_NOT_WRITABLE, ERR_ZIP_CRYPTO_LAST_MOD_DATE, ERR_ZIP_NOT_EMPTY, HttpRangeReader, HttpReader, Reader, SplitDataReader, SplitDataWriter, TextReader, TextWriter, Uint8ArrayReader, Uint8ArrayWriter, VERSION, WARNING_APPENDED_DATA, WARNING_CLAMPED_LAST_MODIFICATION_DATE, WARNING_COMPRESSED_PATCHED_DATA, WARNING_COMPRESSION_UNAVAILABLE, WARNING_DUPLICATE_FILENAME, WARNING_MALFORMED_EXTRA_FIELD, WARNING_MISMATCHED_LOCAL_FILE_HEADER_BIT_FLAG, WARNING_MISMATCHED_LOCAL_FILE_HEADER_COMPRESSION_METHOD, WARNING_MISMATCHED_LOCAL_FILE_HEADER_CRC32_OR_SIZES, WARNING_MISMATCHED_LOCAL_FILE_HEADER_FILENAME, WARNING_MISMATCHED_ZIP64_END_OF_CENTRAL_DIRECTORY, WARNING_MULTIPLE_END_OF_CENTRAL_DIRECTORY, WARNING_PREPENDED_CENTRAL_DIRECTORY, WARNING_PREPENDED_DATA, WARNING_TRAILING_CENTRAL_DIRECTORY_DATA, WARNING_UNKNOWN_VERSION, WARNING_UNKNOWN_ZIP64_EXTENSIBLE_DATA, WARNING_UNSORTED_CENTRAL_DIRECTORY, WARNING_WRAPPED_ENTRIES_COUNT, Writer, ZipReader, ZipReaderStream, ZipWriter, ZipWriterStream, configure, createBlobTempStream, createOPFSTempStream, createSyncAccessHandleTempStream, getMimeType, getRegisteredCodecs, getSupportedCompressionMethods, isZipFile, registerCodec, resetConfiguration, terminateWorkersAndModule as terminateWorkers, unregisterCodec };