@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
package/dist/zip-core.js CHANGED
@@ -134,6 +134,7 @@
134
134
  const BOOLEAN_TYPE = "boolean";
135
135
 
136
136
  const EMPTY_UINT8_ARRAY = new Uint8Array();
137
+ const SYMBOL_ASYNC_DISPOSE = Symbol.asyncDispose || Symbol();
137
138
 
138
139
  /*
139
140
  Copyright (c) 2022 Gildas Lormeau. All rights reserved.
@@ -178,6 +179,7 @@
178
179
  const OPTION_CHECK_OVERLAPPING_ENTRY = "checkOverlappingEntry";
179
180
  const OPTION_CHECK_AMBIGUITY = "checkAmbiguity";
180
181
  const OPTION_CHECK_LOCAL_DIRECTORY = "checkLocalDirectory";
182
+ const OPTION_CHECK_LOCAL_FILENAME = "checkLocalFilename";
181
183
  const OPTION_CHECK_SIGNATURE = "checkSignature";
182
184
  const OPTION_CHECK_CRC32 = "checkCrc32";
183
185
  const OPTION_CHECK_AUTHENTICATION_CODE = "checkAuthenticationCode";
@@ -208,15 +210,20 @@
208
210
  const OPTION_MAX_APPENDED_DATA_SIZE = "maxAppendedDataSize";
209
211
  const OPTION_DECRYPT_CENTRAL_DIRECTORY = "decryptCentralDirectory";
210
212
  const OPTION_SIGN_CENTRAL_DIRECTORY = "signCentralDirectory";
213
+ const OPTION_ENTRY = "entry";
211
214
  const TEXT_TYPE_FILENAME = "filename";
212
215
  const TEXT_TYPE_COMMENT = "comment";
213
216
  const STRICTNESS_STRICT = "strict";
214
217
  const STRICTNESS_BALANCED = "balanced";
215
218
  const STRICTNESS_TOLERANT = "tolerant";
219
+ const PASS_THROUGH_COMPRESSED = "compressed";
216
220
 
217
221
  const ERR_INVALID_FUNCTION_OPTION = "Invalid option (must be a function)";
218
222
  const ERR_INVALID_SIGNAL = "Invalid signal (must be an AbortSignal instance)";
219
223
  const ERR_INVALID_PASSWORD_TYPE = "Invalid password (password must be a string, rawPassword must be a Uint8Array)";
224
+ const ERR_INVALID_PASS_THROUGH_VALUE = "Invalid passThrough option (must be a boolean or 'compressed')";
225
+ const ERR_ABORTED = "The operation was aborted";
226
+ const ABORT_ERROR_NAME = "AbortError";
220
227
 
221
228
  function checkFunctionOption(value) {
222
229
  if (value && typeof value != FUNCTION_TYPE) {
@@ -232,12 +239,25 @@
232
239
  return signal || UNDEFINED_VALUE;
233
240
  }
234
241
 
242
+ function throwIfAborted(signal) {
243
+ if (signal && signal.aborted) {
244
+ throw signal.reason === UNDEFINED_VALUE ? new DOMException(ERR_ABORTED, ABORT_ERROR_NAME) : signal.reason;
245
+ }
246
+ }
247
+
235
248
  function checkPasswordOption(password, rawPassword) {
236
249
  if ((password && typeof password != STRING_TYPE) || (rawPassword && !(rawPassword instanceof Uint8Array))) {
237
250
  throw new Error(ERR_INVALID_PASSWORD_TYPE);
238
251
  }
239
252
  }
240
253
 
254
+ function checkPassThroughOption(passThrough) {
255
+ if (passThrough !== UNDEFINED_VALUE && typeof passThrough != BOOLEAN_TYPE && passThrough !== PASS_THROUGH_COMPRESSED) {
256
+ throw new Error(ERR_INVALID_PASS_THROUGH_VALUE);
257
+ }
258
+ return passThrough;
259
+ }
260
+
241
261
  function checkInteger(value, maxValue, errorMessage) {
242
262
  if (!Number.isInteger(value) || value < 0 || value > maxValue) {
243
263
  throw new Error(errorMessage);
@@ -287,6 +307,8 @@
287
307
  const MINIMUM_CHUNK_SIZE = 64;
288
308
  const MINIMUM_PROPERTY_VALUE = 1;
289
309
  const ERR_INVALID_MAX_WORKERS = "Invalid maxWorkers (must be an integer greater than 0)";
310
+ const ERR_INVALID_BASE_URI = "Invalid baseURI (must be a string)";
311
+ const ERR_INVALID_URI = "Invalid URI (must be a string or a function returning a string)";
290
312
  let maxWorkers = 2;
291
313
  try {
292
314
  if (typeof navigator != UNDEFINED_TYPE && navigator.hardwareConcurrency) {
@@ -311,9 +333,9 @@
311
333
  };
312
334
 
313
335
  const PROPERTY_NAME_MAX_WORKERS = "maxWorkers";
336
+ const PROPERTY_NAME_BASE_URI = "baseURI";
314
337
 
315
- const STRING_PROPERTY_NAMES = [
316
- "baseURI",
338
+ const URI_PROPERTY_NAMES = [
317
339
  "wasmURI",
318
340
  "workerURI"
319
341
  ];
@@ -337,7 +359,8 @@
337
359
  "DecompressionStreamFallback"
338
360
  ];
339
361
  const CONFIGURABLE_PROPERTY_NAMES = [
340
- ...STRING_PROPERTY_NAMES,
362
+ PROPERTY_NAME_BASE_URI,
363
+ ...URI_PROPERTY_NAMES,
341
364
  ...BOOLEAN_PROPERTY_NAMES,
342
365
  ...NUMBER_PROPERTY_NAMES,
343
366
  ...FUNCTION_PROPERTY_NAMES
@@ -381,6 +404,14 @@
381
404
  }
382
405
  } else if (FUNCTION_PROPERTY_NAMES.includes(propertyName)) {
383
406
  checkFunctionOption(propertyValue);
407
+ } else if (propertyName == PROPERTY_NAME_BASE_URI) {
408
+ if (propertyValue && typeof propertyValue != STRING_TYPE) {
409
+ throw new Error(ERR_INVALID_BASE_URI);
410
+ }
411
+ } else if (URI_PROPERTY_NAMES.includes(propertyName)) {
412
+ if (propertyValue && typeof propertyValue != STRING_TYPE && typeof propertyValue != FUNCTION_TYPE) {
413
+ throw new Error(ERR_INVALID_URI);
414
+ }
384
415
  }
385
416
  return propertyValue;
386
417
  }
@@ -2597,6 +2628,7 @@
2597
2628
  constructor(chunkSize) {
2598
2629
  const pendingChunks = [];
2599
2630
  let pendingLength = 0;
2631
+ let outputSize = 0;
2600
2632
  if (!Number.isFinite(chunkSize) || chunkSize < 1) {
2601
2633
  chunkSize = DEFAULT_CHUNK_SIZE;
2602
2634
  }
@@ -2605,15 +2637,20 @@
2605
2637
  pendingChunks.push(chunk);
2606
2638
  pendingLength += chunk.length;
2607
2639
  while (pendingLength > chunkSize) {
2640
+ outputSize += chunkSize;
2608
2641
  controller.enqueue(shiftChunk());
2609
2642
  }
2610
2643
  },
2611
2644
  flush(controller) {
2612
2645
  if (pendingLength) {
2646
+ outputSize += pendingLength;
2613
2647
  controller.enqueue(concatChunks(pendingChunks, pendingLength));
2614
2648
  }
2615
2649
  }
2616
2650
  });
2651
+ Object.defineProperty(this, "outputSize", {
2652
+ get: () => outputSize
2653
+ });
2617
2654
 
2618
2655
  function shiftChunk() {
2619
2656
  const result = new Uint8Array(chunkSize);
@@ -2814,7 +2851,7 @@
2814
2851
  }
2815
2852
 
2816
2853
  async function runWorker$1({ options, readable, writable, onTaskFinished }, config) {
2817
- let codecStream;
2854
+ let codecStream, chunkStream;
2818
2855
  try {
2819
2856
  if (options.compressed && !options.format) {
2820
2857
  const deflate = options.codecType.startsWith(CODEC_DEFLATE);
@@ -2837,9 +2874,10 @@
2837
2874
  }
2838
2875
  }
2839
2876
  codecStream = new CodecStream(options, config);
2877
+ chunkStream = new ChunkStream(getChunkSize(config));
2840
2878
  await readable
2841
2879
  .pipeThrough(codecStream)
2842
- .pipeThrough(new ChunkStream(getChunkSize(config)))
2880
+ .pipeThrough(chunkStream)
2843
2881
  .pipeTo(writable, { preventClose: true, preventAbort: true });
2844
2882
  const {
2845
2883
  crc32,
@@ -2853,7 +2891,7 @@
2853
2891
  };
2854
2892
  } catch (error) {
2855
2893
  if (codecStream) {
2856
- error.outputSize = codecStream.outputSize;
2894
+ error.outputSize = chunkStream ? chunkStream.outputSize : 0;
2857
2895
  }
2858
2896
  throw error;
2859
2897
  } finally {
@@ -2962,11 +3000,17 @@
2962
3000
  let resolveResult, rejectResult;
2963
3001
  const result = new Promise((resolve, reject) => {
2964
3002
  resolveResult = resolve;
2965
- rejectResult = reject;
3003
+ rejectResult = error => {
3004
+ if (error && error.outputSize === UNDEFINED_VALUE) {
3005
+ error.outputSize = workerData.outputSize;
3006
+ }
3007
+ reject(error);
3008
+ };
2966
3009
  });
2967
3010
  Object.assign(workerData, {
2968
3011
  reader: null,
2969
3012
  writer: null,
3013
+ outputSize: 0,
2970
3014
  resolveResult,
2971
3015
  rejectResult,
2972
3016
  result
@@ -3250,8 +3294,10 @@
3250
3294
  }
3251
3295
  }
3252
3296
  if (type == MESSAGE_DATA) {
3297
+ const chunk = new Uint8Array(value);
3253
3298
  await writer.ready;
3254
- await writer.write(new Uint8Array(value));
3299
+ await writer.write(chunk);
3300
+ workerData.outputSize += chunk.length;
3255
3301
  if (!stale()) {
3256
3302
  sendMessage({ type: MESSAGE_ACK_DATA, messageId }, workerData);
3257
3303
  }
@@ -3559,10 +3605,13 @@
3559
3605
 
3560
3606
 
3561
3607
  const ERR_HTTP_STATUS = "HTTP error ";
3608
+ const MIN_SUCCESS_HTTP_STATUS = 200;
3609
+ const MAX_SUCCESS_HTTP_STATUS = 299;
3562
3610
  const ERR_HTTP_RANGE = "HTTP Range not supported";
3563
3611
  const ERR_HTTP_RESOURCE_CHANGED = "HTTP resource changed";
3564
3612
  const ERR_ITERATOR_COMPLETED_TOO_SOON = "Writer iterator completed too soon";
3565
3613
  const ERR_WRITER_NOT_INITIALIZED = "Writer not initialized";
3614
+ const ERR_WRITER_SIZE_NOT_WRITABLE = "Invalid writer (size must be writable)";
3566
3615
 
3567
3616
  const CONTENT_TYPE_TEXT_PLAIN = "text/plain";
3568
3617
  const HTTP_HEADER_CONTENT_LENGTH = "Content-Length";
@@ -3754,11 +3803,14 @@
3754
3803
  const reader = this;
3755
3804
  const { sourceBlob, size } = reader;
3756
3805
  const { offset = 0, size: readSize = size - offset } = options || {};
3757
- if (!offset && readSize >= size) {
3758
- return toCompatibleReadable(sourceBlob.stream());
3759
- }
3760
- if (blobSliceReliable) {
3761
- return toCompatibleReadable(sourceBlob.slice(offset, offset + readSize).stream());
3806
+ // deno-lint-ignore valid-typeof
3807
+ if (typeof sourceBlob.stream == FUNCTION_TYPE) {
3808
+ if (!offset && readSize >= size) {
3809
+ return toCompatibleReadable(sourceBlob.stream());
3810
+ }
3811
+ if (blobSliceReliable) {
3812
+ return toCompatibleReadable(sourceBlob.slice(offset, offset + readSize).stream());
3813
+ }
3762
3814
  }
3763
3815
  return super.createReadable(options);
3764
3816
  }
@@ -4138,7 +4190,7 @@
4138
4190
 
4139
4191
  async function sendFetchRequest(method, { fetch: fetchFunction = fetch, options, url }, headers) {
4140
4192
  const response = await fetchFunction(url, Object.assign({}, options, { method, headers }));
4141
- if (response.status < 400) {
4193
+ if (response.status >= MIN_SUCCESS_HTTP_STATUS && response.status <= MAX_SUCCESS_HTTP_STATUS) {
4142
4194
  return response;
4143
4195
  } else {
4144
4196
  throw response.status == 416 ? new Error(ERR_HTTP_RANGE) : new Error(ERR_HTTP_STATUS + (response.statusText || response.status));
@@ -4149,7 +4201,7 @@
4149
4201
  return new Promise((resolve, reject) => {
4150
4202
  const request = new XMLHttpRequest();
4151
4203
  request.addEventListener("load", () => {
4152
- if (request.status < 400) {
4204
+ if (request.status >= MIN_SUCCESS_HTTP_STATUS && request.status <= MAX_SUCCESS_HTTP_STATUS) {
4153
4205
  const headers = [];
4154
4206
  request.getAllResponseHeaders().trim().split(/[\r\n]+/).forEach(header => {
4155
4207
  const splitHeader = header.trim().split(/\s*:\s*/);
@@ -4453,8 +4505,10 @@
4453
4505
  writable: toCompatibleWritable(writer)
4454
4506
  };
4455
4507
  }
4456
- if (writer.size === UNDEFINED_VALUE) {
4457
- writer.size = 0;
4508
+ try {
4509
+ writer.size = writer.size === UNDEFINED_VALUE ? 0 : writer.size;
4510
+ } catch {
4511
+ throw new Error(ERR_WRITER_SIZE_NOT_WRITABLE);
4458
4512
  }
4459
4513
  return writer;
4460
4514
  }
@@ -4502,6 +4556,45 @@
4502
4556
  }
4503
4557
  }
4504
4558
 
4559
+ /*
4560
+ Copyright (c) 2026 Gildas Lormeau. All rights reserved.
4561
+
4562
+ Redistribution and use in source and binary forms, with or without
4563
+ modification, are permitted provided that the following conditions are met:
4564
+
4565
+ 1. Redistributions of source code must retain the above copyright notice,
4566
+ this list of conditions and the following disclaimer.
4567
+
4568
+ 2. Redistributions in binary form must reproduce the above copyright
4569
+ notice, this list of conditions and the following disclaimer in
4570
+ the documentation and/or other materials provided with the distribution.
4571
+
4572
+ 3. The names of the authors may not be used to endorse or promote products
4573
+ derived from this software without specific prior written permission.
4574
+
4575
+ THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
4576
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
4577
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
4578
+ INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
4579
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
4580
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
4581
+ OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
4582
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
4583
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
4584
+ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
4585
+ */
4586
+
4587
+
4588
+ function addWarning(warnings, reason, filename) {
4589
+ if (!warnings.some(warning => warning.reason == reason)) {
4590
+ const warning = { reason };
4591
+ if (filename !== UNDEFINED_VALUE) {
4592
+ warning.filename = filename;
4593
+ }
4594
+ warnings.push(warning);
4595
+ }
4596
+ }
4597
+
4505
4598
  /*
4506
4599
  Copyright (c) 2025 Gildas Lormeau. All rights reserved.
4507
4600
 
@@ -4530,6 +4623,7 @@
4530
4623
  EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
4531
4624
  */
4532
4625
 
4626
+
4533
4627
  const PROPERTY_NAME_FILENAME = "filename";
4534
4628
  const PROPERTY_NAME_RAW_FILENAME = "rawFilename";
4535
4629
  const PROPERTY_NAME_COMMENT = "comment";
@@ -4654,6 +4748,38 @@
4654
4748
 
4655
4749
  }
4656
4750
 
4751
+ const INTERPRETED_EXTRA_FIELD_TYPES = new Set([
4752
+ EXTRAFIELD_TYPE_ZIP64,
4753
+ EXTRAFIELD_TYPE_AES,
4754
+ EXTRAFIELD_TYPE_NTFS,
4755
+ EXTRAFIELD_TYPE_EXTENDED_TIMESTAMP,
4756
+ EXTRAFIELD_TYPE_UNICODE_PATH,
4757
+ EXTRAFIELD_TYPE_UNICODE_COMMENT,
4758
+ EXTRAFIELD_TYPE_USDZ,
4759
+ EXTRAFIELD_TYPE_INFOZIP,
4760
+ EXTRAFIELD_TYPE_UNIX,
4761
+ EXTRAFIELD_TYPE_UNIX_TYPE1,
4762
+ EXTRAFIELD_TYPE_PKWARE_UNIX
4763
+ ]);
4764
+
4765
+ function getUserExtraField(extraField) {
4766
+ if (extraField) {
4767
+ const userExtraField = new Map();
4768
+ extraField.forEach((field, type) => {
4769
+ if (!INTERPRETED_EXTRA_FIELD_TYPES.has(type)) {
4770
+ userExtraField.set(type, field.data);
4771
+ }
4772
+ });
4773
+ if (userExtraField.size) {
4774
+ return userExtraField;
4775
+ }
4776
+ }
4777
+ }
4778
+
4779
+ function getEncryptionOverhead(encrypted, zipCrypto, encryptionStrength) {
4780
+ return encrypted ? (zipCrypto ? 12 : 16 + encryptionStrength * 4) : 0;
4781
+ }
4782
+
4657
4783
  /*
4658
4784
  Copyright (c) 2025 Gildas Lormeau. All rights reserved.
4659
4785
 
@@ -4713,6 +4839,8 @@
4713
4839
  const WARNING_TRAILING_CENTRAL_DIRECTORY_DATA = "trailing central directory data";
4714
4840
  const WARNING_DUPLICATE_FILENAME = "duplicate filename";
4715
4841
  const WARNING_MISMATCHED_ZIP64_END_OF_CENTRAL_DIRECTORY = "mismatched zip64 end of central directory record";
4842
+ const WARNING_MULTIPLE_END_OF_CENTRAL_DIRECTORY = "multiple end of central directory records";
4843
+ const WARNING_MISMATCHED_LOCAL_FILE_HEADER_FILENAME = "mismatched local file header (filename)";
4716
4844
  const WARNING_MISMATCHED_LOCAL_FILE_HEADER_BIT_FLAG = "mismatched local file header (general purpose bit flag)";
4717
4845
  const WARNING_MISMATCHED_LOCAL_FILE_HEADER_COMPRESSION_METHOD = "mismatched local file header (compression method)";
4718
4846
  const WARNING_MISMATCHED_LOCAL_FILE_HEADER_CRC32_OR_SIZES = "mismatched local file header (crc32 or sizes)";
@@ -4783,7 +4911,7 @@
4783
4911
  }
4784
4912
  }
4785
4913
  if (rejectAmbiguousEndOfDirectory && endOfDirectoryReachingEndCount > 1) {
4786
- throwAmbiguousArchive("multiple end of central directory records");
4914
+ throwAmbiguousArchive(WARNING_MULTIPLE_END_OF_CENTRAL_DIRECTORY);
4787
4915
  }
4788
4916
  const endOfDirectoryView = getDataView(endOfDirectoryInfo);
4789
4917
  let directoryDataLength = getUint32$1(endOfDirectoryView, 12);
@@ -5081,7 +5209,8 @@
5081
5209
  const writer = new TransformStream();
5082
5210
  const arrayBufferPromise = streamToBlob(writer.readable).then(blob => blob.arrayBuffer());
5083
5211
  arrayBufferPromise.catch(() => { });
5084
- await fileEntry.getData(writer, entry, zipReader.readRanges, options);
5212
+ await fileEntry.getData(writer, entry, zipReader.readRanges,
5213
+ Object.assign({}, options, { preventClose: false }));
5085
5214
  return arrayBufferPromise;
5086
5215
  };
5087
5216
  offset = endOffset;
@@ -5162,48 +5291,101 @@
5162
5291
  await reader.readable.cancel();
5163
5292
  }
5164
5293
  }
5294
+
5295
+ [SYMBOL_ASYNC_DISPOSE]() {
5296
+ return this.close();
5297
+ }
5165
5298
  }
5166
5299
 
5167
5300
  class ZipReaderStream {
5168
5301
 
5169
5302
  constructor(options = {}) {
5170
- const { readable, writable } = new TransformStream();
5171
- const gen = new ZipReader(readable, options).getEntriesGenerator();
5303
+ let sourceController;
5304
+ const { readable, writable } = new TransformStream({
5305
+ start(controller) {
5306
+ sourceController = controller;
5307
+ }
5308
+ });
5309
+ const zipReader = new ZipReader(readable, options);
5310
+ const gen = zipReader.getEntriesGenerator();
5311
+ const pendingEntries = new Set();
5172
5312
  this.readable = new ReadableStream({
5173
5313
  async pull(controller) {
5174
5314
  const { done, value } = await gen.next();
5175
5315
  if (done)
5176
5316
  return controller.close();
5317
+ const entryStream = createEntryStream(value, pendingEntries);
5177
5318
  const chunk = {
5178
5319
  ...value,
5179
- readable: (function () {
5180
- const { readable, writable } = new TransformStream();
5181
- if (value.getData) {
5182
- getData();
5183
- return readable;
5184
- }
5185
-
5186
- async function getData() {
5187
- try {
5188
- await value.getData(writable);
5189
- } catch (error) {
5190
- try {
5191
- await writable.abort(error);
5192
- } catch {
5193
- // ignored
5194
- }
5195
- }
5196
- }
5197
- })()
5320
+ readable: entryStream.readable
5198
5321
  };
5199
5322
  delete chunk.getData;
5323
+ Object.defineProperties(chunk, {
5324
+ localDirectory: {
5325
+ get: () => value.localDirectory,
5326
+ enumerable: true
5327
+ },
5328
+ warnings: {
5329
+ get: () => value.warnings,
5330
+ enumerable: true
5331
+ }
5332
+ });
5200
5333
  controller.enqueue(chunk);
5334
+ },
5335
+ async cancel(reason) {
5336
+ const entryStreams = Array.from(pendingEntries);
5337
+ pendingEntries.clear();
5338
+ sourceController.error(reason);
5339
+ await Promise.allSettled(entryStreams.map(entryStream => entryStream.cancel(reason)));
5340
+ await Promise.allSettled([gen.return(), zipReader.close()]);
5201
5341
  }
5202
5342
  });
5203
5343
  this.writable = writable;
5204
5344
  }
5205
5345
  }
5206
5346
 
5347
+ function createEntryStream(entry, pendingEntries) {
5348
+ const { readable, writable } = new TransformStream();
5349
+ let dataReader;
5350
+ const entryStream = {
5351
+ cancel: async reason => {
5352
+ pendingEntries.delete(entryStream);
5353
+ await (dataReader ? dataReader.cancel(reason) : readable.cancel(reason));
5354
+ }
5355
+ };
5356
+ entryStream.readable = new ReadableStream({
5357
+ async pull(controller) {
5358
+ if (!dataReader) {
5359
+ dataReader = readable.getReader();
5360
+ pendingEntries.add(entryStream);
5361
+ getData();
5362
+ }
5363
+ const { done, value } = await dataReader.read();
5364
+ if (done) {
5365
+ controller.close();
5366
+ } else {
5367
+ controller.enqueue(value);
5368
+ }
5369
+ },
5370
+ cancel: reason => entryStream.cancel(reason)
5371
+ }, { highWaterMark: 0 });
5372
+ return entryStream;
5373
+
5374
+ async function getData() {
5375
+ try {
5376
+ await entry.getData(writable, { preventClose: false });
5377
+ } catch (error) {
5378
+ try {
5379
+ await writable.abort(error);
5380
+ } catch {
5381
+ // ignored
5382
+ }
5383
+ } finally {
5384
+ pendingEntries.delete(entryStream);
5385
+ }
5386
+ }
5387
+ }
5388
+
5207
5389
  async function isZipFile(reader, options = {}) {
5208
5390
  reader = new GenericReader(reader);
5209
5391
  await initStream(reader);
@@ -5263,7 +5445,9 @@
5263
5445
  const dataView = getDataView(dataArray);
5264
5446
  let password = getOptionValue$1(zipEntry, options, OPTION_PASSWORD);
5265
5447
  let rawPassword = getOptionValue$1(zipEntry, options, OPTION_RAW_PASSWORD);
5266
- const passThrough = getOptionValue$1(zipEntry, options, OPTION_PASS_THROUGH);
5448
+ const passThrough = checkPassThroughOption(getOptionValue$1(zipEntry, options, OPTION_PASS_THROUGH));
5449
+ const passThroughCompression = Boolean(passThrough);
5450
+ const passThroughEncryption = passThrough === true;
5267
5451
  checkPasswordOption(password, rawPassword);
5268
5452
  password = password && password.length && password;
5269
5453
  rawPassword = rawPassword && rawPassword.length && rawPassword;
@@ -5284,7 +5468,9 @@
5284
5468
  const checkLocalDirectoryOption = getOptionValue$1(zipEntry, options, OPTION_CHECK_LOCAL_DIRECTORY);
5285
5469
  const entryStrictness = getStrictness(options, zipEntry.options);
5286
5470
  const checkLocalDirectory = getCheckLocalDirectory(checkLocalDirectoryOption, entryStrictness);
5287
- const checkLocalFilename = getCheckLocalFilename(checkLocalDirectoryOption, entryStrictness);
5471
+ const checkLocalFilenameOption = getOptionValue$1(zipEntry, options, OPTION_CHECK_LOCAL_FILENAME);
5472
+ const checkLocalFilename = getCheckLocalFilename(
5473
+ checkLocalFilenameOption === UNDEFINED_VALUE ? checkLocalDirectoryOption : checkLocalFilenameOption, entryStrictness);
5288
5474
  let rawLocalFilename = EMPTY_UINT8_ARRAY;
5289
5475
  if (checkLocalFilename && (filenameLength || extraFieldLength)) {
5290
5476
  const trailingDataArray = await readUint8Array(reader, localHeaderOffset + HEADER_SIZE, filenameLength + extraFieldLength);
@@ -5315,16 +5501,17 @@
5315
5501
  if (gid !== UNDEFINED_VALUE && fileEntry.gid === UNDEFINED_VALUE) {
5316
5502
  fileEntry.gid = gid;
5317
5503
  }
5318
- const encrypted = zipEntry.encrypted && localDirectory.encrypted && !passThrough;
5504
+ const checkPasswordOnly = getOptionValue$1(zipEntry, options, OPTION_CHECK_PASSWORD_ONLY);
5505
+ const encrypted = zipEntry.encrypted && localDirectory.encrypted && (!passThroughEncryption || checkPasswordOnly);
5319
5506
  const zipCrypto = encrypted && !extraFieldAES;
5320
- if (!passThrough) {
5507
+ if (!passThroughEncryption) {
5321
5508
  fileEntry.zipCrypto = zipCrypto;
5322
5509
  }
5323
5510
  if (encrypted && (localDirectory.rawBitFlag & BITFLAG_STRONG_ENCRYPTION) == BITFLAG_STRONG_ENCRYPTION) {
5324
5511
  throw new Error(ERR_UNSUPPORTED_ENCRYPTION);
5325
5512
  }
5326
- const registeredCodec = passThrough ? UNDEFINED_VALUE : getRegisteredCodec(compressionMethod);
5327
- if (compressionMethod != COMPRESSION_METHOD_STORE && compressionMethod != COMPRESSION_METHOD_DEFLATE && compressionMethod != COMPRESSION_METHOD_DEFLATE_64 && !registeredCodec && !passThrough) {
5513
+ const registeredCodec = passThroughCompression ? UNDEFINED_VALUE : getRegisteredCodec(compressionMethod);
5514
+ if (compressionMethod != COMPRESSION_METHOD_STORE && compressionMethod != COMPRESSION_METHOD_DEFLATE && compressionMethod != COMPRESSION_METHOD_DEFLATE_64 && !registeredCodec && !passThroughCompression) {
5328
5515
  throw new Error(ERR_UNSUPPORTED_COMPRESSION);
5329
5516
  }
5330
5517
  if (encrypted) {
@@ -5340,15 +5527,17 @@
5340
5527
  const size = compressedSize;
5341
5528
  const readable = toCompatibleReadable(reader.createReadable({ offset: dataOffset, size }));
5342
5529
  const signal = checkSignalOption(getOptionValue$1(zipEntry, options, OPTION_SIGNAL));
5343
- const checkPasswordOnly = getOptionValue$1(zipEntry, options, OPTION_CHECK_PASSWORD_ONLY);
5530
+ throwIfAborted(signal);
5344
5531
  let checkOverlappingEntry = getOptionValue$1(zipEntry, options, OPTION_CHECK_OVERLAPPING_ENTRY);
5345
5532
  const checkOverlappingEntryOnly = getOptionValue$1(zipEntry, options, OPTION_CHECK_OVERLAPPING_ENTRY_ONLY);
5346
5533
  if (checkOverlappingEntryOnly) {
5347
5534
  checkOverlappingEntry = true;
5348
5535
  }
5349
5536
  const { onstart, onprogress, onend } = options;
5350
- const compressed = compressionMethod != COMPRESSION_METHOD_STORE && !passThrough;
5351
- const outputSize = passThrough ? compressedSize : uncompressedSize;
5537
+ const compressed = compressionMethod != COMPRESSION_METHOD_STORE && !passThroughCompression;
5538
+ const outputSize = passThroughCompression ?
5539
+ compressedSize - getEncryptionOverhead(encrypted, zipCrypto, extraFieldAES && extraFieldAES.strength) :
5540
+ uncompressedSize;
5352
5541
  const deflate64 = compressionMethod == COMPRESSION_METHOD_DEFLATE_64;
5353
5542
  let useCompressionStream = getOptionValue$1(zipEntry, options, OPTION_USE_COMPRESSION_STREAM);
5354
5543
  if (deflate64) {
@@ -5357,7 +5546,7 @@
5357
5546
  const checkCrc32Option = getOptionValue$1(zipEntry, options, OPTION_CHECK_CRC32);
5358
5547
  const checkCrc32 = (checkCrc32Option === UNDEFINED_VALUE ?
5359
5548
  getOptionValue$1(zipEntry, options, OPTION_CHECK_SIGNATURE) :
5360
- checkCrc32Option) && !passThrough &&
5549
+ checkCrc32Option) && !passThroughCompression &&
5361
5550
  (!encrypted || zipCrypto || (extraFieldAES && extraFieldAES.vendorVersion == VENDOR_VERSION_AE_1$1));
5362
5551
  const workerOptions = {
5363
5552
  options: {
@@ -5411,10 +5600,10 @@
5411
5600
  await initStream(writer, getDecodableOutputSize(outputSize, compressedSize, compressed));
5412
5601
  ({ writable } = writer);
5413
5602
  const { outputSize: writtenSize } = await runWorker({ readable, writable }, workerOptions);
5414
- writer.size += writtenSize;
5415
5603
  if (writtenSize != outputSize) {
5416
- throw new Error(ERR_INVALID_UNCOMPRESSED_SIZE);
5604
+ throw Object.assign(new Error(ERR_INVALID_UNCOMPRESSED_SIZE), { outputSize: writtenSize });
5417
5605
  }
5606
+ writer.size += writtenSize;
5418
5607
  }
5419
5608
  } catch (error) {
5420
5609
  if (error.outputSize !== UNDEFINED_VALUE) {
@@ -6080,7 +6269,7 @@
6080
6269
  if (checkLocalFilename && !maskedLocalDirectory &&
6081
6270
  (rawLocalFilename.length != rawFilename.length ||
6082
6271
  rawLocalFilename.some((byteValue, indexByte) => byteValue != rawFilename[indexByte]))) {
6083
- reportAmbiguity(reject, warnings, "mismatched local file header (filename)");
6272
+ reportAmbiguity(reject, warnings, WARNING_MISMATCHED_LOCAL_FILE_HEADER_FILENAME);
6084
6273
  }
6085
6274
  if ((localDirectory.rawBitFlag & BITFLAG_AMBIGUITY_MASK) != (zipEntry.rawBitFlag & BITFLAG_AMBIGUITY_MASK)) {
6086
6275
  reportAmbiguity(reject, warnings, WARNING_MISMATCHED_LOCAL_FILE_HEADER_BIT_FLAG);
@@ -6105,16 +6294,6 @@
6105
6294
  }
6106
6295
  }
6107
6296
 
6108
- function addWarning(warnings, reason, filename) {
6109
- if (!warnings.some(warning => warning.reason == reason)) {
6110
- const warning = { reason };
6111
- if (filename !== UNDEFINED_VALUE) {
6112
- warning.filename = filename;
6113
- }
6114
- warnings.push(warning);
6115
- }
6116
- }
6117
-
6118
6297
  function throwAmbiguousArchive(reason) {
6119
6298
  const error = new Error(ERR_AMBIGUOUS_ARCHIVE);
6120
6299
  error.reason = reason;
@@ -6194,7 +6373,9 @@
6194
6373
  WARNING_MISMATCHED_LOCAL_FILE_HEADER_BIT_FLAG: WARNING_MISMATCHED_LOCAL_FILE_HEADER_BIT_FLAG,
6195
6374
  WARNING_MISMATCHED_LOCAL_FILE_HEADER_COMPRESSION_METHOD: WARNING_MISMATCHED_LOCAL_FILE_HEADER_COMPRESSION_METHOD,
6196
6375
  WARNING_MISMATCHED_LOCAL_FILE_HEADER_CRC32_OR_SIZES: WARNING_MISMATCHED_LOCAL_FILE_HEADER_CRC32_OR_SIZES,
6376
+ WARNING_MISMATCHED_LOCAL_FILE_HEADER_FILENAME: WARNING_MISMATCHED_LOCAL_FILE_HEADER_FILENAME,
6197
6377
  WARNING_MISMATCHED_ZIP64_END_OF_CENTRAL_DIRECTORY: WARNING_MISMATCHED_ZIP64_END_OF_CENTRAL_DIRECTORY,
6378
+ WARNING_MULTIPLE_END_OF_CENTRAL_DIRECTORY: WARNING_MULTIPLE_END_OF_CENTRAL_DIRECTORY,
6198
6379
  WARNING_PREPENDED_CENTRAL_DIRECTORY: WARNING_PREPENDED_CENTRAL_DIRECTORY,
6199
6380
  WARNING_PREPENDED_DATA: WARNING_PREPENDED_DATA,
6200
6381
  WARNING_TRAILING_CENTRAL_DIRECTORY_DATA: WARNING_TRAILING_CENTRAL_DIRECTORY_DATA,
@@ -6247,7 +6428,7 @@
6247
6428
  const ERR_INVALID_ENCRYPTION_STRENGTH = "The strength must equal 1, 2, or 3";
6248
6429
  const ERR_UNSUPPORTED_ENCRYPTION_USDZ = "Encryption is not supported in USDZ files";
6249
6430
  const ERR_UNSUPPORTED_SPLIT_USDZ = "Split zip files are not supported in USDZ files";
6250
- const ERR_UNSUPPORTED_ENCRYPTION_PASS_THROUGH = "Encryption is not supported when the 'passThrough' option is set";
6431
+ const ERR_UNSUPPORTED_ENCRYPTION_PASS_THROUGH = "Encryption is not supported when the 'passThrough' option is set to true (use 'compressed' instead)";
6251
6432
  const ERR_INVALID_EXTRAFIELD = "Invalid extra field (must be a Map)";
6252
6433
  const ERR_INVALID_EXTRAFIELD_TYPE = "Invalid extra field type (must be integer 0..65535)";
6253
6434
  const ERR_INVALID_EXTRAFIELD_DATA_TYPE = "Invalid extra field data (must be a Uint8Array)";
@@ -6259,6 +6440,7 @@
6259
6440
  const ERR_UNSUPPORTED_FORMAT = "Zip64 is not supported (set the 'zip64' option to 'true')";
6260
6441
  const ERR_UNDEFINED_UNCOMPRESSED_SIZE = "Undefined uncompressed size";
6261
6442
  const ERR_UNDEFINED_COMPRESSION_METHOD = "Undefined compression method";
6443
+ const ERR_UNDEFINED_CRC32 = "Undefined CRC32";
6262
6444
  const ERR_UNDETERMINED_SIZE = "Undetermined size";
6263
6445
  const ERR_UNDEFINED_READER = "Undefined reader";
6264
6446
  const ERR_INVALID_READER = "Invalid reader (must be a Reader instance, a ReadableStream instance, or an object with a 'readable' property)";
@@ -6272,14 +6454,21 @@
6272
6454
  const ERR_INVALID_MSDOS_DATA = "Invalid msdosAttributes (must be an object with boolean flags)";
6273
6455
  const ERR_INVALID_LEVEL = "Invalid level (must be integer 0..9)";
6274
6456
  const ERR_INVALID_SIGNATURE_DATA = "Signature data exceeds 64KB";
6457
+ const ERR_INVALID_ENTRY = "Invalid entry option (must be an entry returned by ZipReader#getEntries())";
6458
+ const ERR_ZIP_CRYPTO_LAST_MOD_DATE = "The last modification date of an entry encrypted with ZipCrypto cannot be changed when passThrough is set";
6459
+ const WARNING_COMPRESSION_UNAVAILABLE = "compression unavailable";
6460
+ const WARNING_CLAMPED_LAST_MODIFICATION_DATE = "clamped last modification date";
6275
6461
 
6276
6462
  const EXTRAFIELD_DATA_AES = new Uint8Array([0x07, 0x00, 0x02, 0x00, 0x41, 0x45, 0x03, 0x00, 0x00]);
6277
6463
  const EXTRAFIELD_OFFSET_AES_VENDOR_VERSION = 4;
6278
6464
  const EXTRAFIELD_OFFSET_AES_COMPRESSION_METHOD = 9;
6279
6465
  const EXTRAFIELD_USDZ_MAX_LENGTH = 67;
6466
+ const MIN_PRINTABLE_ASCII_CHARACTER_CODE = 0x20;
6467
+ const MAX_PRINTABLE_ASCII_CHARACTER_CODE = 0x7e;
6280
6468
  const VENDOR_VERSION_AE_1 = 1;
6281
6469
  const INFOZIP_EXTRA_FIELD_TYPE = "infozip";
6282
6470
  const UNIX_EXTRA_FIELD_TYPE = "unix";
6471
+ const LEVEL_BY_BITFLAG_LEVEL = [8, 9, 5, 3];
6283
6472
  const MAX_LEVEL = 9;
6284
6473
 
6285
6474
  let workers = 0;
@@ -6306,9 +6495,11 @@
6306
6495
  initialOffset: options[OPTION_OFFSET] === UNDEFINED_VALUE ? 0 : options[OPTION_OFFSET] - (writer.size || writer.writable.size || 0),
6307
6496
  pendingAddFileCalls: new Set(),
6308
6497
  pendingErrors: [],
6498
+ warnings: [],
6309
6499
  bufferedWrites: 0,
6310
6500
  directWrites: 0,
6311
- lastFileEntry: UNDEFINED_VALUE
6501
+ lastFileEntry: UNDEFINED_VALUE,
6502
+ archiveClosed: false
6312
6503
  });
6313
6504
  }
6314
6505
 
@@ -6473,6 +6664,9 @@
6473
6664
  const zipWriter = this;
6474
6665
  const { pendingAddFileCalls, writer } = this;
6475
6666
  const { writable } = writer;
6667
+ if (zipWriter.archiveClosed) {
6668
+ return getWriterData(writer);
6669
+ }
6476
6670
  if (!(comment instanceof Uint8Array)) {
6477
6671
  throw new Error(ERR_INVALID_COMMENT_TYPE);
6478
6672
  }
@@ -6496,11 +6690,16 @@
6496
6690
  throw error;
6497
6691
  }
6498
6692
  await closeFile(zipWriter, comment, options);
6693
+ zipWriter.archiveClosed = true;
6499
6694
  const preventClose = !ownsWritable(writer) && getOptionValue(zipWriter, options, OPTION_PREVENT_CLOSE);
6500
6695
  if (!preventClose) {
6501
6696
  await writable.getWriter().close();
6502
6697
  }
6503
- return writer.getData ? writer.getData() : writable;
6698
+ return getWriterData(writer);
6699
+ }
6700
+
6701
+ [SYMBOL_ASYNC_DISPOSE]() {
6702
+ return this.close();
6504
6703
  }
6505
6704
  }
6506
6705
 
@@ -6579,6 +6778,10 @@
6579
6778
  }
6580
6779
  }
6581
6780
 
6781
+ function getWriterData(writer) {
6782
+ return writer.getData ? writer.getData() : writer.writable;
6783
+ }
6784
+
6582
6785
  function watchPromiseError(zipWriter, promise) {
6583
6786
  const watchedPromise = new WatchedPromise((resolve, reject) => Promise.prototype.then.call(promise, resolve, reject));
6584
6787
  const watcher = {};
@@ -6597,6 +6800,14 @@
6597
6800
 
6598
6801
  async function addFileEntry(zipWriter, name, reader, options) {
6599
6802
  options = Object.assign({}, options);
6803
+ const entry = options[OPTION_ENTRY];
6804
+ if (entry !== UNDEFINED_VALUE) {
6805
+ const { entryOptions, passThroughOptions } = getSourceEntryOptions(entry,
6806
+ checkPassThroughOption(getOptionValue(zipWriter, options, OPTION_PASS_THROUGH)),
6807
+ getOptionValue(zipWriter, options, PROPERTY_NAME_LAST_MODIFICATION_DATE));
6808
+ delete options[OPTION_ENTRY];
6809
+ options = Object.assign(entryOptions, passThroughOptions, options);
6810
+ }
6600
6811
  if (getOptionValue(zipWriter, options, PROPERTY_NAME_DIRECTORY) && !name.endsWith(DIRECTORY_SIGNATURE)) {
6601
6812
  name += DIRECTORY_SIGNATURE;
6602
6813
  }
@@ -6661,21 +6872,33 @@
6661
6872
  try {
6662
6873
  const { resolvedOptions } = metadataInfo;
6663
6874
  if (resolvedOptions.level != 0 && resolvedOptions.compressionMethod === UNDEFINED_VALUE &&
6664
- !resolvedOptions.passThrough && !(await supportsDeflate(getConfiguration()))) {
6875
+ !resolvedOptions.passThroughCompression && !(await supportsDeflate(getConfiguration()))) {
6665
6876
  resolvedOptions.level = 0;
6877
+ addWarning(zipWriter.warnings, WARNING_COMPRESSION_UNAVAILABLE, name);
6666
6878
  }
6667
6879
  const sizesInfo = await resolveSizes(zipWriter, reader, metadataInfo, options);
6668
6880
  ({ reader } = sizesInfo);
6669
6881
  const diskOffset = getDiskOffset(zipWriter.writer);
6670
6882
  const diskNumber = getDiskNumber(zipWriter.writer);
6883
+ let crc32 = options.crc32 === UNDEFINED_VALUE ? options[PROPERTY_NAME_SIGNATURE] : options.crc32;
6884
+ const storesAE2 = sizesInfo.resolvedOptions.encrypted && !resolvedOptions.zipCrypto;
6885
+ if (resolvedOptions.passThroughCompression && !resolvedOptions.passThroughEncryption && storesAE2) {
6886
+ crc32 = UNDEFINED_VALUE;
6887
+ }
6888
+ if (resolvedOptions.passThroughCompression && reader && !storesAE2 && crc32 === UNDEFINED_VALUE) {
6889
+ throw new Error(ERR_UNDEFINED_CRC32);
6890
+ }
6671
6891
  options = Object.assign({}, options, attributesInfo.resolvedOptions, metadataInfo.resolvedOptions, sizesInfo.resolvedOptions, {
6672
6892
  signature: options[PROPERTY_NAME_SIGNATURE],
6673
- crc32: options.crc32 === UNDEFINED_VALUE ? options[PROPERTY_NAME_SIGNATURE] : options.crc32,
6893
+ crc32,
6674
6894
  offset: zipWriter.offset - diskOffset,
6675
6895
  diskNumberStart: diskNumber,
6676
6896
  [OPTION_USDZ]: zipWriter.options[OPTION_USDZ]
6677
6897
  });
6678
6898
  const headerInfo = getHeaderInfo(options);
6899
+ if (headerInfo.lastModDateClamped) {
6900
+ addWarning(zipWriter.warnings, WARNING_CLAMPED_LAST_MODIFICATION_DATE, name);
6901
+ }
6679
6902
  const dataDescriptorInfo = getDataDescriptorInfo(options);
6680
6903
  const metadataSize = getLength(headerInfo.localHeaderArray, dataDescriptorInfo.dataDescriptorArray);
6681
6904
  fileEntry = await getFileEntry(zipWriter, name, reader, {
@@ -6702,6 +6925,95 @@
6702
6925
  return new Entry(fileEntry);
6703
6926
  }
6704
6927
 
6928
+ function getSourceEntryOptions(entry, passThrough, lastModDateOverride) {
6929
+ if (entry === null || typeof entry != OBJECT_TYPE || Array.isArray(entry)) {
6930
+ throw new Error(ERR_INVALID_ENTRY);
6931
+ }
6932
+ const {
6933
+ externalFileAttributes,
6934
+ versionMadeBy,
6935
+ comment,
6936
+ lastModDate,
6937
+ rawLastModDate,
6938
+ creationDate,
6939
+ lastAccessDate,
6940
+ uncompressedSize,
6941
+ encrypted,
6942
+ zipCrypto,
6943
+ crc32,
6944
+ compressionMethod,
6945
+ extraFieldAES,
6946
+ extraFieldUnix,
6947
+ internalFileAttributes,
6948
+ extraField,
6949
+ bitFlag,
6950
+ directory,
6951
+ uid,
6952
+ gid
6953
+ } = entry;
6954
+ const entryOptions = {
6955
+ externalFileAttributes,
6956
+ versionMadeBy,
6957
+ comment,
6958
+ lastModDate,
6959
+ creationDate,
6960
+ lastAccessDate,
6961
+ internalFileAttributes,
6962
+ directory
6963
+ };
6964
+ if (bitFlag && bitFlag.languageEncodingFlag) {
6965
+ entryOptions[OPTION_USE_UNICODE_FILE_NAMES] = true;
6966
+ }
6967
+ const userExtraField = getUserExtraField(extraField);
6968
+ if (userExtraField) {
6969
+ entryOptions[PROPERTY_NAME_EXTRA_FIELD] = userExtraField;
6970
+ }
6971
+ if (uid !== UNDEFINED_VALUE || gid !== UNDEFINED_VALUE) {
6972
+ Object.assign(entryOptions, {
6973
+ uid,
6974
+ gid,
6975
+ unixExtraFieldType: extraFieldUnix ? UNIX_EXTRA_FIELD_TYPE : INFOZIP_EXTRA_FIELD_TYPE
6976
+ });
6977
+ }
6978
+ const passThroughOptions = {};
6979
+ if (passThrough && !directory) {
6980
+ Object.assign(passThroughOptions, {
6981
+ uncompressedSize,
6982
+ crc32,
6983
+ compressionMethod
6984
+ });
6985
+ if (passThrough !== PASS_THROUGH_COMPRESSED) {
6986
+ Object.assign(passThroughOptions, {
6987
+ encrypted,
6988
+ zipCrypto,
6989
+ encryptionStrength: extraFieldAES ? extraFieldAES.strength : UNDEFINED_VALUE
6990
+ });
6991
+ }
6992
+ if (bitFlag) {
6993
+ passThroughOptions.dataDescriptor = bitFlag.dataDescriptor;
6994
+ passThroughOptions[OPTION_LEVEL] = LEVEL_BY_BITFLAG_LEVEL[bitFlag.level];
6995
+ }
6996
+ if (lastModDateOverride === UNDEFINED_VALUE) {
6997
+ passThroughOptions.rawLastModDate = rawLastModDate;
6998
+ } else if (passThrough !== PASS_THROUGH_COMPRESSED && zipCrypto && (!bitFlag || bitFlag.dataDescriptor) &&
6999
+ lastModDateOverride instanceof Date &&
7000
+ getDosTimeHighByte(lastModDateOverride) != ((rawLastModDate >>> 8) & MAX_8_BITS)) {
7001
+ throw new Error(ERR_ZIP_CRYPTO_LAST_MOD_DATE);
7002
+ }
7003
+ }
7004
+ return { entryOptions, passThroughOptions };
7005
+ }
7006
+
7007
+ function getDosTimeHighByte(lastModDate) {
7008
+ let dosLastModDate = new Date(Math.ceil(Math.floor(lastModDate.getTime() / 1000) / 2) * 2000);
7009
+ if (dosLastModDate < MIN_DATE) {
7010
+ dosLastModDate = MIN_DATE;
7011
+ } else if (dosLastModDate > MAX_DATE) {
7012
+ dosLastModDate = MAX_DATE;
7013
+ }
7014
+ return ((dosLastModDate.getHours() << 3) | (dosLastModDate.getMinutes() >> 3)) & MAX_8_BITS;
7015
+ }
7016
+
6705
7017
  function resolveAttributes(zipWriter, name, options) {
6706
7018
  let msDosCompatible = getOptionValue(zipWriter, options, PROPERTY_NAME_MS_DOS_COMPATIBLE);
6707
7019
  let versionMadeBy = getOptionValue(zipWriter, options, PROPERTY_NAME_VERSION_MADE_BY, msDosCompatible ? VERSION_MADE_BY_MSDOS : VERSION_MADE_BY_UNIX);
@@ -6855,7 +7167,9 @@
6855
7167
  const lastAccessDate = getDateOptionValue(zipWriter, options, PROPERTY_NAME_LAST_ACCESS_DATE);
6856
7168
  const creationDate = getDateOptionValue(zipWriter, options, PROPERTY_NAME_CREATION_DATE);
6857
7169
  const internalFileAttributes = getOptionValue(zipWriter, options, PROPERTY_NAME_INTERNAL_FILE_ATTRIBUTES, 0);
6858
- const passThrough = getOptionValue(zipWriter, options, OPTION_PASS_THROUGH);
7170
+ const passThrough = checkPassThroughOption(getOptionValue(zipWriter, options, OPTION_PASS_THROUGH));
7171
+ const passThroughCompression = Boolean(passThrough);
7172
+ const passThroughEncryption = passThrough === true;
6859
7173
  const password = getOptionValue(zipWriter, options, OPTION_PASSWORD);
6860
7174
  const rawPassword = getOptionValue(zipWriter, options, OPTION_RAW_PASSWORD);
6861
7175
  checkPasswordOption(password, rawPassword);
@@ -6870,10 +7184,12 @@
6870
7184
  const createTempStream = getFunctionOptionValue(zipWriter, options, OPTION_CREATE_TEMP_STREAM);
6871
7185
  const dataDescriptorSignature = getOptionValue(zipWriter, options, OPTION_DATA_DESCRIPTOR_SIGNATURE, true);
6872
7186
  const signal = checkSignalOption(getOptionValue(zipWriter, options, OPTION_SIGNAL));
6873
- const useUnicodeFileNames = getOptionValue(zipWriter, options, OPTION_USE_UNICODE_FILE_NAMES, true);
7187
+ throwIfAborted(signal);
7188
+ const useUnicodeFileNames = getOptionValue(zipWriter, options, OPTION_USE_UNICODE_FILE_NAMES,
7189
+ !isPrintableASCIIText(rawFilename) || !isPrintableASCIIText(rawComment));
6874
7190
  const compressionMethod = getOptionValue(zipWriter, options, PROPERTY_NAME_COMPRESSION_METHOD);
6875
- const registeredCodec = passThrough || compressionMethod === UNDEFINED_VALUE ? UNDEFINED_VALUE : getRegisteredCodec(compressionMethod);
6876
- if (!passThrough && compressionMethod !== UNDEFINED_VALUE &&
7191
+ const registeredCodec = passThroughCompression || compressionMethod === UNDEFINED_VALUE ? UNDEFINED_VALUE : getRegisteredCodec(compressionMethod);
7192
+ if (!passThroughCompression && compressionMethod !== UNDEFINED_VALUE &&
6877
7193
  compressionMethod !== COMPRESSION_METHOD_STORE && compressionMethod !== COMPRESSION_METHOD_DEFLATE && !registeredCodec) {
6878
7194
  throw new Error(ERR_UNSUPPORTED_COMPRESSION);
6879
7195
  }
@@ -6887,15 +7203,15 @@
6887
7203
  level = 0;
6888
7204
  }
6889
7205
  }
6890
- if (passThrough) {
6891
- level = UNDEFINED_VALUE;
7206
+ if (passThroughCompression) {
7207
+ level = toNumber(options[OPTION_LEVEL]);
6892
7208
  }
6893
7209
  let useCompressionStream = getOptionValue(zipWriter, options, OPTION_USE_COMPRESSION_STREAM);
6894
7210
  let dataDescriptor = getOptionValue(zipWriter, options, OPTION_DATA_DESCRIPTOR);
6895
7211
  if (bufferedWrite && dataDescriptor === UNDEFINED_VALUE) {
6896
7212
  dataDescriptor = false;
6897
7213
  }
6898
- if (dataDescriptor === UNDEFINED_VALUE || (zipCrypto && !passThrough)) {
7214
+ if (dataDescriptor === UNDEFINED_VALUE || (zipCrypto && !passThroughEncryption)) {
6899
7215
  dataDescriptor = true;
6900
7216
  }
6901
7217
  if (level !== UNDEFINED_VALUE && level != 6) {
@@ -6919,7 +7235,8 @@
6919
7235
  lastAccessDate,
6920
7236
  creationDate,
6921
7237
  internalFileAttributes,
6922
- passThrough,
7238
+ passThroughCompression,
7239
+ passThroughEncryption,
6923
7240
  password,
6924
7241
  rawPassword,
6925
7242
  encryptionStrength,
@@ -6980,7 +7297,7 @@
6980
7297
  }
6981
7298
 
6982
7299
  async function resolveSizes(zipWriter, reader, { resolvedOptions: metadata }, options) {
6983
- if (metadata.passThrough && !reader && !getOptionValue(zipWriter, options, PROPERTY_NAME_DIRECTORY)) {
7300
+ if (metadata.passThroughCompression && !reader && !getOptionValue(zipWriter, options, PROPERTY_NAME_DIRECTORY)) {
6984
7301
  throw new Error(ERR_UNDEFINED_READER);
6985
7302
  }
6986
7303
  let contentSize;
@@ -6996,12 +7313,12 @@
6996
7313
  }
6997
7314
 
6998
7315
  function resolveEntrySizes(zipWriter, hasContent, contentSize, metadata, options) {
6999
- const { passThrough, zipCrypto, password, rawPassword, encryptionStrength } = metadata;
7316
+ const { passThroughCompression, passThroughEncryption, zipCrypto, password, rawPassword, encryptionStrength } = metadata;
7000
7317
  let { dataDescriptor, zip64, level, compressionMethod } = metadata;
7001
7318
  let maximumCompressedSize = 0;
7002
7319
  let uncompressedSize = 0;
7003
7320
  let unknownSize = false;
7004
- if (passThrough && hasContent) {
7321
+ if (passThroughCompression && hasContent) {
7005
7322
  uncompressedSize = options[PROPERTY_NAME_UNCOMPRESSED_SIZE];
7006
7323
  if (uncompressedSize === UNDEFINED_VALUE) {
7007
7324
  throw new Error(ERR_UNDEFINED_UNCOMPRESSED_SIZE);
@@ -7012,17 +7329,17 @@
7012
7329
  }
7013
7330
  const zip64Enabled = zip64 === true;
7014
7331
  const encrypted = getOptionValue(zipWriter, options, PROPERTY_NAME_ENCRYPTED);
7015
- if (hasContent && passThrough && !encrypted && getLength(password, rawPassword)) {
7332
+ if (hasContent && passThroughEncryption && !encrypted && getLength(password, rawPassword)) {
7016
7333
  throw new Error(ERR_UNSUPPORTED_ENCRYPTION_PASS_THROUGH);
7017
7334
  }
7018
- const encryptedEntry = hasContent && (Boolean((password && getLength(password)) || (rawPassword && getLength(rawPassword))) || (passThrough && encrypted));
7335
+ const encryptedEntry = hasContent && (Boolean((password && getLength(password)) || (rawPassword && getLength(rawPassword))) || (passThroughEncryption && encrypted));
7019
7336
  if (!hasContent) {
7020
7337
  level = 0;
7021
7338
  compressionMethod = COMPRESSION_METHOD_STORE;
7022
7339
  }
7023
- const encryptionOverhead = encryptedEntry ? (zipCrypto ? 12 : 16 + encryptionStrength * 4) : 0;
7340
+ const encryptionOverhead = getEncryptionOverhead(encryptedEntry, zipCrypto, encryptionStrength);
7024
7341
  if (hasContent) {
7025
- if (!passThrough) {
7342
+ if (!passThroughCompression) {
7026
7343
  if (contentSize === UNDEFINED_VALUE) {
7027
7344
  dataDescriptor = true;
7028
7345
  if (zip64 || zip64 === UNDEFINED_VALUE) {
@@ -7035,10 +7352,12 @@
7035
7352
  }
7036
7353
  } else {
7037
7354
  options.uncompressedSize = uncompressedSize;
7038
- maximumCompressedSize = contentSize === UNDEFINED_VALUE ? getMaximumCompressedSize(uncompressedSize) + encryptionOverhead : contentSize;
7355
+ maximumCompressedSize = contentSize === UNDEFINED_VALUE ?
7356
+ getMaximumCompressedSize(uncompressedSize) + encryptionOverhead :
7357
+ contentSize + (passThroughEncryption ? 0 : encryptionOverhead);
7039
7358
  }
7040
7359
  }
7041
- const emptyEntry = !encryptedEntry && (!hasContent || (contentSize === 0 && !passThrough)) && !isCompressed(compressionMethod, level);
7360
+ const emptyEntry = !encryptedEntry && (!hasContent || (contentSize === 0 && !passThroughCompression)) && !isCompressed(compressionMethod, level);
7042
7361
  if (emptyEntry && !zipCrypto && getOptionValue(zipWriter, options, OPTION_DATA_DESCRIPTOR) === UNDEFINED_VALUE) {
7043
7362
  dataDescriptor = false;
7044
7363
  }
@@ -7245,6 +7564,7 @@
7245
7564
  localExtraFieldZip64Length,
7246
7565
  rawExtraFieldExtendedTimestamp,
7247
7566
  extraFieldExtendedTimestampFlag,
7567
+ extraFieldExtendedTimestampTime,
7248
7568
  rawExtraFieldNTFS,
7249
7569
  rawExtraFieldUnix,
7250
7570
  rawExtraFieldAES,
@@ -7257,6 +7577,7 @@
7257
7577
  password,
7258
7578
  rawPassword,
7259
7579
  level,
7580
+ useUnicodeFileNames,
7260
7581
  zip64,
7261
7582
  zip64Enabled,
7262
7583
  zip64UncompressedSize,
@@ -7291,7 +7612,8 @@
7291
7612
  msdosAttributesRaw,
7292
7613
  msdosAttributes,
7293
7614
  useCompressionStream,
7294
- passThrough,
7615
+ passThroughCompression,
7616
+ passThroughEncryption,
7295
7617
  format,
7296
7618
  codecURI
7297
7619
  } = options;
@@ -7302,9 +7624,9 @@
7302
7624
  zip64Enabled,
7303
7625
  directory: Boolean(directory),
7304
7626
  executable: Boolean(executable),
7305
- filenameUTF8: true,
7627
+ filenameUTF8: Boolean(useUnicodeFileNames),
7306
7628
  rawFilename,
7307
- commentUTF8: true,
7629
+ commentUTF8: Boolean(useUnicodeFileNames),
7308
7630
  rawComment,
7309
7631
  rawExtraFieldZip64,
7310
7632
  localExtraFieldZip64Length,
@@ -7335,7 +7657,7 @@
7335
7657
  uncompressedSize
7336
7658
  } = options;
7337
7659
  let compressedSize = 0;
7338
- if (!passThrough) {
7660
+ if (!passThroughCompression) {
7339
7661
  uncompressedSize = 0;
7340
7662
  }
7341
7663
  const { writable } = writer;
@@ -7352,9 +7674,9 @@
7352
7674
  encryptionStrength,
7353
7675
  zipCrypto: encrypted && zipCrypto,
7354
7676
  passwordVerification: encrypted && zipCrypto && (rawLastModDate >> 8) & MAX_8_BITS,
7355
- computeCrc32: !passThrough,
7356
- compressed: compressed && !passThrough,
7357
- encrypted: encrypted && !passThrough,
7677
+ computeCrc32: !passThroughCompression,
7678
+ compressed: compressed && !passThroughCompression,
7679
+ encrypted: encrypted && !passThroughEncryption,
7358
7680
  useWebWorkers,
7359
7681
  useCompressionStream,
7360
7682
  transferStreams,
@@ -7369,7 +7691,7 @@
7369
7691
  const result = await runWorker({ readable, writable }, workerOptions);
7370
7692
  compressedSize = result.outputSize;
7371
7693
  writer.size += compressedSize;
7372
- if (!passThrough) {
7694
+ if (!passThroughCompression) {
7373
7695
  uncompressedSize = result.inputSize;
7374
7696
  if (!encrypted || zipCrypto) {
7375
7697
  crc32 = result.crc32;
@@ -7412,8 +7734,9 @@
7412
7734
  headerArray,
7413
7735
  headerView,
7414
7736
  signature: crc32,
7415
- crc32: encrypted && !zipCrypto && !passThrough ? UNDEFINED_VALUE : crc32,
7737
+ crc32: encrypted && !zipCrypto && !passThroughCompression ? UNDEFINED_VALUE : crc32,
7416
7738
  extraFieldExtendedTimestampFlag,
7739
+ extraFieldExtendedTimestampTime,
7417
7740
  zip64UncompressedSize,
7418
7741
  zip64CompressedSize
7419
7742
  });
@@ -7438,7 +7761,7 @@
7438
7761
  encryptionStrength,
7439
7762
  extendedTimestamp,
7440
7763
  ntfsTimestamp,
7441
- passThrough,
7764
+ passThroughCompression,
7442
7765
  encrypted,
7443
7766
  zip64UncompressedSize,
7444
7767
  zip64CompressedSize,
@@ -7449,7 +7772,7 @@
7449
7772
  let { version, compressionMethod } = options;
7450
7773
  const compressed = !directory && isCompressed(compressionMethod, level);
7451
7774
  let rawLocalExtraFieldZip64;
7452
- const uncompressedFile = passThrough || !compressed;
7775
+ const uncompressedFile = passThroughCompression || !compressed;
7453
7776
  const zip64ExtraFieldComplete = zip64 && (options.bufferedWrite || !dataDescriptor || ((!zip64UncompressedSize && !zip64CompressedSize) || (uncompressedFile && !unknownSize)));
7454
7777
  const writeLocalExtraFieldZip64 = zip64ExtraFieldComplete || (zip64 && dataDescriptor && (zip64UncompressedSize || zip64CompressedSize));
7455
7778
  if (zip64 && (zip64UncompressedSize || zip64CompressedSize)) {
@@ -7461,8 +7784,8 @@
7461
7784
  if (zip64ExtraFieldComplete) {
7462
7785
  extraFieldZip64.writeUint64(uncompressedSize);
7463
7786
  if (uncompressedFile) {
7464
- const encryptionOverhead = encrypted ? (zipCrypto ? 12 : 16 + encryptionStrength * 4) : 0;
7465
- extraFieldZip64.writeUint64(passThrough ? 0 : uncompressedSize + encryptionOverhead);
7787
+ const encryptionOverhead = getEncryptionOverhead(encrypted, zipCrypto, encryptionStrength);
7788
+ extraFieldZip64.writeUint64(passThroughCompression ? 0 : uncompressedSize + encryptionOverhead);
7466
7789
  }
7467
7790
  }
7468
7791
  } else {
@@ -7481,6 +7804,7 @@
7481
7804
  let rawExtraFieldNTFS;
7482
7805
  let rawExtraFieldExtendedTimestamp;
7483
7806
  let extraFieldExtendedTimestampFlag;
7807
+ let extraFieldExtendedTimestampTime;
7484
7808
  if (extendedTimestamp) {
7485
7809
  const lastModTimeUnix = getTimeUnix(lastModDate);
7486
7810
  const lastModTimeUnixInRange = inUnixTimeRange(lastModTimeUnix);
@@ -7488,6 +7812,7 @@
7488
7812
  const extraFieldTimestampLength = 9 + (lastAccessDate ? 4 : 0) + (creationDate ? 4 : 0);
7489
7813
  const extraFieldTimestamp = createRecordWriter(extraFieldTimestampLength);
7490
7814
  extraFieldExtendedTimestampFlag = 0x1 + (lastAccessDate ? 0x2 : 0) + (creationDate ? 0x4 : 0);
7815
+ extraFieldExtendedTimestampTime = lastModTimeUnix;
7491
7816
  extraFieldTimestamp.writeUint16(EXTRAFIELD_TYPE_EXTENDED_TIMESTAMP);
7492
7817
  extraFieldTimestamp.writeUint16(extraFieldTimestampLength - 4);
7493
7818
  extraFieldTimestamp.writeUint8(extraFieldExtendedTimestampFlag);
@@ -7571,7 +7896,7 @@
7571
7896
  }
7572
7897
  if (encrypted && !zipCrypto) {
7573
7898
  version = version > VERSION_AES ? version : VERSION_AES;
7574
- if (passThrough && crc32 !== UNDEFINED_VALUE) {
7899
+ if (passThroughCompression && crc32 !== UNDEFINED_VALUE) {
7575
7900
  rawExtraFieldAES[EXTRAFIELD_OFFSET_AES_VENDOR_VERSION] = VENDOR_VERSION_AE_1;
7576
7901
  }
7577
7902
  setUint16(getDataView(rawExtraFieldAES), EXTRAFIELD_OFFSET_AES_COMPRESSION_METHOD, compressionMethod);
@@ -7633,12 +7958,14 @@
7633
7958
  headerArray,
7634
7959
  headerView,
7635
7960
  lastModDate: storedLastModDate,
7961
+ lastModDateClamped: storedLastModDate === clampedLastModDate && dosLastModDate.getTime() != clampedLastModDate.getTime(),
7636
7962
  rawLastModDate,
7637
7963
  encrypted,
7638
7964
  compressed,
7639
7965
  version,
7640
7966
  compressionMethod,
7641
7967
  extraFieldExtendedTimestampFlag,
7968
+ extraFieldExtendedTimestampTime,
7642
7969
  rawExtraFieldZip64: EMPTY_UINT8_ARRAY,
7643
7970
  localExtraFieldZip64Length,
7644
7971
  rawExtraFieldExtendedTimestamp,
@@ -7741,7 +8068,7 @@
7741
8068
  }, {
7742
8069
  zip64,
7743
8070
  zipCrypto,
7744
- passThrough,
8071
+ passThroughCompression,
7745
8072
  dataDescriptor
7746
8073
  }) {
7747
8074
  const {
@@ -7752,7 +8079,7 @@
7752
8079
  dataDescriptorView,
7753
8080
  dataDescriptorOffset
7754
8081
  } = dataDescriptorInfo;
7755
- if ((!encrypted || zipCrypto || passThrough) && crc32 !== UNDEFINED_VALUE) {
8082
+ if ((!encrypted || zipCrypto || passThroughCompression) && crc32 !== UNDEFINED_VALUE) {
7756
8083
  setUint32(headerView, HEADER_OFFSET_SIGNATURE, crc32);
7757
8084
  if (dataDescriptor) {
7758
8085
  setUint32(dataDescriptorView, dataDescriptorOffset, crc32);
@@ -7783,9 +8110,9 @@
7783
8110
  uncompressedSize,
7784
8111
  zip64UncompressedSize,
7785
8112
  zip64CompressedSize
7786
- }, localHeaderView, { dataDescriptor, passThrough }) {
8113
+ }, localHeaderView, { dataDescriptor, passThroughCompression }) {
7787
8114
  if (!dataDescriptor) {
7788
- if (!encrypted || (passThrough && crc32 !== UNDEFINED_VALUE)) {
8115
+ if (!encrypted || (passThroughCompression && crc32 !== UNDEFINED_VALUE)) {
7789
8116
  setUint32(localHeaderView, HEADER_OFFSET_SIGNATURE + LOCAL_HEADER_COMMON_OFFSET, crc32);
7790
8117
  }
7791
8118
  if (!zip64CompressedSize) {
@@ -7822,9 +8149,8 @@
7822
8149
  rawExtraFieldUnix,
7823
8150
  rawExtraField,
7824
8151
  rawCentralExtraField,
7825
- extendedTimestamp,
7826
8152
  extraFieldExtendedTimestampFlag,
7827
- lastModDate,
8153
+ extraFieldExtendedTimestampTime,
7828
8154
  zip64Enabled,
7829
8155
  uncompressedSize,
7830
8156
  compressedSize
@@ -7867,16 +8193,15 @@
7867
8193
  fileEntry.zip64Offset = zip64Offset;
7868
8194
  fileEntry.zip64DiskNumberStart = zip64DiskNumberStart;
7869
8195
  let rawExtraFieldTimestamp;
7870
- const lastModTimeUnix = getTimeUnix(lastModDate);
7871
- if (extendedTimestamp && inUnixTimeRange(lastModTimeUnix)) {
8196
+ if (extraFieldExtendedTimestampTime === UNDEFINED_VALUE) {
8197
+ rawExtraFieldTimestamp = EMPTY_UINT8_ARRAY;
8198
+ } else {
7872
8199
  const extraFieldTimestamp = createRecordWriter(9);
7873
8200
  extraFieldTimestamp.writeUint16(EXTRAFIELD_TYPE_EXTENDED_TIMESTAMP);
7874
8201
  extraFieldTimestamp.writeUint16(5);
7875
8202
  extraFieldTimestamp.writeUint8(extraFieldExtendedTimestampFlag);
7876
- extraFieldTimestamp.writeUint32(lastModTimeUnix);
8203
+ extraFieldTimestamp.writeUint32(extraFieldExtendedTimestampTime);
7877
8204
  rawExtraFieldTimestamp = extraFieldTimestamp.array;
7878
- } else {
7879
- rawExtraFieldTimestamp = EMPTY_UINT8_ARRAY;
7880
8205
  }
7881
8206
  fileEntry.rawExtraFieldExtendedTimestamp = rawExtraFieldTimestamp;
7882
8207
  const extraFieldLength = getLength(
@@ -8376,6 +8701,11 @@
8376
8701
  };
8377
8702
  }
8378
8703
 
8704
+ function isPrintableASCIIText(rawText) {
8705
+ return rawText.every(characterCode =>
8706
+ characterCode >= MIN_PRINTABLE_ASCII_CHARACTER_CODE && characterCode <= MAX_PRINTABLE_ASCII_CHARACTER_CODE);
8707
+ }
8708
+
8379
8709
  function getBitFlag(level, useUnicodeFileNames, dataDescriptor, encrypted, compressionMethod) {
8380
8710
  let bitFlag = 0;
8381
8711
  if (useUnicodeFileNames) {
@@ -8537,7 +8867,7 @@
8537
8867
  EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
8538
8868
  */
8539
8869
 
8540
- const VERSION = "2.11.3";
8870
+ const VERSION = "2.12.0";
8541
8871
 
8542
8872
  /*
8543
8873
  Copyright (c) 2025 Gildas Lormeau. All rights reserved.
@@ -8990,6 +9320,7 @@
8990
9320
  exports.BlobWriter = BlobWriter;
8991
9321
  exports.Data64URIReader = Data64URIReader;
8992
9322
  exports.Data64URIWriter = Data64URIWriter;
9323
+ exports.ERR_ABORTED = ERR_ABORTED;
8993
9324
  exports.ERR_AMBIGUOUS_ARCHIVE = ERR_AMBIGUOUS_ARCHIVE;
8994
9325
  exports.ERR_BAD_FORMAT = ERR_BAD_FORMAT;
8995
9326
  exports.ERR_CENTRAL_DIRECTORY_NOT_FOUND = ERR_CENTRAL_DIRECTORY_NOT_FOUND;
@@ -9002,7 +9333,9 @@
9002
9333
  exports.ERR_EXTRAFIELD_ZIP64_NOT_FOUND = ERR_EXTRAFIELD_ZIP64_NOT_FOUND;
9003
9334
  exports.ERR_HTTP_RANGE = ERR_HTTP_RANGE;
9004
9335
  exports.ERR_HTTP_RESOURCE_CHANGED = ERR_HTTP_RESOURCE_CHANGED;
9336
+ exports.ERR_HTTP_STATUS = ERR_HTTP_STATUS;
9005
9337
  exports.ERR_INVALID_AUTHENTICATION_CODE = ERR_INVALID_AUTHENTICATION_CODE;
9338
+ exports.ERR_INVALID_BASE_URI = ERR_INVALID_BASE_URI;
9006
9339
  exports.ERR_INVALID_CODEC_DEFINITION = ERR_INVALID_CODEC_DEFINITION;
9007
9340
  exports.ERR_INVALID_CODEC_MODULE = ERR_INVALID_CODEC_MODULE;
9008
9341
  exports.ERR_INVALID_COMMENT = ERR_INVALID_COMMENT;
@@ -9011,6 +9344,7 @@
9011
9344
  exports.ERR_INVALID_CRC32 = ERR_INVALID_CRC32;
9012
9345
  exports.ERR_INVALID_DATE = ERR_INVALID_DATE;
9013
9346
  exports.ERR_INVALID_ENCRYPTION_STRENGTH = ERR_INVALID_ENCRYPTION_STRENGTH;
9347
+ exports.ERR_INVALID_ENTRY = ERR_INVALID_ENTRY;
9014
9348
  exports.ERR_INVALID_ENTRY_COMMENT = ERR_INVALID_ENTRY_COMMENT;
9015
9349
  exports.ERR_INVALID_ENTRY_COMMENT_TYPE = ERR_INVALID_ENTRY_COMMENT_TYPE;
9016
9350
  exports.ERR_INVALID_ENTRY_NAME = ERR_INVALID_ENTRY_NAME;
@@ -9028,6 +9362,7 @@
9028
9362
  exports.ERR_INVALID_MSDOS_DATA = ERR_INVALID_MSDOS_DATA;
9029
9363
  exports.ERR_INVALID_PASSWORD = ERR_INVALID_PASSWORD;
9030
9364
  exports.ERR_INVALID_PASSWORD_TYPE = ERR_INVALID_PASSWORD_TYPE;
9365
+ exports.ERR_INVALID_PASS_THROUGH_VALUE = ERR_INVALID_PASS_THROUGH_VALUE;
9031
9366
  exports.ERR_INVALID_READER = ERR_INVALID_READER;
9032
9367
  exports.ERR_INVALID_SIGNAL = ERR_INVALID_SIGNAL;
9033
9368
  exports.ERR_INVALID_SIGNATURE_DATA = ERR_INVALID_SIGNATURE_DATA;
@@ -9037,6 +9372,7 @@
9037
9372
  exports.ERR_INVALID_UNIX_EXTRA_FIELD_TYPE = ERR_INVALID_UNIX_EXTRA_FIELD_TYPE;
9038
9373
  exports.ERR_INVALID_UNIX_ID_SIZE = ERR_INVALID_UNIX_ID_SIZE;
9039
9374
  exports.ERR_INVALID_UNIX_MODE = ERR_INVALID_UNIX_MODE;
9375
+ exports.ERR_INVALID_URI = ERR_INVALID_URI;
9040
9376
  exports.ERR_INVALID_VERSION = ERR_INVALID_VERSION;
9041
9377
  exports.ERR_ITERATOR_COMPLETED_TOO_SOON = ERR_ITERATOR_COMPLETED_TOO_SOON;
9042
9378
  exports.ERR_LOCAL_FILE_HEADER_NOT_FOUND = ERR_LOCAL_FILE_HEADER_NOT_FOUND;
@@ -9044,6 +9380,7 @@
9044
9380
  exports.ERR_RESERVED_COMPRESSION_METHOD = ERR_RESERVED_COMPRESSION_METHOD;
9045
9381
  exports.ERR_SPLIT_ZIP_FILE = ERR_SPLIT_ZIP_FILE;
9046
9382
  exports.ERR_UNDEFINED_COMPRESSION_METHOD = ERR_UNDEFINED_COMPRESSION_METHOD;
9383
+ exports.ERR_UNDEFINED_CRC32 = ERR_UNDEFINED_CRC32;
9047
9384
  exports.ERR_UNDEFINED_READER = ERR_UNDEFINED_READER;
9048
9385
  exports.ERR_UNDEFINED_UNCOMPRESSED_SIZE = ERR_UNDEFINED_UNCOMPRESSED_SIZE;
9049
9386
  exports.ERR_UNDETERMINED_SIZE = ERR_UNDETERMINED_SIZE;
@@ -9059,6 +9396,8 @@
9059
9396
  exports.ERR_UNSUPPORTED_UINT64 = ERR_UNSUPPORTED_UINT64;
9060
9397
  exports.ERR_WORKER_STARTUP_TIMEOUT = ERR_WORKER_STARTUP_TIMEOUT;
9061
9398
  exports.ERR_WRITER_NOT_INITIALIZED = ERR_WRITER_NOT_INITIALIZED;
9399
+ exports.ERR_WRITER_SIZE_NOT_WRITABLE = ERR_WRITER_SIZE_NOT_WRITABLE;
9400
+ exports.ERR_ZIP_CRYPTO_LAST_MOD_DATE = ERR_ZIP_CRYPTO_LAST_MOD_DATE;
9062
9401
  exports.ERR_ZIP_NOT_EMPTY = ERR_ZIP_NOT_EMPTY;
9063
9402
  exports.HttpRangeReader = HttpRangeReader;
9064
9403
  exports.HttpReader = HttpReader;
@@ -9071,13 +9410,17 @@
9071
9410
  exports.Uint8ArrayWriter = Uint8ArrayWriter;
9072
9411
  exports.VERSION = VERSION;
9073
9412
  exports.WARNING_APPENDED_DATA = WARNING_APPENDED_DATA;
9413
+ exports.WARNING_CLAMPED_LAST_MODIFICATION_DATE = WARNING_CLAMPED_LAST_MODIFICATION_DATE;
9074
9414
  exports.WARNING_COMPRESSED_PATCHED_DATA = WARNING_COMPRESSED_PATCHED_DATA;
9415
+ exports.WARNING_COMPRESSION_UNAVAILABLE = WARNING_COMPRESSION_UNAVAILABLE;
9075
9416
  exports.WARNING_DUPLICATE_FILENAME = WARNING_DUPLICATE_FILENAME;
9076
9417
  exports.WARNING_MALFORMED_EXTRA_FIELD = WARNING_MALFORMED_EXTRA_FIELD;
9077
9418
  exports.WARNING_MISMATCHED_LOCAL_FILE_HEADER_BIT_FLAG = WARNING_MISMATCHED_LOCAL_FILE_HEADER_BIT_FLAG;
9078
9419
  exports.WARNING_MISMATCHED_LOCAL_FILE_HEADER_COMPRESSION_METHOD = WARNING_MISMATCHED_LOCAL_FILE_HEADER_COMPRESSION_METHOD;
9079
9420
  exports.WARNING_MISMATCHED_LOCAL_FILE_HEADER_CRC32_OR_SIZES = WARNING_MISMATCHED_LOCAL_FILE_HEADER_CRC32_OR_SIZES;
9421
+ exports.WARNING_MISMATCHED_LOCAL_FILE_HEADER_FILENAME = WARNING_MISMATCHED_LOCAL_FILE_HEADER_FILENAME;
9080
9422
  exports.WARNING_MISMATCHED_ZIP64_END_OF_CENTRAL_DIRECTORY = WARNING_MISMATCHED_ZIP64_END_OF_CENTRAL_DIRECTORY;
9423
+ exports.WARNING_MULTIPLE_END_OF_CENTRAL_DIRECTORY = WARNING_MULTIPLE_END_OF_CENTRAL_DIRECTORY;
9081
9424
  exports.WARNING_PREPENDED_CENTRAL_DIRECTORY = WARNING_PREPENDED_CENTRAL_DIRECTORY;
9082
9425
  exports.WARNING_PREPENDED_DATA = WARNING_PREPENDED_DATA;
9083
9426
  exports.WARNING_TRAILING_CENTRAL_DIRECTORY_DATA = WARNING_TRAILING_CENTRAL_DIRECTORY_DATA;