@zip.js/zip.js 2.8.35 → 2.8.37

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 (40) hide show
  1. package/deno.json +3 -2
  2. package/dist/zip-core.js +246 -55
  3. package/dist/zip-core.min.js +1 -1
  4. package/dist/zip-fs-core.js +198 -55
  5. package/dist/zip-fs-core.min.js +1 -1
  6. package/dist/zip-fs-native.js +249 -58
  7. package/dist/zip-fs-native.min.js +1 -1
  8. package/dist/zip-fs.js +247 -56
  9. package/dist/zip-fs.min.js +1 -1
  10. package/dist/zip-legacy.js +248 -57
  11. package/dist/zip-legacy.min.js +1 -1
  12. package/dist/zip-native.js +249 -58
  13. package/dist/zip-native.min.js +1 -1
  14. package/dist/zip-web-worker-native.js +1 -1
  15. package/dist/zip-web-worker.js +1 -1
  16. package/dist/zip.js +247 -56
  17. package/dist/zip.min.js +1 -1
  18. package/index-native.cjs +249 -58
  19. package/index-native.min.js +1 -1
  20. package/index.cjs +247 -56
  21. package/index.d.cts +112 -2
  22. package/index.d.ts +112 -2
  23. package/index.min.js +1 -1
  24. package/lib/core/codec-pool.js +19 -3
  25. package/lib/core/codec-registry.js +116 -0
  26. package/lib/core/constants.js +1 -1
  27. package/lib/core/io.js +47 -26
  28. package/lib/core/options.js +2 -0
  29. package/lib/core/streams/codec-stream.js +1 -1
  30. package/lib/core/streams/zip-entry-stream.js +22 -5
  31. package/lib/core/streams/zlib-js/zlib-streams.min.js +1 -1
  32. package/lib/core/web-worker-base.js +5 -1
  33. package/lib/core/web-worker-inline-native.js +1 -1
  34. package/lib/core/web-worker-inline-wasm.js +1 -1
  35. package/lib/core/zip-reader.js +6 -2
  36. package/lib/core/zip-writer.js +53 -18
  37. package/lib/zip-core-base.js +7 -0
  38. package/lib/zip-core-writer.js +1 -0
  39. package/package.json +1 -1
  40. package/worker-message-property-names.js +1 -1
@@ -103,7 +103,7 @@
103
103
  const HEADER_OFFSET_UNCOMPRESSED_SIZE = 18;
104
104
  const LOCAL_HEADER_COMMON_OFFSET = 4;
105
105
 
106
- const MAX_DATE = new Date(2107, 11, 31);
106
+ const MAX_DATE = new Date(2107, 11, 31, 23, 59, 58);
107
107
  const MIN_DATE = new Date(1980, 0, 1);
108
108
 
109
109
  const UNDEFINED_VALUE = undefined;
@@ -268,6 +268,7 @@
268
268
  const HTTP_METHOD_GET = "GET";
269
269
  const HTTP_RANGE_UNIT = "bytes";
270
270
  const DEFAULT_BUFFER_SIZE = 256 * 1024;
271
+ const DEFAULT_MAXIMUM_RANGE_SIZE = 16 * 1024 * 1024;
271
272
 
272
273
  const PROPERTY_NAME_WRITABLE = "writable";
273
274
  const DISK_BOUNDARY = Symbol();
@@ -580,6 +581,7 @@
580
581
  forceRangeRequests,
581
582
  combineSizeEocd,
582
583
  checkResourceChanges = true,
584
+ maximumRangeSize = DEFAULT_MAXIMUM_RANGE_SIZE,
583
585
  fetch
584
586
  } = options;
585
587
  options = Object.assign({}, options);
@@ -588,6 +590,7 @@
588
590
  delete options.forceRangeRequests;
589
591
  delete options.combineSizeEocd;
590
592
  delete options.checkResourceChanges;
593
+ delete options.maximumRangeSize;
591
594
  delete options.useXHR;
592
595
  delete options.fetch;
593
596
  Object.assign(httpReader, {
@@ -598,6 +601,7 @@
598
601
  forceRangeRequests,
599
602
  combineSizeEocd,
600
603
  checkResourceChanges,
604
+ maximumRangeSize,
601
605
  fetch
602
606
  });
603
607
  }
@@ -683,40 +687,31 @@
683
687
 
684
688
  function createRangeReadable(httpReader, offset, size) {
685
689
  let bodyReader;
690
+ let windowOffset = offset;
691
+ let windowRemainingLength = 0;
686
692
  let remainingLength = size;
687
693
  return new ReadableStream({
688
- async start() {
689
- const response = await sendFetchRequest(HTTP_METHOD_GET, httpReader, getRangeHeaders(httpReader, offset, size));
690
- if (response.status != 206) {
691
- throw new Error(ERR_HTTP_RANGE);
692
- }
693
- const contentRangeHeader = response.headers.get(HTTP_HEADER_CONTENT_RANGE);
694
- if (contentRangeHeader) {
695
- const rangeStart = Number(contentRangeHeader.trim().split(/[\s-]+/)[1]);
696
- if (!Number.isNaN(rangeStart) && rangeStart != offset) {
697
- throw new Error(ERR_HTTP_RANGE);
698
- }
699
- }
700
- checkResourceValidators(httpReader, response);
701
- setResourceValidators(httpReader, response);
702
- bodyReader = response.body.getReader();
694
+ start() {
695
+ return openWindow();
703
696
  },
704
697
  async pull(controller) {
698
+ if (!bodyReader) {
699
+ await openWindow();
700
+ }
705
701
  const { value, done } = await bodyReader.read();
706
702
  if (done) {
707
- if (remainingLength) {
708
- throw new Error(ERR_HTTP_RANGE);
709
- }
710
- controller.close();
711
- } else {
712
- const chunk = value.length > remainingLength ? value.subarray(0, remainingLength) : value;
713
- remainingLength -= chunk.length;
714
- if (chunk.length) {
715
- controller.enqueue(chunk);
716
- }
703
+ throw new Error(ERR_HTTP_RANGE);
704
+ }
705
+ const chunk = value.length > windowRemainingLength ? value.subarray(0, windowRemainingLength) : value;
706
+ windowRemainingLength -= chunk.length;
707
+ remainingLength -= chunk.length;
708
+ if (chunk.length) {
709
+ controller.enqueue(chunk);
710
+ }
711
+ if (!windowRemainingLength) {
712
+ await closeWindow();
717
713
  if (!remainingLength) {
718
714
  controller.close();
719
- await bodyReader.cancel();
720
715
  }
721
716
  }
722
717
  },
@@ -724,6 +719,32 @@
724
719
  return bodyReader && bodyReader.cancel(reason);
725
720
  }
726
721
  });
722
+
723
+ async function openWindow() {
724
+ const windowLength = Math.min(httpReader.maximumRangeSize, remainingLength);
725
+ const response = await sendFetchRequest(HTTP_METHOD_GET, httpReader, getRangeHeaders(httpReader, windowOffset, windowLength));
726
+ if (response.status != 206) {
727
+ throw new Error(ERR_HTTP_RANGE);
728
+ }
729
+ const contentRangeHeader = response.headers.get(HTTP_HEADER_CONTENT_RANGE);
730
+ if (contentRangeHeader) {
731
+ const rangeStart = Number(contentRangeHeader.trim().split(/[\s-]+/)[1]);
732
+ if (!Number.isNaN(rangeStart) && rangeStart != windowOffset) {
733
+ throw new Error(ERR_HTTP_RANGE);
734
+ }
735
+ }
736
+ checkResourceValidators(httpReader, response);
737
+ setResourceValidators(httpReader, response);
738
+ windowOffset += windowLength;
739
+ windowRemainingLength = windowLength;
740
+ bodyReader = response.body.getReader();
741
+ }
742
+
743
+ async function closeWindow() {
744
+ const currentBodyReader = bodyReader;
745
+ bodyReader = UNDEFINED_VALUE;
746
+ await currentBodyReader.cancel();
747
+ }
727
748
  }
728
749
 
729
750
  function getContentRangeSize(response) {
@@ -1150,6 +1171,61 @@
1150
1171
  return reader.readUint8Array(offset, size);
1151
1172
  }
1152
1173
 
1174
+ /*
1175
+ Copyright (c) 2025 Gildas Lormeau. All rights reserved.
1176
+
1177
+ Redistribution and use in source and binary forms, with or without
1178
+ modification, are permitted provided that the following conditions are met:
1179
+
1180
+ 1. Redistributions of source code must retain the above copyright notice,
1181
+ this list of conditions and the following disclaimer.
1182
+
1183
+ 2. Redistributions in binary form must reproduce the above copyright
1184
+ notice, this list of conditions and the following disclaimer in
1185
+ the documentation and/or other materials provided with the distribution.
1186
+
1187
+ 3. The names of the authors may not be used to endorse or promote products
1188
+ derived from this software without specific prior written permission.
1189
+
1190
+ THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
1191
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
1192
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
1193
+ INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
1194
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
1195
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
1196
+ OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
1197
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
1198
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
1199
+ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1200
+ */
1201
+
1202
+ const ERR_INVALID_CODEC_MODULE = "Invalid codec module";
1203
+
1204
+ const registeredCodecs = new Map();
1205
+ const codecStreams = new Map();
1206
+
1207
+ function getRegisteredCodec(compressionMethod) {
1208
+ return registeredCodecs.get(compressionMethod);
1209
+ }
1210
+
1211
+ function getCodecStreams(format) {
1212
+ return codecStreams.get(format);
1213
+ }
1214
+
1215
+ function setCodecStreams(format, streams) {
1216
+ const { CompressionStream, DecompressionStream } = streams;
1217
+ if (typeof CompressionStream != FUNCTION_TYPE && typeof DecompressionStream != FUNCTION_TYPE) {
1218
+ throw new Error(ERR_INVALID_CODEC_MODULE);
1219
+ }
1220
+ codecStreams.set(format, { CompressionStream, DecompressionStream });
1221
+ }
1222
+
1223
+ async function ensureCodecStreams(format, codecURI) {
1224
+ if (!codecStreams.has(format) && codecURI) {
1225
+ setCodecStreams(format, await import(codecURI));
1226
+ }
1227
+ }
1228
+
1153
1229
  /*
1154
1230
  Copyright (c) 2022 Gildas Lormeau. All rights reserved.
1155
1231
 
@@ -2642,6 +2718,7 @@
2642
2718
 
2643
2719
  const ERR_INVALID_UNCOMPRESSED_SIZE = "Invalid uncompressed size";
2644
2720
  const ERR_INVALID_COMPRESSED_DATA = "Invalid compressed data";
2721
+ const ERR_UNSUPPORTED_COMPRESSION$2 = "Compression method not supported";
2645
2722
  const FORMAT_DEFLATE_RAW = "deflate-raw";
2646
2723
  const FORMAT_DEFLATE64_RAW = "deflate64-raw";
2647
2724
  const FORMAT_GZIP = "gzip";
@@ -2652,18 +2729,21 @@
2652
2729
 
2653
2730
  constructor(options, { chunkSize, CompressionStreamZlib, CompressionStream }) {
2654
2731
  super({});
2655
- const { compressed, encrypted, useCompressionStream, zipCrypto, signed, level, deflate64 } = options;
2732
+ const { compressed, encrypted, useCompressionStream, zipCrypto, signed, level, deflate64, format } = options;
2656
2733
  const stream = this;
2657
2734
  let crc32Stream, encryptionStream, gzipCrc32Stream;
2658
2735
  let readable = super.readable;
2659
- const useGzipCrc32 = signed && compressed && !deflate64 && (!encrypted || zipCrypto) &&
2736
+ const codecStreams = format && getCodecStreams(format);
2737
+ const useGzipCrc32 = signed && compressed && !deflate64 && !codecStreams && (!encrypted || zipCrypto) &&
2660
2738
  Boolean(useCompressionStream && CompressionStream);
2661
2739
  if ((!encrypted || zipCrypto) && signed && !useGzipCrc32) {
2662
2740
  crc32Stream = new Crc32Stream();
2663
2741
  readable = pipeThrough(readable, crc32Stream);
2664
2742
  }
2665
2743
  if (compressed) {
2666
- if (useGzipCrc32) {
2744
+ if (codecStreams) {
2745
+ readable = pipeThroughBackpressured(readable, createCodecStream(codecStreams.CompressionStream, format, { level, chunkSize }));
2746
+ } else if (useGzipCrc32) {
2667
2747
  gzipCrc32Stream = new GzipToRawDeflateStream();
2668
2748
  readable = pipeThroughBackpressured(readable, new CompressionStream(FORMAT_GZIP));
2669
2749
  readable = pipeThrough(readable, gzipCrc32Stream);
@@ -2737,7 +2817,7 @@
2737
2817
 
2738
2818
  constructor(options, { chunkSize, DecompressionStreamZlib, DecompressionStream }) {
2739
2819
  super({});
2740
- const { zipCrypto, encrypted, signed, signature, compressed, useCompressionStream, deflate64 } = options;
2820
+ const { zipCrypto, encrypted, signed, signature, compressed, useCompressionStream, deflate64, format } = options;
2741
2821
  let crc32Stream, decryptionStream;
2742
2822
  let readable = super.readable;
2743
2823
  if (encrypted) {
@@ -2749,7 +2829,12 @@
2749
2829
  }
2750
2830
  }
2751
2831
  if (compressed) {
2752
- readable = pipeThroughCommpressionStream(readable, useCompressionStream, { chunkSize, deflate64 }, DecompressionStream, DecompressionStreamZlib, DecompressionStream);
2832
+ const codecStreams = format && getCodecStreams(format);
2833
+ if (codecStreams) {
2834
+ readable = pipeThroughBackpressured(readable, createCodecStream(codecStreams.DecompressionStream, format, { chunkSize }));
2835
+ } else {
2836
+ readable = pipeThroughCommpressionStream(readable, useCompressionStream, { chunkSize, deflate64 }, DecompressionStream, DecompressionStreamZlib, DecompressionStream);
2837
+ }
2753
2838
  readable = mapInflateStreamError(readable);
2754
2839
  }
2755
2840
  if ((!encrypted || zipCrypto) && signed) {
@@ -2776,6 +2861,13 @@
2776
2861
  });
2777
2862
  }
2778
2863
 
2864
+ function createCodecStream(CodecStreamClass, format, options) {
2865
+ if (!CodecStreamClass) {
2866
+ throw new Error(ERR_UNSUPPORTED_COMPRESSION$2);
2867
+ }
2868
+ return new CodecStreamClass(format, options);
2869
+ }
2870
+
2779
2871
  function pipeThroughCommpressionStream(readable, useCompressionStream, options, CompressionStreamNative, CompressionStreamZlib, CompressionStream) {
2780
2872
  const Stream = useCompressionStream && CompressionStreamNative ? CompressionStreamNative : CompressionStreamZlib || CompressionStream;
2781
2873
  const format = options.deflate64 ? FORMAT_DEFLATE64_RAW : FORMAT_DEFLATE_RAW;
@@ -2969,7 +3061,7 @@
2969
3061
  constructor(chunkSize) {
2970
3062
  const pendingChunks = [];
2971
3063
  let pendingLength = 0;
2972
- if (!(chunkSize >= 1)) {
3064
+ if (!Number.isFinite(chunkSize) || chunkSize < 1) {
2973
3065
  chunkSize = DEFAULT_CHUNK_SIZE;
2974
3066
  }
2975
3067
  super({
@@ -3520,11 +3612,18 @@
3520
3612
 
3521
3613
  async function runWorker(stream, workerOptions) {
3522
3614
  const { options, config } = workerOptions;
3523
- const { transferStreams, useWebWorkers, useCompressionStream, compressed, signed, encrypted } = options;
3615
+ const { transferStreams, useWebWorkers, useCompressionStream, compressed, signed, encrypted, format, codecURI } = options;
3524
3616
  const { workerURI, maxWorkers } = config;
3617
+ if (format) {
3618
+ if (codecURI) {
3619
+ options.codecURI = resolveCodecURI(codecURI, config.baseURI);
3620
+ }
3621
+ await ensureCodecStreams(format, options.codecURI);
3622
+ }
3525
3623
  workerOptions.transferStreams = transferStreams || (transferStreams === UNDEFINED_VALUE && config.transferStreams);
3526
3624
  const streamCopy = !compressed && !signed && !encrypted;
3527
- workerOptions.useWebWorkers = !streamCopy && (useWebWorkers || (useWebWorkers === UNDEFINED_VALUE && config.useWebWorkers));
3625
+ const workerSupported = format === UNDEFINED_VALUE || Boolean(options.codecURI);
3626
+ workerOptions.useWebWorkers = !streamCopy && workerSupported && (useWebWorkers || (useWebWorkers === UNDEFINED_VALUE && config.useWebWorkers));
3528
3627
  workerOptions.workerURI = workerOptions.useWebWorkers && workerURI ? workerURI : UNDEFINED_VALUE;
3529
3628
  options.useCompressionStream = useCompressionStream || (useCompressionStream === UNDEFINED_VALUE && config.useCompressionStream);
3530
3629
  return (await getWorker()).run();
@@ -3564,6 +3663,14 @@
3564
3663
  }
3565
3664
  }
3566
3665
 
3666
+ function resolveCodecURI(codecURI, baseURI) {
3667
+ try {
3668
+ return new URL(codecURI, baseURI).toString();
3669
+ } catch {
3670
+ return codecURI;
3671
+ }
3672
+ }
3673
+
3567
3674
  function armStarvationTimeout() {
3568
3675
  if (!starvationTimeout && pendingRequests.length && Number.isFinite(starvationDelay) && starvationDelay >= 0) {
3569
3676
  starvationTimeout = setTimeout(onWorkerStarvation, starvationDelay);
@@ -3882,6 +3989,7 @@
3882
3989
  const OPTION_PREVENT_CLOSE = "preventClose";
3883
3990
  const OPTION_ENCRYPTION_STRENGTH = "encryptionStrength";
3884
3991
  const OPTION_EXTENDED_TIMESTAMP = "extendedTimestamp";
3992
+ const OPTION_NTFS_TIMESTAMP = "ntfsTimestamp";
3885
3993
  const OPTION_KEEP_ORDER = "keepOrder";
3886
3994
  const OPTION_LEVEL = "level";
3887
3995
  const OPTION_BUFFERED_WRITE = "bufferedWrite";
@@ -4313,7 +4421,8 @@
4313
4421
  throw new Error(ERR_UNSUPPORTED_COMPRESSION$1);
4314
4422
  }
4315
4423
  }
4316
- if ((compressionMethod != COMPRESSION_METHOD_STORE && compressionMethod != COMPRESSION_METHOD_DEFLATE && compressionMethod != COMPRESSION_METHOD_DEFLATE_64) && !passThrough) {
4424
+ const registeredCodec = passThrough ? UNDEFINED_VALUE : getRegisteredCodec(compressionMethod);
4425
+ if ((compressionMethod != COMPRESSION_METHOD_STORE && compressionMethod != COMPRESSION_METHOD_DEFLATE && compressionMethod != COMPRESSION_METHOD_DEFLATE_64 && !registeredCodec) && !passThrough) {
4317
4426
  throw new Error(ERR_UNSUPPORTED_COMPRESSION$1);
4318
4427
  }
4319
4428
  if (dataArray.length < HEADER_SIZE || getUint32(dataView, 0) != LOCAL_FILE_HEADER_SIGNATURE) {
@@ -4352,7 +4461,7 @@
4352
4461
  fileEntry.zipCrypto = zipCrypto;
4353
4462
  }
4354
4463
  if (encrypted) {
4355
- if (!zipCrypto && extraFieldAES.strength === UNDEFINED_VALUE) {
4464
+ if (!zipCrypto && (extraFieldAES.strength < 1 || extraFieldAES.strength > 3)) {
4356
4465
  throw new Error(ERR_UNSUPPORTED_ENCRYPTION);
4357
4466
  } else if (!password && !rawPassword) {
4358
4467
  throw new Error(ERR_ENCRYPTED);
@@ -4391,6 +4500,8 @@
4391
4500
  useCompressionStream,
4392
4501
  transferStreams: getOptionValue$1(zipEntry, options, OPTION_TRANSFER_STREAMS),
4393
4502
  deflate64,
4503
+ format: registeredCodec ? registeredCodec.format : UNDEFINED_VALUE,
4504
+ codecURI: registeredCodec ? registeredCodec.codecURI : UNDEFINED_VALUE,
4394
4505
  checkPasswordOnly
4395
4506
  },
4396
4507
  config,
@@ -5007,6 +5118,7 @@
5007
5118
  const ERR_INVALID_ENTRY_NAME = "File entry name exceeds 64KB";
5008
5119
  const ERR_INVALID_VERSION = "Version exceeds 65535";
5009
5120
  const ERR_INVALID_ENCRYPTION_STRENGTH = "The strength must equal 1, 2, or 3";
5121
+ const ERR_UNSUPPORTED_ENCRYPTION_USDZ = "Encryption is not supported in USDZ files";
5010
5122
  const ERR_INVALID_EXTRAFIELD_TYPE = "Extra field type exceeds 65535";
5011
5123
  const ERR_INVALID_EXTRAFIELD_DATA = "Extra field data exceeds 64KB";
5012
5124
  const ERR_UNSUPPORTED_COMPRESSION = "Compression method not supported";
@@ -5409,6 +5521,7 @@
5409
5521
  const encryptionStrength = getOptionValue(zipWriter, options, OPTION_ENCRYPTION_STRENGTH, 3);
5410
5522
  const zipCrypto = getOptionValue(zipWriter, options, PROPERTY_NAME_ZIPCRYPTO);
5411
5523
  const extendedTimestamp = getOptionValue(zipWriter, options, OPTION_EXTENDED_TIMESTAMP, true);
5524
+ const ntfsTimestamp = getOptionValue(zipWriter, options, OPTION_NTFS_TIMESTAMP);
5412
5525
  const keepOrder = getOptionValue(zipWriter, options, OPTION_KEEP_ORDER, true);
5413
5526
  const useWebWorkers = getOptionValue(zipWriter, options, OPTION_USE_WEB_WORKERS);
5414
5527
  const transferStreams = getOptionValue(zipWriter, options, OPTION_TRANSFER_STREAMS);
@@ -5418,11 +5531,20 @@
5418
5531
  const signal = getOptionValue(zipWriter, options, OPTION_SIGNAL);
5419
5532
  const useUnicodeFileNames = getOptionValue(zipWriter, options, OPTION_USE_UNICODE_FILE_NAMES, true);
5420
5533
  const compressionMethod = getOptionValue(zipWriter, options, PROPERTY_NAME_COMPRESSION_METHOD);
5534
+ const registeredCodec = passThrough || compressionMethod === UNDEFINED_VALUE ? UNDEFINED_VALUE : getRegisteredCodec(compressionMethod);
5421
5535
  if (!passThrough && compressionMethod !== UNDEFINED_VALUE &&
5422
- compressionMethod !== COMPRESSION_METHOD_STORE && compressionMethod !== COMPRESSION_METHOD_DEFLATE) {
5536
+ compressionMethod !== COMPRESSION_METHOD_STORE && compressionMethod !== COMPRESSION_METHOD_DEFLATE && !registeredCodec) {
5423
5537
  throw new Error(ERR_UNSUPPORTED_COMPRESSION);
5424
5538
  }
5425
5539
  let level = getOptionValue(zipWriter, options, OPTION_LEVEL);
5540
+ if (zipWriter.options[OPTION_USDZ]) {
5541
+ if (password !== UNDEFINED_VALUE || rawPassword !== UNDEFINED_VALUE) {
5542
+ throw new Error(ERR_UNSUPPORTED_ENCRYPTION_USDZ);
5543
+ }
5544
+ if (level === UNDEFINED_VALUE && compressionMethod === UNDEFINED_VALUE) {
5545
+ level = 0;
5546
+ }
5547
+ }
5426
5548
  let useCompressionStream = getOptionValue(zipWriter, options, OPTION_USE_COMPRESSION_STREAM);
5427
5549
  let dataDescriptor = getOptionValue(zipWriter, options, OPTION_DATA_DESCRIPTOR);
5428
5550
  if (bufferedWrite && dataDescriptor === UNDEFINED_VALUE) {
@@ -5434,7 +5556,7 @@
5434
5556
  if (level !== UNDEFINED_VALUE && level != 6) {
5435
5557
  useCompressionStream = false;
5436
5558
  }
5437
- if (!useCompressionStream && (zipWriter.config.CompressionStream === UNDEFINED_VALUE && zipWriter.config.CompressionStreamZlib === UNDEFINED_VALUE)) {
5559
+ if (!useCompressionStream && !registeredCodec && (zipWriter.config.CompressionStream === UNDEFINED_VALUE && zipWriter.config.CompressionStreamZlib === UNDEFINED_VALUE)) {
5438
5560
  level = 0;
5439
5561
  }
5440
5562
  const zip64 = getOptionValue(zipWriter, options, PROPERTY_NAME_ZIP64);
@@ -5478,6 +5600,7 @@
5478
5600
  encryptionStrength,
5479
5601
  zipCrypto,
5480
5602
  extendedTimestamp,
5603
+ ntfsTimestamp,
5481
5604
  keepOrder,
5482
5605
  useWebWorkers,
5483
5606
  transferStreams,
@@ -5487,6 +5610,9 @@
5487
5610
  signal,
5488
5611
  useUnicodeFileNames,
5489
5612
  compressionMethod,
5613
+ format: registeredCodec ? registeredCodec.format : UNDEFINED_VALUE,
5614
+ codecURI: registeredCodec ? registeredCodec.codecURI : UNDEFINED_VALUE,
5615
+ codecVersionNeeded: registeredCodec ? registeredCodec.versionNeeded : UNDEFINED_VALUE,
5490
5616
  level,
5491
5617
  useCompressionStream,
5492
5618
  dataDescriptor,
@@ -5783,7 +5909,9 @@
5783
5909
  msdosAttributesRaw,
5784
5910
  msdosAttributes,
5785
5911
  useCompressionStream,
5786
- passThrough
5912
+ passThrough,
5913
+ format,
5914
+ codecURI
5787
5915
  } = options;
5788
5916
  const fileEntry = {
5789
5917
  lock,
@@ -5843,7 +5971,9 @@
5843
5971
  encrypted: encrypted && !passThrough,
5844
5972
  useWebWorkers,
5845
5973
  useCompressionStream,
5846
- transferStreams
5974
+ transferStreams,
5975
+ format,
5976
+ codecURI
5847
5977
  },
5848
5978
  config,
5849
5979
  streamOptions: { signal, size, onstart, onprogress, onend }
@@ -5915,6 +6045,7 @@
5915
6045
  rawExtraField,
5916
6046
  encryptionStrength,
5917
6047
  extendedTimestamp,
6048
+ ntfsTimestamp,
5918
6049
  passThrough,
5919
6050
  encrypted,
5920
6051
  zip64UncompressedSize,
@@ -5960,7 +6091,8 @@
5960
6091
  let extraFieldExtendedTimestampFlag;
5961
6092
  if (extendedTimestamp) {
5962
6093
  const lastModTimeUnix = getTimeUnix(lastModDate);
5963
- if (inUnixTimeRange(lastModTimeUnix)) {
6094
+ const lastModTimeUnixInRange = inUnixTimeRange(lastModTimeUnix);
6095
+ if (lastModTimeUnixInRange) {
5964
6096
  const extraFieldTimestampLength = 9 + (lastAccessDate ? 4 : 0) + (creationDate ? 4 : 0);
5965
6097
  const extraFieldTimestamp = createRecordWriter(extraFieldTimestampLength);
5966
6098
  extraFieldExtendedTimestampFlag = 0x1 + (lastAccessDate ? 0x2 : 0) + (creationDate ? 0x4 : 0);
@@ -5978,19 +6110,26 @@
5978
6110
  } else {
5979
6111
  rawExtraFieldExtendedTimestamp = EMPTY_UINT8_ARRAY;
5980
6112
  }
5981
- try {
5982
- const lastModTimeNTFS = getTimeNTFS(lastModDate);
5983
- const extraFieldNTFS = createRecordWriter(36);
5984
- extraFieldNTFS.uint16(EXTRAFIELD_TYPE_NTFS);
5985
- extraFieldNTFS.uint16(32);
5986
- extraFieldNTFS.skip(4);
5987
- extraFieldNTFS.uint16(EXTRAFIELD_TYPE_NTFS_TAG1);
5988
- extraFieldNTFS.uint16(24);
5989
- extraFieldNTFS.uint64(lastModTimeNTFS);
5990
- extraFieldNTFS.uint64(getTimeNTFS(lastAccessDate) || lastModTimeNTFS);
5991
- extraFieldNTFS.uint64(getTimeNTFS(creationDate) || lastModTimeNTFS);
5992
- rawExtraFieldNTFS = extraFieldNTFS.array;
5993
- } catch {
6113
+ const writeExtraFieldNTFS = ntfsTimestamp === UNDEFINED_VALUE ?
6114
+ !lastModTimeUnixInRange || Boolean(lastAccessDate || creationDate) :
6115
+ ntfsTimestamp;
6116
+ if (writeExtraFieldNTFS) {
6117
+ try {
6118
+ const lastModTimeNTFS = getTimeNTFS(lastModDate);
6119
+ const extraFieldNTFS = createRecordWriter(36);
6120
+ extraFieldNTFS.uint16(EXTRAFIELD_TYPE_NTFS);
6121
+ extraFieldNTFS.uint16(32);
6122
+ extraFieldNTFS.skip(4);
6123
+ extraFieldNTFS.uint16(EXTRAFIELD_TYPE_NTFS_TAG1);
6124
+ extraFieldNTFS.uint16(24);
6125
+ extraFieldNTFS.uint64(lastModTimeNTFS);
6126
+ extraFieldNTFS.uint64(getTimeNTFS(lastAccessDate) || lastModTimeNTFS);
6127
+ extraFieldNTFS.uint64(getTimeNTFS(creationDate) || lastModTimeNTFS);
6128
+ rawExtraFieldNTFS = extraFieldNTFS.array;
6129
+ } catch {
6130
+ rawExtraFieldNTFS = EMPTY_UINT8_ARRAY;
6131
+ }
6132
+ } else {
5994
6133
  rawExtraFieldNTFS = EMPTY_UINT8_ARRAY;
5995
6134
  }
5996
6135
  } else {
@@ -6028,6 +6167,10 @@
6028
6167
  if (compressionMethod === UNDEFINED_VALUE) {
6029
6168
  compressionMethod = compressed ? COMPRESSION_METHOD_DEFLATE : COMPRESSION_METHOD_STORE;
6030
6169
  }
6170
+ const { codecVersionNeeded } = options;
6171
+ if (compressed && codecVersionNeeded !== UNDEFINED_VALUE) {
6172
+ version = version > codecVersionNeeded ? version : codecVersionNeeded;
6173
+ }
6031
6174
  if (zip64) {
6032
6175
  version = version > VERSION_ZIP64 ? version : VERSION_ZIP64;
6033
6176
  }