@zip.js/zip.js 2.11.3 → 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 +444 -114
  3. package/dist/zip-core-external.min.js +1 -1
  4. package/dist/zip-core.js +454 -111
  5. package/dist/zip-core.min.js +1 -1
  6. package/dist/zip-fs-core-external.js +509 -236
  7. package/dist/zip-fs-core-external.min.js +1 -1
  8. package/dist/zip-fs-core.js +522 -233
  9. package/dist/zip-fs-core.min.js +1 -1
  10. package/dist/zip-fs-external.js +509 -236
  11. package/dist/zip-fs-external.min.js +1 -1
  12. package/dist/zip-fs-native.js +524 -235
  13. package/dist/zip-fs-native.min.js +1 -1
  14. package/dist/zip-fs.js +525 -236
  15. package/dist/zip-fs.min.js +1 -1
  16. package/dist/zip-legacy.js +456 -113
  17. package/dist/zip-legacy.min.js +1 -1
  18. package/dist/zip-native.js +456 -113
  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 +457 -114
  23. package/dist/zip.min.js +1 -1
  24. package/index-native.cjs +524 -235
  25. package/index-native.min.js +1 -1
  26. package/index.cjs +525 -236
  27. package/index.d.cts +480 -59
  28. package/index.d.ts +480 -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 +20 -10
  35. package/lib/core/options.js +29 -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 -134
  44. package/lib/core/zip-reader.js +108 -47
  45. package/lib/core/zip-writer.js +238 -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,20 @@ 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')";
216
+ const ERR_ABORTED = "The operation was aborted";
217
+ const ABORT_ERROR_NAME = "AbortError";
211
218
 
212
219
  function checkFunctionOption(value) {
213
220
  if (value && typeof value != FUNCTION_TYPE) {
@@ -223,12 +230,25 @@ function checkSignalOption(signal) {
223
230
  return signal || UNDEFINED_VALUE;
224
231
  }
225
232
 
233
+ function throwIfAborted(signal) {
234
+ if (signal && signal.aborted) {
235
+ throw signal.reason === UNDEFINED_VALUE ? new DOMException(ERR_ABORTED, ABORT_ERROR_NAME) : signal.reason;
236
+ }
237
+ }
238
+
226
239
  function checkPasswordOption(password, rawPassword) {
227
240
  if ((password && typeof password != STRING_TYPE) || (rawPassword && !(rawPassword instanceof Uint8Array))) {
228
241
  throw new Error(ERR_INVALID_PASSWORD_TYPE);
229
242
  }
230
243
  }
231
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
+
232
252
  function checkInteger(value, maxValue, errorMessage) {
233
253
  if (!Number.isInteger(value) || value < 0 || value > maxValue) {
234
254
  throw new Error(errorMessage);
@@ -278,6 +298,8 @@ const DEFAULT_CHUNK_SIZE$1 = 64 * 1024;
278
298
  const MINIMUM_CHUNK_SIZE = 64;
279
299
  const MINIMUM_PROPERTY_VALUE = 1;
280
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)";
281
303
  let maxWorkers = 2;
282
304
  try {
283
305
  if (typeof navigator != UNDEFINED_TYPE && navigator.hardwareConcurrency) {
@@ -302,9 +324,9 @@ const DEFAULT_CONFIGURATION = {
302
324
  };
303
325
 
304
326
  const PROPERTY_NAME_MAX_WORKERS = "maxWorkers";
327
+ const PROPERTY_NAME_BASE_URI = "baseURI";
305
328
 
306
- const STRING_PROPERTY_NAMES = [
307
- "baseURI",
329
+ const URI_PROPERTY_NAMES = [
308
330
  "wasmURI",
309
331
  "workerURI"
310
332
  ];
@@ -328,7 +350,8 @@ const FUNCTION_PROPERTY_NAMES = [
328
350
  "DecompressionStreamFallback"
329
351
  ];
330
352
  const CONFIGURABLE_PROPERTY_NAMES = [
331
- ...STRING_PROPERTY_NAMES,
353
+ PROPERTY_NAME_BASE_URI,
354
+ ...URI_PROPERTY_NAMES,
332
355
  ...BOOLEAN_PROPERTY_NAMES,
333
356
  ...NUMBER_PROPERTY_NAMES,
334
357
  ...FUNCTION_PROPERTY_NAMES
@@ -372,6 +395,14 @@ function checkPropertyValue(propertyName, propertyValue) {
372
395
  }
373
396
  } else if (FUNCTION_PROPERTY_NAMES.includes(propertyName)) {
374
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
+ }
375
406
  }
376
407
  return propertyValue;
377
408
  }
@@ -2624,6 +2655,7 @@ class ChunkStream extends TransformStream {
2624
2655
  constructor(chunkSize) {
2625
2656
  const pendingChunks = [];
2626
2657
  let pendingLength = 0;
2658
+ let outputSize = 0;
2627
2659
  if (!Number.isFinite(chunkSize) || chunkSize < 1) {
2628
2660
  chunkSize = DEFAULT_CHUNK_SIZE;
2629
2661
  }
@@ -2632,15 +2664,20 @@ class ChunkStream extends TransformStream {
2632
2664
  pendingChunks.push(chunk);
2633
2665
  pendingLength += chunk.length;
2634
2666
  while (pendingLength > chunkSize) {
2667
+ outputSize += chunkSize;
2635
2668
  controller.enqueue(shiftChunk());
2636
2669
  }
2637
2670
  },
2638
2671
  flush(controller) {
2639
2672
  if (pendingLength) {
2673
+ outputSize += pendingLength;
2640
2674
  controller.enqueue(concatChunks(pendingChunks, pendingLength));
2641
2675
  }
2642
2676
  }
2643
2677
  });
2678
+ Object.defineProperty(this, "outputSize", {
2679
+ get: () => outputSize
2680
+ });
2644
2681
 
2645
2682
  function shiftChunk() {
2646
2683
  const result = new Uint8Array(chunkSize);
@@ -2845,7 +2882,7 @@ function createWorkerInterface(workerData, config) {
2845
2882
  }
2846
2883
 
2847
2884
  async function runWorker$1({ options, readable, writable, onTaskFinished }, config) {
2848
- let codecStream;
2885
+ let codecStream, chunkStream;
2849
2886
  try {
2850
2887
  if (options.compressed && !options.format) {
2851
2888
  const deflate = options.codecType.startsWith(CODEC_DEFLATE);
@@ -2868,9 +2905,10 @@ async function runWorker$1({ options, readable, writable, onTaskFinished }, conf
2868
2905
  }
2869
2906
  }
2870
2907
  codecStream = new CodecStream(options, config);
2908
+ chunkStream = new ChunkStream(getChunkSize(config));
2871
2909
  await readable
2872
2910
  .pipeThrough(codecStream)
2873
- .pipeThrough(new ChunkStream(getChunkSize(config)))
2911
+ .pipeThrough(chunkStream)
2874
2912
  .pipeTo(writable, { preventClose: true, preventAbort: true });
2875
2913
  const {
2876
2914
  crc32,
@@ -2884,7 +2922,7 @@ async function runWorker$1({ options, readable, writable, onTaskFinished }, conf
2884
2922
  };
2885
2923
  } catch (error) {
2886
2924
  if (codecStream) {
2887
- error.outputSize = codecStream.outputSize;
2925
+ error.outputSize = chunkStream ? chunkStream.outputSize : 0;
2888
2926
  }
2889
2927
  throw error;
2890
2928
  } finally {
@@ -2993,11 +3031,17 @@ async function runWebWorker(workerData, config) {
2993
3031
  let resolveResult, rejectResult;
2994
3032
  const result = new Promise((resolve, reject) => {
2995
3033
  resolveResult = resolve;
2996
- rejectResult = reject;
3034
+ rejectResult = error => {
3035
+ if (error && error.outputSize === UNDEFINED_VALUE) {
3036
+ error.outputSize = workerData.outputSize;
3037
+ }
3038
+ reject(error);
3039
+ };
2997
3040
  });
2998
3041
  Object.assign(workerData, {
2999
3042
  reader: null,
3000
3043
  writer: null,
3044
+ outputSize: 0,
3001
3045
  resolveResult,
3002
3046
  rejectResult,
3003
3047
  result
@@ -3281,8 +3325,10 @@ async function onMessage({ data }, workerData) {
3281
3325
  }
3282
3326
  }
3283
3327
  if (type == MESSAGE_DATA) {
3328
+ const chunk = new Uint8Array(value);
3284
3329
  await writer.ready;
3285
- await writer.write(new Uint8Array(value));
3330
+ await writer.write(chunk);
3331
+ workerData.outputSize += chunk.length;
3286
3332
  if (!stale()) {
3287
3333
  sendMessage({ type: MESSAGE_ACK_DATA, messageId }, workerData);
3288
3334
  }
@@ -3590,10 +3636,13 @@ function decode(value, encoding, ignoreBOM) {
3590
3636
 
3591
3637
 
3592
3638
  const ERR_HTTP_STATUS = "HTTP error ";
3639
+ const MIN_SUCCESS_HTTP_STATUS = 200;
3640
+ const MAX_SUCCESS_HTTP_STATUS = 299;
3593
3641
  const ERR_HTTP_RANGE = "HTTP Range not supported";
3594
3642
  const ERR_HTTP_RESOURCE_CHANGED = "HTTP resource changed";
3595
3643
  const ERR_ITERATOR_COMPLETED_TOO_SOON = "Writer iterator completed too soon";
3596
3644
  const ERR_WRITER_NOT_INITIALIZED = "Writer not initialized";
3645
+ const ERR_WRITER_SIZE_NOT_WRITABLE = "Invalid writer (size must be writable)";
3597
3646
 
3598
3647
  const CONTENT_TYPE_TEXT_PLAIN = "text/plain";
3599
3648
  const HTTP_HEADER_CONTENT_LENGTH = "Content-Length";
@@ -3785,11 +3834,14 @@ class BlobReader extends Reader {
3785
3834
  const reader = this;
3786
3835
  const { sourceBlob, size } = reader;
3787
3836
  const { offset = 0, size: readSize = size - offset } = options || {};
3788
- if (!offset && readSize >= size) {
3789
- return toCompatibleReadable(sourceBlob.stream());
3790
- }
3791
- if (blobSliceReliable) {
3792
- return toCompatibleReadable(sourceBlob.slice(offset, offset + readSize).stream());
3837
+ // deno-lint-ignore valid-typeof
3838
+ if (typeof sourceBlob.stream == FUNCTION_TYPE) {
3839
+ if (!offset && readSize >= size) {
3840
+ return toCompatibleReadable(sourceBlob.stream());
3841
+ }
3842
+ if (blobSliceReliable) {
3843
+ return toCompatibleReadable(sourceBlob.slice(offset, offset + readSize).stream());
3844
+ }
3793
3845
  }
3794
3846
  return super.createReadable(options);
3795
3847
  }
@@ -4169,7 +4221,7 @@ async function getContentLength(httpReader, sendRequest, getRequestData) {
4169
4221
 
4170
4222
  async function sendFetchRequest(method, { fetch: fetchFunction = fetch, options, url }, headers) {
4171
4223
  const response = await fetchFunction(url, Object.assign({}, options, { method, headers }));
4172
- if (response.status < 400) {
4224
+ if (response.status >= MIN_SUCCESS_HTTP_STATUS && response.status <= MAX_SUCCESS_HTTP_STATUS) {
4173
4225
  return response;
4174
4226
  } else {
4175
4227
  throw response.status == 416 ? new Error(ERR_HTTP_RANGE) : new Error(ERR_HTTP_STATUS + (response.statusText || response.status));
@@ -4180,7 +4232,7 @@ function sendXMLHttpRequest(method, { url }, headers) {
4180
4232
  return new Promise((resolve, reject) => {
4181
4233
  const request = new XMLHttpRequest();
4182
4234
  request.addEventListener("load", () => {
4183
- if (request.status < 400) {
4235
+ if (request.status >= MIN_SUCCESS_HTTP_STATUS && request.status <= MAX_SUCCESS_HTTP_STATUS) {
4184
4236
  const headers = [];
4185
4237
  request.getAllResponseHeaders().trim().split(/[\r\n]+/).forEach(header => {
4186
4238
  const splitHeader = header.trim().split(/\s*:\s*/);
@@ -4484,8 +4536,10 @@ class GenericWriter {
4484
4536
  writable: toCompatibleWritable(writer)
4485
4537
  };
4486
4538
  }
4487
- if (writer.size === UNDEFINED_VALUE) {
4488
- 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);
4489
4543
  }
4490
4544
  return writer;
4491
4545
  }
@@ -4533,6 +4587,45 @@ function createReadable(reader, options) {
4533
4587
  }
4534
4588
  }
4535
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
+
4536
4629
  /*
4537
4630
  Copyright (c) 2025 Gildas Lormeau. All rights reserved.
4538
4631
 
@@ -4561,6 +4654,7 @@ function createReadable(reader, options) {
4561
4654
  EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
4562
4655
  */
4563
4656
 
4657
+
4564
4658
  const PROPERTY_NAME_FILENAME = "filename";
4565
4659
  const PROPERTY_NAME_RAW_FILENAME = "rawFilename";
4566
4660
  const PROPERTY_NAME_COMMENT = "comment";
@@ -4685,6 +4779,38 @@ class Entry {
4685
4779
 
4686
4780
  }
4687
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
+
4688
4814
  /*
4689
4815
  Copyright (c) 2025 Gildas Lormeau. All rights reserved.
4690
4816
 
@@ -4744,6 +4870,8 @@ const WARNING_PREPENDED_CENTRAL_DIRECTORY = "prepended central directory";
4744
4870
  const WARNING_TRAILING_CENTRAL_DIRECTORY_DATA = "trailing central directory data";
4745
4871
  const WARNING_DUPLICATE_FILENAME = "duplicate filename";
4746
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)";
4747
4875
  const WARNING_MISMATCHED_LOCAL_FILE_HEADER_BIT_FLAG = "mismatched local file header (general purpose bit flag)";
4748
4876
  const WARNING_MISMATCHED_LOCAL_FILE_HEADER_COMPRESSION_METHOD = "mismatched local file header (compression method)";
4749
4877
  const WARNING_MISMATCHED_LOCAL_FILE_HEADER_CRC32_OR_SIZES = "mismatched local file header (crc32 or sizes)";
@@ -4814,7 +4942,7 @@ class ZipReader {
4814
4942
  }
4815
4943
  }
4816
4944
  if (rejectAmbiguousEndOfDirectory && endOfDirectoryReachingEndCount > 1) {
4817
- throwAmbiguousArchive("multiple end of central directory records");
4945
+ throwAmbiguousArchive(WARNING_MULTIPLE_END_OF_CENTRAL_DIRECTORY);
4818
4946
  }
4819
4947
  const endOfDirectoryView = getDataView(endOfDirectoryInfo);
4820
4948
  let directoryDataLength = getUint32$1(endOfDirectoryView, 12);
@@ -5112,7 +5240,8 @@ class ZipReader {
5112
5240
  const writer = new TransformStream();
5113
5241
  const arrayBufferPromise = streamToBlob(writer.readable).then(blob => blob.arrayBuffer());
5114
5242
  arrayBufferPromise.catch(() => { });
5115
- await fileEntry.getData(writer, entry, zipReader.readRanges, options);
5243
+ await fileEntry.getData(writer, entry, zipReader.readRanges,
5244
+ Object.assign({}, options, { preventClose: false }));
5116
5245
  return arrayBufferPromise;
5117
5246
  };
5118
5247
  offset = endOffset;
@@ -5193,48 +5322,101 @@ class ZipReader {
5193
5322
  await reader.readable.cancel();
5194
5323
  }
5195
5324
  }
5325
+
5326
+ [SYMBOL_ASYNC_DISPOSE]() {
5327
+ return this.close();
5328
+ }
5196
5329
  }
5197
5330
 
5198
5331
  class ZipReaderStream {
5199
5332
 
5200
5333
  constructor(options = {}) {
5201
- const { readable, writable } = new TransformStream();
5202
- 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();
5203
5343
  this.readable = new ReadableStream({
5204
5344
  async pull(controller) {
5205
5345
  const { done, value } = await gen.next();
5206
5346
  if (done)
5207
5347
  return controller.close();
5348
+ const entryStream = createEntryStream(value, pendingEntries);
5208
5349
  const chunk = {
5209
5350
  ...value,
5210
- readable: (function () {
5211
- const { readable, writable } = new TransformStream();
5212
- if (value.getData) {
5213
- getData();
5214
- return readable;
5215
- }
5216
-
5217
- async function getData() {
5218
- try {
5219
- await value.getData(writable);
5220
- } catch (error) {
5221
- try {
5222
- await writable.abort(error);
5223
- } catch {
5224
- // ignored
5225
- }
5226
- }
5227
- }
5228
- })()
5351
+ readable: entryStream.readable
5229
5352
  };
5230
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
+ });
5231
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()]);
5232
5372
  }
5233
5373
  });
5234
5374
  this.writable = writable;
5235
5375
  }
5236
5376
  }
5237
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
+
5238
5420
  async function isZipFile(reader, options = {}) {
5239
5421
  reader = new GenericReader(reader);
5240
5422
  await initStream(reader);
@@ -5294,7 +5476,9 @@ class ZipEntry {
5294
5476
  const dataView = getDataView(dataArray);
5295
5477
  let password = getOptionValue$1(zipEntry, options, OPTION_PASSWORD);
5296
5478
  let rawPassword = getOptionValue$1(zipEntry, options, OPTION_RAW_PASSWORD);
5297
- 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;
5298
5482
  checkPasswordOption(password, rawPassword);
5299
5483
  password = password && password.length && password;
5300
5484
  rawPassword = rawPassword && rawPassword.length && rawPassword;
@@ -5315,7 +5499,9 @@ class ZipEntry {
5315
5499
  const checkLocalDirectoryOption = getOptionValue$1(zipEntry, options, OPTION_CHECK_LOCAL_DIRECTORY);
5316
5500
  const entryStrictness = getStrictness(options, zipEntry.options);
5317
5501
  const checkLocalDirectory = getCheckLocalDirectory(checkLocalDirectoryOption, entryStrictness);
5318
- 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);
5319
5505
  let rawLocalFilename = EMPTY_UINT8_ARRAY;
5320
5506
  if (checkLocalFilename && (filenameLength || extraFieldLength)) {
5321
5507
  const trailingDataArray = await readUint8Array(reader, localHeaderOffset + HEADER_SIZE, filenameLength + extraFieldLength);
@@ -5346,16 +5532,17 @@ class ZipEntry {
5346
5532
  if (gid !== UNDEFINED_VALUE && fileEntry.gid === UNDEFINED_VALUE) {
5347
5533
  fileEntry.gid = gid;
5348
5534
  }
5349
- 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);
5350
5537
  const zipCrypto = encrypted && !extraFieldAES;
5351
- if (!passThrough) {
5538
+ if (!passThroughEncryption) {
5352
5539
  fileEntry.zipCrypto = zipCrypto;
5353
5540
  }
5354
5541
  if (encrypted && (localDirectory.rawBitFlag & BITFLAG_STRONG_ENCRYPTION) == BITFLAG_STRONG_ENCRYPTION) {
5355
5542
  throw new Error(ERR_UNSUPPORTED_ENCRYPTION);
5356
5543
  }
5357
- const registeredCodec = passThrough ? UNDEFINED_VALUE : getRegisteredCodec(compressionMethod);
5358
- 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) {
5359
5546
  throw new Error(ERR_UNSUPPORTED_COMPRESSION);
5360
5547
  }
5361
5548
  if (encrypted) {
@@ -5371,15 +5558,17 @@ class ZipEntry {
5371
5558
  const size = compressedSize;
5372
5559
  const readable = toCompatibleReadable(reader.createReadable({ offset: dataOffset, size }));
5373
5560
  const signal = checkSignalOption(getOptionValue$1(zipEntry, options, OPTION_SIGNAL));
5374
- const checkPasswordOnly = getOptionValue$1(zipEntry, options, OPTION_CHECK_PASSWORD_ONLY);
5561
+ throwIfAborted(signal);
5375
5562
  let checkOverlappingEntry = getOptionValue$1(zipEntry, options, OPTION_CHECK_OVERLAPPING_ENTRY);
5376
5563
  const checkOverlappingEntryOnly = getOptionValue$1(zipEntry, options, OPTION_CHECK_OVERLAPPING_ENTRY_ONLY);
5377
5564
  if (checkOverlappingEntryOnly) {
5378
5565
  checkOverlappingEntry = true;
5379
5566
  }
5380
5567
  const { onstart, onprogress, onend } = options;
5381
- const compressed = compressionMethod != COMPRESSION_METHOD_STORE && !passThrough;
5382
- 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;
5383
5572
  const deflate64 = compressionMethod == COMPRESSION_METHOD_DEFLATE_64;
5384
5573
  let useCompressionStream = getOptionValue$1(zipEntry, options, OPTION_USE_COMPRESSION_STREAM);
5385
5574
  if (deflate64) {
@@ -5388,7 +5577,7 @@ class ZipEntry {
5388
5577
  const checkCrc32Option = getOptionValue$1(zipEntry, options, OPTION_CHECK_CRC32);
5389
5578
  const checkCrc32 = (checkCrc32Option === UNDEFINED_VALUE ?
5390
5579
  getOptionValue$1(zipEntry, options, OPTION_CHECK_SIGNATURE) :
5391
- checkCrc32Option) && !passThrough &&
5580
+ checkCrc32Option) && !passThroughCompression &&
5392
5581
  (!encrypted || zipCrypto || (extraFieldAES && extraFieldAES.vendorVersion == VENDOR_VERSION_AE_1$1));
5393
5582
  const workerOptions = {
5394
5583
  options: {
@@ -5442,10 +5631,10 @@ class ZipEntry {
5442
5631
  await initStream(writer, getDecodableOutputSize(outputSize, compressedSize, compressed));
5443
5632
  ({ writable } = writer);
5444
5633
  const { outputSize: writtenSize } = await runWorker({ readable, writable }, workerOptions);
5445
- writer.size += writtenSize;
5446
5634
  if (writtenSize != outputSize) {
5447
- throw new Error(ERR_INVALID_UNCOMPRESSED_SIZE);
5635
+ throw Object.assign(new Error(ERR_INVALID_UNCOMPRESSED_SIZE), { outputSize: writtenSize });
5448
5636
  }
5637
+ writer.size += writtenSize;
5449
5638
  }
5450
5639
  } catch (error) {
5451
5640
  if (error.outputSize !== UNDEFINED_VALUE) {
@@ -6111,7 +6300,7 @@ function validateLocalDirectory(zipEntry, localDirectory, rawLocalFilename, chec
6111
6300
  if (checkLocalFilename && !maskedLocalDirectory &&
6112
6301
  (rawLocalFilename.length != rawFilename.length ||
6113
6302
  rawLocalFilename.some((byteValue, indexByte) => byteValue != rawFilename[indexByte]))) {
6114
- reportAmbiguity(reject, warnings, "mismatched local file header (filename)");
6303
+ reportAmbiguity(reject, warnings, WARNING_MISMATCHED_LOCAL_FILE_HEADER_FILENAME);
6115
6304
  }
6116
6305
  if ((localDirectory.rawBitFlag & BITFLAG_AMBIGUITY_MASK) != (zipEntry.rawBitFlag & BITFLAG_AMBIGUITY_MASK)) {
6117
6306
  reportAmbiguity(reject, warnings, WARNING_MISMATCHED_LOCAL_FILE_HEADER_BIT_FLAG);
@@ -6136,16 +6325,6 @@ function reportAmbiguity(reject, warnings, reason) {
6136
6325
  }
6137
6326
  }
6138
6327
 
6139
- function addWarning(warnings, reason, filename) {
6140
- if (!warnings.some(warning => warning.reason == reason)) {
6141
- const warning = { reason };
6142
- if (filename !== UNDEFINED_VALUE) {
6143
- warning.filename = filename;
6144
- }
6145
- warnings.push(warning);
6146
- }
6147
- }
6148
-
6149
6328
  function throwAmbiguousArchive(reason) {
6150
6329
  const error = new Error(ERR_AMBIGUOUS_ARCHIVE);
6151
6330
  error.reason = reason;
@@ -6225,7 +6404,9 @@ var zipReader = /*#__PURE__*/Object.freeze({
6225
6404
  WARNING_MISMATCHED_LOCAL_FILE_HEADER_BIT_FLAG: WARNING_MISMATCHED_LOCAL_FILE_HEADER_BIT_FLAG,
6226
6405
  WARNING_MISMATCHED_LOCAL_FILE_HEADER_COMPRESSION_METHOD: WARNING_MISMATCHED_LOCAL_FILE_HEADER_COMPRESSION_METHOD,
6227
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,
6228
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,
6229
6410
  WARNING_PREPENDED_CENTRAL_DIRECTORY: WARNING_PREPENDED_CENTRAL_DIRECTORY,
6230
6411
  WARNING_PREPENDED_DATA: WARNING_PREPENDED_DATA,
6231
6412
  WARNING_TRAILING_CENTRAL_DIRECTORY_DATA: WARNING_TRAILING_CENTRAL_DIRECTORY_DATA,
@@ -6278,7 +6459,7 @@ const ERR_INVALID_VERSION = "Version exceeds 65535";
6278
6459
  const ERR_INVALID_ENCRYPTION_STRENGTH = "The strength must equal 1, 2, or 3";
6279
6460
  const ERR_UNSUPPORTED_ENCRYPTION_USDZ = "Encryption is not supported in USDZ files";
6280
6461
  const ERR_UNSUPPORTED_SPLIT_USDZ = "Split zip files are not supported in USDZ files";
6281
- 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)";
6282
6463
  const ERR_INVALID_EXTRAFIELD = "Invalid extra field (must be a Map)";
6283
6464
  const ERR_INVALID_EXTRAFIELD_TYPE = "Invalid extra field type (must be integer 0..65535)";
6284
6465
  const ERR_INVALID_EXTRAFIELD_DATA_TYPE = "Invalid extra field data (must be a Uint8Array)";
@@ -6290,6 +6471,7 @@ const MAX_NTFS_TIME = BigInt("0x7fffffffffffffff");
6290
6471
  const ERR_UNSUPPORTED_FORMAT = "Zip64 is not supported (set the 'zip64' option to 'true')";
6291
6472
  const ERR_UNDEFINED_UNCOMPRESSED_SIZE = "Undefined uncompressed size";
6292
6473
  const ERR_UNDEFINED_COMPRESSION_METHOD = "Undefined compression method";
6474
+ const ERR_UNDEFINED_CRC32 = "Undefined CRC32";
6293
6475
  const ERR_UNDETERMINED_SIZE = "Undetermined size";
6294
6476
  const ERR_UNDEFINED_READER = "Undefined reader";
6295
6477
  const ERR_INVALID_READER = "Invalid reader (must be a Reader instance, a ReadableStream instance, or an object with a 'readable' property)";
@@ -6303,14 +6485,21 @@ const ERR_INVALID_MSDOS_ATTRIBUTES = "Invalid msdosAttributesRaw (must be intege
6303
6485
  const ERR_INVALID_MSDOS_DATA = "Invalid msdosAttributes (must be an object with boolean flags)";
6304
6486
  const ERR_INVALID_LEVEL = "Invalid level (must be integer 0..9)";
6305
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";
6306
6492
 
6307
6493
  const EXTRAFIELD_DATA_AES = new Uint8Array([0x07, 0x00, 0x02, 0x00, 0x41, 0x45, 0x03, 0x00, 0x00]);
6308
6494
  const EXTRAFIELD_OFFSET_AES_VENDOR_VERSION = 4;
6309
6495
  const EXTRAFIELD_OFFSET_AES_COMPRESSION_METHOD = 9;
6310
6496
  const EXTRAFIELD_USDZ_MAX_LENGTH = 67;
6497
+ const MIN_PRINTABLE_ASCII_CHARACTER_CODE = 0x20;
6498
+ const MAX_PRINTABLE_ASCII_CHARACTER_CODE = 0x7e;
6311
6499
  const VENDOR_VERSION_AE_1 = 1;
6312
6500
  const INFOZIP_EXTRA_FIELD_TYPE = "infozip";
6313
6501
  const UNIX_EXTRA_FIELD_TYPE = "unix";
6502
+ const LEVEL_BY_BITFLAG_LEVEL = [8, 9, 5, 3];
6314
6503
  const MAX_LEVEL = 9;
6315
6504
 
6316
6505
  let workers = 0;
@@ -6337,9 +6526,11 @@ class ZipWriter {
6337
6526
  initialOffset: options[OPTION_OFFSET] === UNDEFINED_VALUE ? 0 : options[OPTION_OFFSET] - (writer.size || writer.writable.size || 0),
6338
6527
  pendingAddFileCalls: new Set(),
6339
6528
  pendingErrors: [],
6529
+ warnings: [],
6340
6530
  bufferedWrites: 0,
6341
6531
  directWrites: 0,
6342
- lastFileEntry: UNDEFINED_VALUE
6532
+ lastFileEntry: UNDEFINED_VALUE,
6533
+ archiveClosed: false
6343
6534
  });
6344
6535
  }
6345
6536
 
@@ -6504,6 +6695,9 @@ class ZipWriter {
6504
6695
  const zipWriter = this;
6505
6696
  const { pendingAddFileCalls, writer } = this;
6506
6697
  const { writable } = writer;
6698
+ if (zipWriter.archiveClosed) {
6699
+ return getWriterData(writer);
6700
+ }
6507
6701
  if (!(comment instanceof Uint8Array)) {
6508
6702
  throw new Error(ERR_INVALID_COMMENT_TYPE);
6509
6703
  }
@@ -6527,11 +6721,16 @@ class ZipWriter {
6527
6721
  throw error;
6528
6722
  }
6529
6723
  await closeFile(zipWriter, comment, options);
6724
+ zipWriter.archiveClosed = true;
6530
6725
  const preventClose = !ownsWritable(writer) && getOptionValue(zipWriter, options, OPTION_PREVENT_CLOSE);
6531
6726
  if (!preventClose) {
6532
6727
  await writable.getWriter().close();
6533
6728
  }
6534
- return writer.getData ? writer.getData() : writable;
6729
+ return getWriterData(writer);
6730
+ }
6731
+
6732
+ [SYMBOL_ASYNC_DISPOSE]() {
6733
+ return this.close();
6535
6734
  }
6536
6735
  }
6537
6736
 
@@ -6610,6 +6809,10 @@ class WatchedPromise extends Promise {
6610
6809
  }
6611
6810
  }
6612
6811
 
6812
+ function getWriterData(writer) {
6813
+ return writer.getData ? writer.getData() : writer.writable;
6814
+ }
6815
+
6613
6816
  function watchPromiseError(zipWriter, promise) {
6614
6817
  const watchedPromise = new WatchedPromise((resolve, reject) => Promise.prototype.then.call(promise, resolve, reject));
6615
6818
  const watcher = {};
@@ -6628,6 +6831,14 @@ async function prependZipEntries(zipWriter, reader) {
6628
6831
 
6629
6832
  async function addFileEntry(zipWriter, name, reader, options) {
6630
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
+ }
6631
6842
  if (getOptionValue(zipWriter, options, PROPERTY_NAME_DIRECTORY) && !name.endsWith(DIRECTORY_SIGNATURE)) {
6632
6843
  name += DIRECTORY_SIGNATURE;
6633
6844
  }
@@ -6692,21 +6903,33 @@ async function addFile(zipWriter, name, reader, options) {
6692
6903
  try {
6693
6904
  const { resolvedOptions } = metadataInfo;
6694
6905
  if (resolvedOptions.level != 0 && resolvedOptions.compressionMethod === UNDEFINED_VALUE &&
6695
- !resolvedOptions.passThrough && !(await supportsDeflate(getConfiguration()))) {
6906
+ !resolvedOptions.passThroughCompression && !(await supportsDeflate(getConfiguration()))) {
6696
6907
  resolvedOptions.level = 0;
6908
+ addWarning(zipWriter.warnings, WARNING_COMPRESSION_UNAVAILABLE, name);
6697
6909
  }
6698
6910
  const sizesInfo = await resolveSizes(zipWriter, reader, metadataInfo, options);
6699
6911
  ({ reader } = sizesInfo);
6700
6912
  const diskOffset = getDiskOffset(zipWriter.writer);
6701
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
+ }
6702
6922
  options = Object.assign({}, options, attributesInfo.resolvedOptions, metadataInfo.resolvedOptions, sizesInfo.resolvedOptions, {
6703
6923
  signature: options[PROPERTY_NAME_SIGNATURE],
6704
- crc32: options.crc32 === UNDEFINED_VALUE ? options[PROPERTY_NAME_SIGNATURE] : options.crc32,
6924
+ crc32,
6705
6925
  offset: zipWriter.offset - diskOffset,
6706
6926
  diskNumberStart: diskNumber,
6707
6927
  [OPTION_USDZ]: zipWriter.options[OPTION_USDZ]
6708
6928
  });
6709
6929
  const headerInfo = getHeaderInfo(options);
6930
+ if (headerInfo.lastModDateClamped) {
6931
+ addWarning(zipWriter.warnings, WARNING_CLAMPED_LAST_MODIFICATION_DATE, name);
6932
+ }
6710
6933
  const dataDescriptorInfo = getDataDescriptorInfo(options);
6711
6934
  const metadataSize = getLength(headerInfo.localHeaderArray, dataDescriptorInfo.dataDescriptorArray);
6712
6935
  fileEntry = await getFileEntry(zipWriter, name, reader, {
@@ -6733,6 +6956,95 @@ async function addFile(zipWriter, name, reader, options) {
6733
6956
  return new Entry(fileEntry);
6734
6957
  }
6735
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
+
6736
7048
  function resolveAttributes(zipWriter, name, options) {
6737
7049
  let msDosCompatible = getOptionValue(zipWriter, options, PROPERTY_NAME_MS_DOS_COMPATIBLE);
6738
7050
  let versionMadeBy = getOptionValue(zipWriter, options, PROPERTY_NAME_VERSION_MADE_BY, msDosCompatible ? VERSION_MADE_BY_MSDOS : VERSION_MADE_BY_UNIX);
@@ -6886,7 +7198,9 @@ function resolveMetadata(zipWriter, name, options) {
6886
7198
  const lastAccessDate = getDateOptionValue(zipWriter, options, PROPERTY_NAME_LAST_ACCESS_DATE);
6887
7199
  const creationDate = getDateOptionValue(zipWriter, options, PROPERTY_NAME_CREATION_DATE);
6888
7200
  const internalFileAttributes = getOptionValue(zipWriter, options, PROPERTY_NAME_INTERNAL_FILE_ATTRIBUTES, 0);
6889
- 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;
6890
7204
  const password = getOptionValue(zipWriter, options, OPTION_PASSWORD);
6891
7205
  const rawPassword = getOptionValue(zipWriter, options, OPTION_RAW_PASSWORD);
6892
7206
  checkPasswordOption(password, rawPassword);
@@ -6901,10 +7215,12 @@ function resolveMetadata(zipWriter, name, options) {
6901
7215
  const createTempStream = getFunctionOptionValue(zipWriter, options, OPTION_CREATE_TEMP_STREAM);
6902
7216
  const dataDescriptorSignature = getOptionValue(zipWriter, options, OPTION_DATA_DESCRIPTOR_SIGNATURE, true);
6903
7217
  const signal = checkSignalOption(getOptionValue(zipWriter, options, OPTION_SIGNAL));
6904
- const useUnicodeFileNames = getOptionValue(zipWriter, options, OPTION_USE_UNICODE_FILE_NAMES, true);
7218
+ throwIfAborted(signal);
7219
+ const useUnicodeFileNames = getOptionValue(zipWriter, options, OPTION_USE_UNICODE_FILE_NAMES,
7220
+ !isPrintableASCIIText(rawFilename) || !isPrintableASCIIText(rawComment));
6905
7221
  const compressionMethod = getOptionValue(zipWriter, options, PROPERTY_NAME_COMPRESSION_METHOD);
6906
- const registeredCodec = passThrough || compressionMethod === UNDEFINED_VALUE ? UNDEFINED_VALUE : getRegisteredCodec(compressionMethod);
6907
- if (!passThrough && compressionMethod !== UNDEFINED_VALUE &&
7222
+ const registeredCodec = passThroughCompression || compressionMethod === UNDEFINED_VALUE ? UNDEFINED_VALUE : getRegisteredCodec(compressionMethod);
7223
+ if (!passThroughCompression && compressionMethod !== UNDEFINED_VALUE &&
6908
7224
  compressionMethod !== COMPRESSION_METHOD_STORE && compressionMethod !== COMPRESSION_METHOD_DEFLATE && !registeredCodec) {
6909
7225
  throw new Error(ERR_UNSUPPORTED_COMPRESSION);
6910
7226
  }
@@ -6918,15 +7234,15 @@ function resolveMetadata(zipWriter, name, options) {
6918
7234
  level = 0;
6919
7235
  }
6920
7236
  }
6921
- if (passThrough) {
6922
- level = UNDEFINED_VALUE;
7237
+ if (passThroughCompression) {
7238
+ level = toNumber(options[OPTION_LEVEL]);
6923
7239
  }
6924
7240
  let useCompressionStream = getOptionValue(zipWriter, options, OPTION_USE_COMPRESSION_STREAM);
6925
7241
  let dataDescriptor = getOptionValue(zipWriter, options, OPTION_DATA_DESCRIPTOR);
6926
7242
  if (bufferedWrite && dataDescriptor === UNDEFINED_VALUE) {
6927
7243
  dataDescriptor = false;
6928
7244
  }
6929
- if (dataDescriptor === UNDEFINED_VALUE || (zipCrypto && !passThrough)) {
7245
+ if (dataDescriptor === UNDEFINED_VALUE || (zipCrypto && !passThroughEncryption)) {
6930
7246
  dataDescriptor = true;
6931
7247
  }
6932
7248
  if (level !== UNDEFINED_VALUE && level != 6) {
@@ -6950,7 +7266,8 @@ function resolveMetadata(zipWriter, name, options) {
6950
7266
  lastAccessDate,
6951
7267
  creationDate,
6952
7268
  internalFileAttributes,
6953
- passThrough,
7269
+ passThroughCompression,
7270
+ passThroughEncryption,
6954
7271
  password,
6955
7272
  rawPassword,
6956
7273
  encryptionStrength,
@@ -7011,7 +7328,7 @@ function serializeExtraField(extraField) {
7011
7328
  }
7012
7329
 
7013
7330
  async function resolveSizes(zipWriter, reader, { resolvedOptions: metadata }, options) {
7014
- if (metadata.passThrough && !reader && !getOptionValue(zipWriter, options, PROPERTY_NAME_DIRECTORY)) {
7331
+ if (metadata.passThroughCompression && !reader && !getOptionValue(zipWriter, options, PROPERTY_NAME_DIRECTORY)) {
7015
7332
  throw new Error(ERR_UNDEFINED_READER);
7016
7333
  }
7017
7334
  let contentSize;
@@ -7027,12 +7344,12 @@ async function resolveSizes(zipWriter, reader, { resolvedOptions: metadata }, op
7027
7344
  }
7028
7345
 
7029
7346
  function resolveEntrySizes(zipWriter, hasContent, contentSize, metadata, options) {
7030
- const { passThrough, zipCrypto, password, rawPassword, encryptionStrength } = metadata;
7347
+ const { passThroughCompression, passThroughEncryption, zipCrypto, password, rawPassword, encryptionStrength } = metadata;
7031
7348
  let { dataDescriptor, zip64, level, compressionMethod } = metadata;
7032
7349
  let maximumCompressedSize = 0;
7033
7350
  let uncompressedSize = 0;
7034
7351
  let unknownSize = false;
7035
- if (passThrough && hasContent) {
7352
+ if (passThroughCompression && hasContent) {
7036
7353
  uncompressedSize = options[PROPERTY_NAME_UNCOMPRESSED_SIZE];
7037
7354
  if (uncompressedSize === UNDEFINED_VALUE) {
7038
7355
  throw new Error(ERR_UNDEFINED_UNCOMPRESSED_SIZE);
@@ -7043,17 +7360,17 @@ function resolveEntrySizes(zipWriter, hasContent, contentSize, metadata, options
7043
7360
  }
7044
7361
  const zip64Enabled = zip64 === true;
7045
7362
  const encrypted = getOptionValue(zipWriter, options, PROPERTY_NAME_ENCRYPTED);
7046
- if (hasContent && passThrough && !encrypted && getLength(password, rawPassword)) {
7363
+ if (hasContent && passThroughEncryption && !encrypted && getLength(password, rawPassword)) {
7047
7364
  throw new Error(ERR_UNSUPPORTED_ENCRYPTION_PASS_THROUGH);
7048
7365
  }
7049
- 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));
7050
7367
  if (!hasContent) {
7051
7368
  level = 0;
7052
7369
  compressionMethod = COMPRESSION_METHOD_STORE;
7053
7370
  }
7054
- const encryptionOverhead = encryptedEntry ? (zipCrypto ? 12 : 16 + encryptionStrength * 4) : 0;
7371
+ const encryptionOverhead = getEncryptionOverhead(encryptedEntry, zipCrypto, encryptionStrength);
7055
7372
  if (hasContent) {
7056
- if (!passThrough) {
7373
+ if (!passThroughCompression) {
7057
7374
  if (contentSize === UNDEFINED_VALUE) {
7058
7375
  dataDescriptor = true;
7059
7376
  if (zip64 || zip64 === UNDEFINED_VALUE) {
@@ -7066,10 +7383,12 @@ function resolveEntrySizes(zipWriter, hasContent, contentSize, metadata, options
7066
7383
  }
7067
7384
  } else {
7068
7385
  options.uncompressedSize = uncompressedSize;
7069
- maximumCompressedSize = contentSize === UNDEFINED_VALUE ? getMaximumCompressedSize(uncompressedSize) + encryptionOverhead : contentSize;
7386
+ maximumCompressedSize = contentSize === UNDEFINED_VALUE ?
7387
+ getMaximumCompressedSize(uncompressedSize) + encryptionOverhead :
7388
+ contentSize + (passThroughEncryption ? 0 : encryptionOverhead);
7070
7389
  }
7071
7390
  }
7072
- const emptyEntry = !encryptedEntry && (!hasContent || (contentSize === 0 && !passThrough)) && !isCompressed(compressionMethod, level);
7391
+ const emptyEntry = !encryptedEntry && (!hasContent || (contentSize === 0 && !passThroughCompression)) && !isCompressed(compressionMethod, level);
7073
7392
  if (emptyEntry && !zipCrypto && getOptionValue(zipWriter, options, OPTION_DATA_DESCRIPTOR) === UNDEFINED_VALUE) {
7074
7393
  dataDescriptor = false;
7075
7394
  }
@@ -7276,6 +7595,7 @@ async function createFileEntry(reader, writer, { diskNumberStart, lockFileEntry
7276
7595
  localExtraFieldZip64Length,
7277
7596
  rawExtraFieldExtendedTimestamp,
7278
7597
  extraFieldExtendedTimestampFlag,
7598
+ extraFieldExtendedTimestampTime,
7279
7599
  rawExtraFieldNTFS,
7280
7600
  rawExtraFieldUnix,
7281
7601
  rawExtraFieldAES,
@@ -7288,6 +7608,7 @@ async function createFileEntry(reader, writer, { diskNumberStart, lockFileEntry
7288
7608
  password,
7289
7609
  rawPassword,
7290
7610
  level,
7611
+ useUnicodeFileNames,
7291
7612
  zip64,
7292
7613
  zip64Enabled,
7293
7614
  zip64UncompressedSize,
@@ -7322,7 +7643,8 @@ async function createFileEntry(reader, writer, { diskNumberStart, lockFileEntry
7322
7643
  msdosAttributesRaw,
7323
7644
  msdosAttributes,
7324
7645
  useCompressionStream,
7325
- passThrough,
7646
+ passThroughCompression,
7647
+ passThroughEncryption,
7326
7648
  format,
7327
7649
  codecURI
7328
7650
  } = options;
@@ -7333,9 +7655,9 @@ async function createFileEntry(reader, writer, { diskNumberStart, lockFileEntry
7333
7655
  zip64Enabled,
7334
7656
  directory: Boolean(directory),
7335
7657
  executable: Boolean(executable),
7336
- filenameUTF8: true,
7658
+ filenameUTF8: Boolean(useUnicodeFileNames),
7337
7659
  rawFilename,
7338
- commentUTF8: true,
7660
+ commentUTF8: Boolean(useUnicodeFileNames),
7339
7661
  rawComment,
7340
7662
  rawExtraFieldZip64,
7341
7663
  localExtraFieldZip64Length,
@@ -7366,7 +7688,7 @@ async function createFileEntry(reader, writer, { diskNumberStart, lockFileEntry
7366
7688
  uncompressedSize
7367
7689
  } = options;
7368
7690
  let compressedSize = 0;
7369
- if (!passThrough) {
7691
+ if (!passThroughCompression) {
7370
7692
  uncompressedSize = 0;
7371
7693
  }
7372
7694
  const { writable } = writer;
@@ -7383,9 +7705,9 @@ async function createFileEntry(reader, writer, { diskNumberStart, lockFileEntry
7383
7705
  encryptionStrength,
7384
7706
  zipCrypto: encrypted && zipCrypto,
7385
7707
  passwordVerification: encrypted && zipCrypto && (rawLastModDate >> 8) & MAX_8_BITS,
7386
- computeCrc32: !passThrough,
7387
- compressed: compressed && !passThrough,
7388
- encrypted: encrypted && !passThrough,
7708
+ computeCrc32: !passThroughCompression,
7709
+ compressed: compressed && !passThroughCompression,
7710
+ encrypted: encrypted && !passThroughEncryption,
7389
7711
  useWebWorkers,
7390
7712
  useCompressionStream,
7391
7713
  transferStreams,
@@ -7400,7 +7722,7 @@ async function createFileEntry(reader, writer, { diskNumberStart, lockFileEntry
7400
7722
  const result = await runWorker({ readable, writable }, workerOptions);
7401
7723
  compressedSize = result.outputSize;
7402
7724
  writer.size += compressedSize;
7403
- if (!passThrough) {
7725
+ if (!passThroughCompression) {
7404
7726
  uncompressedSize = result.inputSize;
7405
7727
  if (!encrypted || zipCrypto) {
7406
7728
  crc32 = result.crc32;
@@ -7443,8 +7765,9 @@ async function createFileEntry(reader, writer, { diskNumberStart, lockFileEntry
7443
7765
  headerArray,
7444
7766
  headerView,
7445
7767
  signature: crc32,
7446
- crc32: encrypted && !zipCrypto && !passThrough ? UNDEFINED_VALUE : crc32,
7768
+ crc32: encrypted && !zipCrypto && !passThroughCompression ? UNDEFINED_VALUE : crc32,
7447
7769
  extraFieldExtendedTimestampFlag,
7770
+ extraFieldExtendedTimestampTime,
7448
7771
  zip64UncompressedSize,
7449
7772
  zip64CompressedSize
7450
7773
  });
@@ -7469,7 +7792,7 @@ function getHeaderInfo(options) {
7469
7792
  encryptionStrength,
7470
7793
  extendedTimestamp,
7471
7794
  ntfsTimestamp,
7472
- passThrough,
7795
+ passThroughCompression,
7473
7796
  encrypted,
7474
7797
  zip64UncompressedSize,
7475
7798
  zip64CompressedSize,
@@ -7480,7 +7803,7 @@ function getHeaderInfo(options) {
7480
7803
  let { version, compressionMethod } = options;
7481
7804
  const compressed = !directory && isCompressed(compressionMethod, level);
7482
7805
  let rawLocalExtraFieldZip64;
7483
- const uncompressedFile = passThrough || !compressed;
7806
+ const uncompressedFile = passThroughCompression || !compressed;
7484
7807
  const zip64ExtraFieldComplete = zip64 && (options.bufferedWrite || !dataDescriptor || ((!zip64UncompressedSize && !zip64CompressedSize) || (uncompressedFile && !unknownSize)));
7485
7808
  const writeLocalExtraFieldZip64 = zip64ExtraFieldComplete || (zip64 && dataDescriptor && (zip64UncompressedSize || zip64CompressedSize));
7486
7809
  if (zip64 && (zip64UncompressedSize || zip64CompressedSize)) {
@@ -7492,8 +7815,8 @@ function getHeaderInfo(options) {
7492
7815
  if (zip64ExtraFieldComplete) {
7493
7816
  extraFieldZip64.writeUint64(uncompressedSize);
7494
7817
  if (uncompressedFile) {
7495
- const encryptionOverhead = encrypted ? (zipCrypto ? 12 : 16 + encryptionStrength * 4) : 0;
7496
- extraFieldZip64.writeUint64(passThrough ? 0 : uncompressedSize + encryptionOverhead);
7818
+ const encryptionOverhead = getEncryptionOverhead(encrypted, zipCrypto, encryptionStrength);
7819
+ extraFieldZip64.writeUint64(passThroughCompression ? 0 : uncompressedSize + encryptionOverhead);
7497
7820
  }
7498
7821
  }
7499
7822
  } else {
@@ -7512,6 +7835,7 @@ function getHeaderInfo(options) {
7512
7835
  let rawExtraFieldNTFS;
7513
7836
  let rawExtraFieldExtendedTimestamp;
7514
7837
  let extraFieldExtendedTimestampFlag;
7838
+ let extraFieldExtendedTimestampTime;
7515
7839
  if (extendedTimestamp) {
7516
7840
  const lastModTimeUnix = getTimeUnix(lastModDate);
7517
7841
  const lastModTimeUnixInRange = inUnixTimeRange(lastModTimeUnix);
@@ -7519,6 +7843,7 @@ function getHeaderInfo(options) {
7519
7843
  const extraFieldTimestampLength = 9 + (lastAccessDate ? 4 : 0) + (creationDate ? 4 : 0);
7520
7844
  const extraFieldTimestamp = createRecordWriter(extraFieldTimestampLength);
7521
7845
  extraFieldExtendedTimestampFlag = 0x1 + (lastAccessDate ? 0x2 : 0) + (creationDate ? 0x4 : 0);
7846
+ extraFieldExtendedTimestampTime = lastModTimeUnix;
7522
7847
  extraFieldTimestamp.writeUint16(EXTRAFIELD_TYPE_EXTENDED_TIMESTAMP);
7523
7848
  extraFieldTimestamp.writeUint16(extraFieldTimestampLength - 4);
7524
7849
  extraFieldTimestamp.writeUint8(extraFieldExtendedTimestampFlag);
@@ -7602,7 +7927,7 @@ function getHeaderInfo(options) {
7602
7927
  }
7603
7928
  if (encrypted && !zipCrypto) {
7604
7929
  version = version > VERSION_AES ? version : VERSION_AES;
7605
- if (passThrough && crc32 !== UNDEFINED_VALUE) {
7930
+ if (passThroughCompression && crc32 !== UNDEFINED_VALUE) {
7606
7931
  rawExtraFieldAES[EXTRAFIELD_OFFSET_AES_VENDOR_VERSION] = VENDOR_VERSION_AE_1;
7607
7932
  }
7608
7933
  setUint16(getDataView(rawExtraFieldAES), EXTRAFIELD_OFFSET_AES_COMPRESSION_METHOD, compressionMethod);
@@ -7664,12 +7989,14 @@ function getHeaderInfo(options) {
7664
7989
  headerArray,
7665
7990
  headerView,
7666
7991
  lastModDate: storedLastModDate,
7992
+ lastModDateClamped: storedLastModDate === clampedLastModDate && dosLastModDate.getTime() != clampedLastModDate.getTime(),
7667
7993
  rawLastModDate,
7668
7994
  encrypted,
7669
7995
  compressed,
7670
7996
  version,
7671
7997
  compressionMethod,
7672
7998
  extraFieldExtendedTimestampFlag,
7999
+ extraFieldExtendedTimestampTime,
7673
8000
  rawExtraFieldZip64: EMPTY_UINT8_ARRAY,
7674
8001
  localExtraFieldZip64Length,
7675
8002
  rawExtraFieldExtendedTimestamp,
@@ -7772,7 +8099,7 @@ function setEntryInfo({
7772
8099
  }, {
7773
8100
  zip64,
7774
8101
  zipCrypto,
7775
- passThrough,
8102
+ passThroughCompression,
7776
8103
  dataDescriptor
7777
8104
  }) {
7778
8105
  const {
@@ -7783,7 +8110,7 @@ function setEntryInfo({
7783
8110
  dataDescriptorView,
7784
8111
  dataDescriptorOffset
7785
8112
  } = dataDescriptorInfo;
7786
- if ((!encrypted || zipCrypto || passThrough) && crc32 !== UNDEFINED_VALUE) {
8113
+ if ((!encrypted || zipCrypto || passThroughCompression) && crc32 !== UNDEFINED_VALUE) {
7787
8114
  setUint32(headerView, HEADER_OFFSET_SIGNATURE, crc32);
7788
8115
  if (dataDescriptor) {
7789
8116
  setUint32(dataDescriptorView, dataDescriptorOffset, crc32);
@@ -7814,9 +8141,9 @@ function updateLocalHeader({
7814
8141
  uncompressedSize,
7815
8142
  zip64UncompressedSize,
7816
8143
  zip64CompressedSize
7817
- }, localHeaderView, { dataDescriptor, passThrough }) {
8144
+ }, localHeaderView, { dataDescriptor, passThroughCompression }) {
7818
8145
  if (!dataDescriptor) {
7819
- if (!encrypted || (passThrough && crc32 !== UNDEFINED_VALUE)) {
8146
+ if (!encrypted || (passThroughCompression && crc32 !== UNDEFINED_VALUE)) {
7820
8147
  setUint32(localHeaderView, HEADER_OFFSET_SIGNATURE + LOCAL_HEADER_COMMON_OFFSET, crc32);
7821
8148
  }
7822
8149
  if (!zip64CompressedSize) {
@@ -7853,9 +8180,8 @@ function createDirectoryRecords(files) {
7853
8180
  rawExtraFieldUnix,
7854
8181
  rawExtraField,
7855
8182
  rawCentralExtraField,
7856
- extendedTimestamp,
7857
8183
  extraFieldExtendedTimestampFlag,
7858
- lastModDate,
8184
+ extraFieldExtendedTimestampTime,
7859
8185
  zip64Enabled,
7860
8186
  uncompressedSize,
7861
8187
  compressedSize
@@ -7898,16 +8224,15 @@ function createDirectoryRecords(files) {
7898
8224
  fileEntry.zip64Offset = zip64Offset;
7899
8225
  fileEntry.zip64DiskNumberStart = zip64DiskNumberStart;
7900
8226
  let rawExtraFieldTimestamp;
7901
- const lastModTimeUnix = getTimeUnix(lastModDate);
7902
- if (extendedTimestamp && inUnixTimeRange(lastModTimeUnix)) {
8227
+ if (extraFieldExtendedTimestampTime === UNDEFINED_VALUE) {
8228
+ rawExtraFieldTimestamp = EMPTY_UINT8_ARRAY;
8229
+ } else {
7903
8230
  const extraFieldTimestamp = createRecordWriter(9);
7904
8231
  extraFieldTimestamp.writeUint16(EXTRAFIELD_TYPE_EXTENDED_TIMESTAMP);
7905
8232
  extraFieldTimestamp.writeUint16(5);
7906
8233
  extraFieldTimestamp.writeUint8(extraFieldExtendedTimestampFlag);
7907
- extraFieldTimestamp.writeUint32(lastModTimeUnix);
8234
+ extraFieldTimestamp.writeUint32(extraFieldExtendedTimestampTime);
7908
8235
  rawExtraFieldTimestamp = extraFieldTimestamp.array;
7909
- } else {
7910
- rawExtraFieldTimestamp = EMPTY_UINT8_ARRAY;
7911
8236
  }
7912
8237
  fileEntry.rawExtraFieldExtendedTimestamp = rawExtraFieldTimestamp;
7913
8238
  const extraFieldLength = getLength(
@@ -8407,6 +8732,11 @@ function getHeaderArrayData({
8407
8732
  };
8408
8733
  }
8409
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
+
8410
8740
  function getBitFlag(level, useUnicodeFileNames, dataDescriptor, encrypted, compressionMethod) {
8411
8741
  let bitFlag = 0;
8412
8742
  if (useUnicodeFileNames) {
@@ -8568,7 +8898,7 @@ function formatSupported(StreamClass, format) {
8568
8898
  EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
8569
8899
  */
8570
8900
 
8571
- const VERSION = "2.11.3";
8901
+ const VERSION = "2.12.0";
8572
8902
 
8573
8903
  /*
8574
8904
  Copyright (c) 2025 Gildas Lormeau. All rights reserved.
@@ -9388,9 +9718,9 @@ setDefaultConfiguration({
9388
9718
  DecompressionStreamFallback: DecompressionStreamZlib
9389
9719
  });
9390
9720
 
9391
- function terminateWorkersAndModule() {
9721
+ async function terminateWorkersAndModule() {
9722
+ await terminateWorkers();
9392
9723
  modulePromise = null;
9393
- terminateWorkers();
9394
9724
  resetWasmModule();
9395
9725
  }
9396
9726
 
@@ -9399,4 +9729,4 @@ function terminateWorkersAndModule() {
9399
9729
 
9400
9730
  configureExternalAssets();
9401
9731
 
9402
- 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 };