@zip.js/zip.js 2.8.36 → 2.8.38

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 (42) hide show
  1. package/deno.json +4 -2
  2. package/dist/zip-core.js +356 -63
  3. package/dist/zip-core.min.js +1 -1
  4. package/dist/zip-fs-core.js +301 -63
  5. package/dist/zip-fs-core.min.js +1 -1
  6. package/dist/zip-fs-native.js +359 -66
  7. package/dist/zip-fs-native.min.js +1 -1
  8. package/dist/zip-fs.js +357 -64
  9. package/dist/zip-fs.min.js +1 -1
  10. package/dist/zip-legacy.js +358 -65
  11. package/dist/zip-legacy.min.js +1 -1
  12. package/dist/zip-native.js +359 -66
  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 +357 -64
  17. package/dist/zip.min.js +1 -1
  18. package/index-native.cjs +359 -66
  19. package/index-native.min.js +1 -1
  20. package/index.cjs +357 -64
  21. package/index.d.cts +126 -4
  22. package/index.d.ts +126 -4
  23. package/index.min.js +1 -1
  24. package/lib/core/codec-pool.js +21 -4
  25. package/lib/core/codec-registry.js +116 -0
  26. package/lib/core/codec-worker.js +94 -18
  27. package/lib/core/configuration.js +2 -0
  28. package/lib/core/constants.js +5 -1
  29. package/lib/core/options.js +2 -0
  30. package/lib/core/streams/codec-stream.js +6 -2
  31. package/lib/core/streams/zip-entry-stream.js +50 -16
  32. package/lib/core/streams/zlib-js/zlib-streams.min.js +1 -1
  33. package/lib/core/web-worker-base.js +30 -8
  34. package/lib/core/web-worker-inline-native.js +1 -1
  35. package/lib/core/web-worker-inline-wasm.js +1 -1
  36. package/lib/core/zip-reader.js +29 -3
  37. package/lib/core/zip-writer.js +68 -25
  38. package/lib/zip-core-base.js +7 -0
  39. package/lib/zip-core-reader.js +2 -1
  40. package/lib/zip-core-writer.js +1 -0
  41. package/package.json +1 -1
  42. package/worker-message-property-names.js +1 -1
@@ -45,6 +45,7 @@
45
45
  const LOCAL_FILE_HEADER_SIGNATURE = 0x04034b50;
46
46
  const SPLIT_ZIP_FILE_SIGNATURE = 0x08074b50;
47
47
  const DATA_DESCRIPTOR_RECORD_SIGNATURE = SPLIT_ZIP_FILE_SIGNATURE;
48
+ const ARCHIVE_EXTRA_DATA_SIGNATURE = 0x08064b50;
48
49
  const CENTRAL_FILE_HEADER_SIGNATURE = 0x02014b50;
49
50
  const END_OF_CENTRAL_DIR_SIGNATURE = 0x06054b50;
50
51
  const ZIP64_END_OF_CENTRAL_DIR_SIGNATURE = 0x06064b50;
@@ -76,6 +77,7 @@
76
77
  const BITFLAG_LEVEL_FAST_MASK = 0b100;
77
78
  const BITFLAG_LEVEL_SUPER_FAST_MASK = 0b110;
78
79
  const BITFLAG_DATA_DESCRIPTOR = 0b1000;
80
+ const BITFLAG_STRONG_ENCRYPTION = 0b1000000;
79
81
  const BITFLAG_LANG_ENCODING_FLAG = 0b100000000000;
80
82
  const FILE_ATTR_MSDOS_DIR_MASK = 0b10000;
81
83
  const FILE_ATTR_MSDOS_READONLY_MASK = 0x01;
@@ -103,7 +105,7 @@
103
105
  const HEADER_OFFSET_UNCOMPRESSED_SIZE = 18;
104
106
  const LOCAL_HEADER_COMMON_OFFSET = 4;
105
107
 
106
- const MAX_DATE = new Date(2107, 11, 31);
108
+ const MAX_DATE = new Date(2107, 11, 31, 23, 59, 58);
107
109
  const MIN_DATE = new Date(1980, 0, 1);
108
110
 
109
111
  const UNDEFINED_VALUE = undefined;
@@ -159,6 +161,7 @@
159
161
  maxWorkers,
160
162
  terminateWorkerTimeout: 5000,
161
163
  workerStarvationTimeout: 5000,
164
+ workerStartupTimeout: 5000,
162
165
  useWebWorkers: true,
163
166
  useCompressionStream: true,
164
167
  transferStreams: true,
@@ -1171,6 +1174,61 @@
1171
1174
  return reader.readUint8Array(offset, size);
1172
1175
  }
1173
1176
 
1177
+ /*
1178
+ Copyright (c) 2025 Gildas Lormeau. All rights reserved.
1179
+
1180
+ Redistribution and use in source and binary forms, with or without
1181
+ modification, are permitted provided that the following conditions are met:
1182
+
1183
+ 1. Redistributions of source code must retain the above copyright notice,
1184
+ this list of conditions and the following disclaimer.
1185
+
1186
+ 2. Redistributions in binary form must reproduce the above copyright
1187
+ notice, this list of conditions and the following disclaimer in
1188
+ the documentation and/or other materials provided with the distribution.
1189
+
1190
+ 3. The names of the authors may not be used to endorse or promote products
1191
+ derived from this software without specific prior written permission.
1192
+
1193
+ THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
1194
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
1195
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
1196
+ INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
1197
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
1198
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
1199
+ OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
1200
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
1201
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
1202
+ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1203
+ */
1204
+
1205
+ const ERR_INVALID_CODEC_MODULE = "Invalid codec module";
1206
+
1207
+ const registeredCodecs = new Map();
1208
+ const codecStreams = new Map();
1209
+
1210
+ function getRegisteredCodec(compressionMethod) {
1211
+ return registeredCodecs.get(compressionMethod);
1212
+ }
1213
+
1214
+ function getCodecStreams(format) {
1215
+ return codecStreams.get(format);
1216
+ }
1217
+
1218
+ function setCodecStreams(format, streams) {
1219
+ const { CompressionStream, DecompressionStream } = streams;
1220
+ if (typeof CompressionStream != FUNCTION_TYPE && typeof DecompressionStream != FUNCTION_TYPE) {
1221
+ throw new Error(ERR_INVALID_CODEC_MODULE);
1222
+ }
1223
+ codecStreams.set(format, { CompressionStream, DecompressionStream });
1224
+ }
1225
+
1226
+ async function ensureCodecStreams(format, codecURI) {
1227
+ if (!codecStreams.has(format) && codecURI) {
1228
+ setCodecStreams(format, await import(codecURI));
1229
+ }
1230
+ }
1231
+
1174
1232
  /*
1175
1233
  Copyright (c) 2022 Gildas Lormeau. All rights reserved.
1176
1234
 
@@ -2663,6 +2721,7 @@
2663
2721
 
2664
2722
  const ERR_INVALID_UNCOMPRESSED_SIZE = "Invalid uncompressed size";
2665
2723
  const ERR_INVALID_COMPRESSED_DATA = "Invalid compressed data";
2724
+ const ERR_UNSUPPORTED_COMPRESSION$2 = "Compression method not supported";
2666
2725
  const FORMAT_DEFLATE_RAW = "deflate-raw";
2667
2726
  const FORMAT_DEFLATE64_RAW = "deflate64-raw";
2668
2727
  const FORMAT_GZIP = "gzip";
@@ -2673,23 +2732,26 @@
2673
2732
 
2674
2733
  constructor(options, { chunkSize, CompressionStreamZlib, CompressionStream }) {
2675
2734
  super({});
2676
- const { compressed, encrypted, useCompressionStream, zipCrypto, signed, level, deflate64 } = options;
2735
+ const { compressed, encrypted, useCompressionStream, zipCrypto, signed, level, deflate64, format } = options;
2677
2736
  const stream = this;
2678
2737
  let crc32Stream, encryptionStream, gzipCrc32Stream;
2679
2738
  let readable = super.readable;
2680
- const useGzipCrc32 = signed && compressed && !deflate64 && (!encrypted || zipCrypto) &&
2739
+ const codecStreams = format && getCodecStreams(format);
2740
+ const useGzipCrc32 = signed && compressed && !deflate64 && !codecStreams && (!encrypted || zipCrypto) &&
2681
2741
  Boolean(useCompressionStream && CompressionStream);
2682
2742
  if ((!encrypted || zipCrypto) && signed && !useGzipCrc32) {
2683
2743
  crc32Stream = new Crc32Stream();
2684
2744
  readable = pipeThrough(readable, crc32Stream);
2685
2745
  }
2686
2746
  if (compressed) {
2687
- if (useGzipCrc32) {
2747
+ if (codecStreams) {
2748
+ readable = pipeThroughBackpressured(readable, createCodecStream(codecStreams.CompressionStream, format, { level, chunkSize }));
2749
+ } else if (useGzipCrc32) {
2688
2750
  gzipCrc32Stream = new GzipToRawDeflateStream();
2689
2751
  readable = pipeThroughBackpressured(readable, new CompressionStream(FORMAT_GZIP));
2690
2752
  readable = pipeThrough(readable, gzipCrc32Stream);
2691
2753
  } else {
2692
- readable = pipeThroughCommpressionStream(readable, useCompressionStream, { level, chunkSize }, CompressionStream, CompressionStreamZlib, CompressionStream);
2754
+ readable = pipeThroughCompressionStream(readable, useCompressionStream, { level, chunkSize }, CompressionStream, CompressionStreamZlib);
2693
2755
  }
2694
2756
  }
2695
2757
  if (encrypted) {
@@ -2758,7 +2820,7 @@
2758
2820
 
2759
2821
  constructor(options, { chunkSize, DecompressionStreamZlib, DecompressionStream }) {
2760
2822
  super({});
2761
- const { zipCrypto, encrypted, signed, signature, compressed, useCompressionStream, deflate64 } = options;
2823
+ const { zipCrypto, encrypted, signed, signature, compressed, useCompressionStream, deflate64, format } = options;
2762
2824
  let crc32Stream, decryptionStream;
2763
2825
  let readable = super.readable;
2764
2826
  if (encrypted) {
@@ -2770,7 +2832,12 @@
2770
2832
  }
2771
2833
  }
2772
2834
  if (compressed) {
2773
- readable = pipeThroughCommpressionStream(readable, useCompressionStream, { chunkSize, deflate64 }, DecompressionStream, DecompressionStreamZlib, DecompressionStream);
2835
+ const codecStreams = format && getCodecStreams(format);
2836
+ if (codecStreams) {
2837
+ readable = pipeThroughBackpressured(readable, createCodecStream(codecStreams.DecompressionStream, format, { chunkSize }));
2838
+ } else {
2839
+ readable = pipeThroughCompressionStream(readable, useCompressionStream, { chunkSize, deflate64 }, DecompressionStream, DecompressionStreamZlib);
2840
+ }
2774
2841
  readable = mapInflateStreamError(readable);
2775
2842
  }
2776
2843
  if ((!encrypted || zipCrypto) && signed) {
@@ -2788,6 +2855,25 @@
2788
2855
  }
2789
2856
  }
2790
2857
 
2858
+ const deflateRawSupportByStream = new Map();
2859
+
2860
+ function supportsDeflateRaw(StreamClass) {
2861
+ if (!StreamClass) {
2862
+ return false;
2863
+ }
2864
+ let supported = deflateRawSupportByStream.get(StreamClass);
2865
+ if (supported === UNDEFINED_VALUE) {
2866
+ try {
2867
+ new StreamClass(FORMAT_DEFLATE_RAW);
2868
+ supported = true;
2869
+ } catch {
2870
+ supported = false;
2871
+ }
2872
+ deflateRawSupportByStream.set(StreamClass, supported);
2873
+ }
2874
+ return supported;
2875
+ }
2876
+
2791
2877
  function setReadable(stream, readable, flush) {
2792
2878
  readable = pipeThrough(readable, new TransformStream({ flush }));
2793
2879
  Object.defineProperty(stream, "readable", {
@@ -2797,21 +2883,24 @@
2797
2883
  });
2798
2884
  }
2799
2885
 
2800
- function pipeThroughCommpressionStream(readable, useCompressionStream, options, CompressionStreamNative, CompressionStreamZlib, CompressionStream) {
2801
- const Stream = useCompressionStream && CompressionStreamNative ? CompressionStreamNative : CompressionStreamZlib || CompressionStream;
2886
+ function createCodecStream(CodecStreamClass, format, options) {
2887
+ if (!CodecStreamClass) {
2888
+ throw new Error(ERR_UNSUPPORTED_COMPRESSION$2);
2889
+ }
2890
+ return new CodecStreamClass(format, options);
2891
+ }
2892
+
2893
+ function pipeThroughCompressionStream(readable, useCompressionStream, options, CompressionStreamNative, CompressionStreamZlib) {
2894
+ const Stream = useCompressionStream && CompressionStreamNative ?
2895
+ CompressionStreamNative :
2896
+ CompressionStreamZlib || CompressionStreamNative;
2802
2897
  const format = options.deflate64 ? FORMAT_DEFLATE64_RAW : FORMAT_DEFLATE_RAW;
2803
2898
  let codecStream;
2804
2899
  try {
2805
2900
  codecStream = new Stream(format, options);
2806
2901
  } catch (error) {
2807
- if (useCompressionStream) {
2808
- if (CompressionStreamZlib) {
2809
- codecStream = new CompressionStreamZlib(format, options);
2810
- } else if (CompressionStream) {
2811
- codecStream = new CompressionStream(format, options);
2812
- } else {
2813
- throw error;
2814
- }
2902
+ if (useCompressionStream && CompressionStreamZlib && Stream != CompressionStreamZlib) {
2903
+ codecStream = new CompressionStreamZlib(format, options);
2815
2904
  } else {
2816
2905
  throw error;
2817
2906
  }
@@ -3072,6 +3161,7 @@
3072
3161
  const MODULE_WORKER_OPTIONS = { type: "module" };
3073
3162
  const ERROR_EVENT_TYPE = "error";
3074
3163
  const MESSAGE_ERROR_EVENT_TYPE = "messageerror";
3164
+ const ERR_WORKER_STARTUP_TIMEOUT = "Worker startup timeout";
3075
3165
 
3076
3166
  let webWorkerSupported, webWorkerSource, webWorkerURI, webWorkerOptions;
3077
3167
  let transferStreamsSupported = true;
@@ -3175,7 +3265,7 @@
3175
3265
  }
3176
3266
 
3177
3267
  function createWebWorkerInterface(workerData, config) {
3178
- const { baseURI, chunkSize } = config;
3268
+ const { baseURI, chunkSize, workerStartupTimeout } = config;
3179
3269
  let { wasmURI } = config;
3180
3270
 
3181
3271
  if (!workerData.interface) {
@@ -3192,9 +3282,26 @@
3192
3282
  }
3193
3283
  Object.assign(workerData, {
3194
3284
  worker,
3285
+ workerAlive: false,
3195
3286
  terminated: false,
3196
3287
  interface: {
3197
- run: () => runWebWorker(workerData, { chunkSize, wasmURI, baseURI })
3288
+ run: async () => {
3289
+ try {
3290
+ return await runWebWorker(workerData, { chunkSize, wasmURI, baseURI, workerStartupTimeout });
3291
+ } catch (error) {
3292
+ if (error && error.workerStartupFailed) {
3293
+ webWorkerSupported = false;
3294
+ const { reader } = workerData;
3295
+ if (reader) {
3296
+ reader.releaseLock();
3297
+ }
3298
+ workerData.reader = null;
3299
+ workerData.writer = null;
3300
+ return runWorker$1(workerData, config);
3301
+ }
3302
+ throw error;
3303
+ }
3304
+ }
3198
3305
  }
3199
3306
  });
3200
3307
  }
@@ -3204,15 +3311,23 @@
3204
3311
  async function runWorker$1({ options, readable, writable, onTaskFinished }, config) {
3205
3312
  let codecStream;
3206
3313
  try {
3207
- if (!options.useCompressionStream) {
3208
- try {
3209
- await initModule(config);
3210
- } catch {
3211
- const ZlibStream = options.codecType.startsWith(CODEC_DEFLATE) ?
3212
- config.CompressionStreamZlib :
3213
- config.DecompressionStreamZlib;
3214
- if (!ZlibStream || ZlibStream.requiresModule) {
3215
- options.useCompressionStream = true;
3314
+ if (options.compressed && !options.format) {
3315
+ const deflate = options.codecType.startsWith(CODEC_DEFLATE);
3316
+ const ZlibStream = deflate ? config.CompressionStreamZlib : config.DecompressionStreamZlib;
3317
+ const NativeStream = deflate ? config.CompressionStream : config.DecompressionStream;
3318
+ if (!options.useCompressionStream) {
3319
+ try {
3320
+ await initModule(config);
3321
+ } catch {
3322
+ if (!ZlibStream || ZlibStream.requiresModule) {
3323
+ options.useCompressionStream = true;
3324
+ }
3325
+ }
3326
+ } else if (ZlibStream && ZlibStream.requiresModule && !supportsDeflateRaw(NativeStream)) {
3327
+ try {
3328
+ await initModule(config);
3329
+ } catch {
3330
+ // ignored
3216
3331
  }
3217
3332
  }
3218
3333
  }
@@ -3281,6 +3396,10 @@
3281
3396
  writer: writable.getWriter()
3282
3397
  });
3283
3398
  }
3399
+ const { workerStartupTimeout } = config;
3400
+ if (!workerData.workerAlive && Number.isFinite(workerStartupTimeout) && workerStartupTimeout >= 0) {
3401
+ workerData.startupTimeout = setTimeout(() => onStartupTimeout(workerData), workerStartupTimeout);
3402
+ }
3284
3403
  try {
3285
3404
  const resultValue = await result;
3286
3405
  await closeWritable();
@@ -3393,28 +3512,68 @@
3393
3512
  } else {
3394
3513
  worker = new Worker(webWorkerURI, webWorkerOptions);
3395
3514
  }
3396
- worker.addEventListener(MESSAGE_EVENT_TYPE, event => onMessage(event, workerData));
3515
+ worker.addEventListener(MESSAGE_EVENT_TYPE, event => {
3516
+ workerData.workerAlive = true;
3517
+ clearStartupTimeout(workerData);
3518
+ onMessage(event, workerData);
3519
+ });
3397
3520
  worker.addEventListener(ERROR_EVENT_TYPE, event => onWorkerError(event, workerData));
3398
3521
  worker.addEventListener(MESSAGE_ERROR_EVENT_TYPE, event => onWorkerError(event, workerData));
3399
3522
  return worker;
3400
3523
  }
3401
3524
 
3525
+ function onStartupTimeout(workerData) {
3526
+ workerData.startupTimeout = null;
3527
+ if (workerData.workerAlive) {
3528
+ return;
3529
+ }
3530
+ const { rejectResult, writer } = workerData;
3531
+ terminateWorker$1(workerData);
3532
+ workerData.worker = null;
3533
+ if (rejectResult) {
3534
+ const error = new Error(ERR_WORKER_STARTUP_TIMEOUT);
3535
+ error.workerStartupFailed = true;
3536
+ rejectResult(error);
3537
+ if (writer) {
3538
+ writer.releaseLock();
3539
+ }
3540
+ }
3541
+ }
3542
+
3543
+ function clearStartupTimeout(workerData) {
3544
+ const { startupTimeout } = workerData;
3545
+ if (startupTimeout) {
3546
+ clearTimeout(startupTimeout);
3547
+ workerData.startupTimeout = null;
3548
+ }
3549
+ }
3550
+
3402
3551
  function onWorkerError(event, workerData) {
3403
3552
  if (event.preventDefault) {
3404
3553
  event.preventDefault();
3405
3554
  }
3406
- const { rejectResult, writer, onTaskFinished } = workerData;
3555
+ clearStartupTimeout(workerData);
3556
+ const { workerAlive, rejectResult, writer, onTaskFinished } = workerData;
3407
3557
  terminateWorker$1(workerData);
3558
+ if (!workerAlive) {
3559
+ workerData.worker = null;
3560
+ }
3408
3561
  if (rejectResult) {
3409
- rejectResult(event.error || new Error(event.message || ERROR_EVENT_TYPE));
3562
+ let error = event.error || new Error(event.message || ERROR_EVENT_TYPE);
3563
+ if (!workerAlive) {
3564
+ error = Object.assign(new Error(error.message || ERROR_EVENT_TYPE), { workerStartupFailed: true });
3565
+ }
3566
+ rejectResult(error);
3410
3567
  if (writer) {
3411
3568
  writer.releaseLock();
3412
3569
  }
3413
- onTaskFinished();
3570
+ if (workerAlive) {
3571
+ onTaskFinished();
3572
+ }
3414
3573
  }
3415
3574
  }
3416
3575
 
3417
- function sendMessage(message, { worker, writer, transferStreams }) {
3576
+ function sendMessage(message, { worker, writer, transferStreams, workerAlive }) {
3418
3577
  try {
3419
3578
  const { value, readable, writable } = message;
3420
3579
  const transferables = [];
@@ -3422,7 +3581,7 @@
3422
3581
  message.value = toExactUint8Array(value);
3423
3582
  transferables.push(message.value.buffer);
3424
3583
  }
3425
- if (transferStreams && transferStreamsSupported) {
3584
+ if (transferStreams && transferStreamsSupported && workerAlive) {
3426
3585
  if (readable) {
3427
3586
  transferables.push(readable);
3428
3587
  }
@@ -3541,11 +3700,18 @@
3541
3700
 
3542
3701
  async function runWorker(stream, workerOptions) {
3543
3702
  const { options, config } = workerOptions;
3544
- const { transferStreams, useWebWorkers, useCompressionStream, compressed, signed, encrypted } = options;
3703
+ const { transferStreams, useWebWorkers, useCompressionStream, compressed, signed, encrypted, format, codecURI } = options;
3545
3704
  const { workerURI, maxWorkers } = config;
3705
+ if (format) {
3706
+ if (codecURI) {
3707
+ options.codecURI = resolveCodecURI(codecURI, config.baseURI);
3708
+ }
3709
+ await ensureCodecStreams(format, options.codecURI);
3710
+ }
3546
3711
  workerOptions.transferStreams = transferStreams || (transferStreams === UNDEFINED_VALUE && config.transferStreams);
3547
3712
  const streamCopy = !compressed && !signed && !encrypted;
3548
- workerOptions.useWebWorkers = !streamCopy && (useWebWorkers || (useWebWorkers === UNDEFINED_VALUE && config.useWebWorkers));
3713
+ const workerSupported = format === UNDEFINED_VALUE || Boolean(options.codecURI);
3714
+ workerOptions.useWebWorkers = !streamCopy && workerSupported && (useWebWorkers || (useWebWorkers === UNDEFINED_VALUE && config.useWebWorkers));
3549
3715
  workerOptions.workerURI = workerOptions.useWebWorkers && workerURI ? workerURI : UNDEFINED_VALUE;
3550
3716
  options.useCompressionStream = useCompressionStream || (useCompressionStream === UNDEFINED_VALUE && config.useCompressionStream);
3551
3717
  return (await getWorker()).run();
@@ -3585,6 +3751,14 @@
3585
3751
  }
3586
3752
  }
3587
3753
 
3754
+ function resolveCodecURI(codecURI, baseURI) {
3755
+ try {
3756
+ return new URL(codecURI, baseURI).toString();
3757
+ } catch {
3758
+ return codecURI;
3759
+ }
3760
+ }
3761
+
3588
3762
  function armStarvationTimeout() {
3589
3763
  if (!starvationTimeout && pendingRequests.length && Number.isFinite(starvationDelay) && starvationDelay >= 0) {
3590
3764
  starvationTimeout = setTimeout(onWorkerStarvation, starvationDelay);
@@ -3903,6 +4077,7 @@
3903
4077
  const OPTION_PREVENT_CLOSE = "preventClose";
3904
4078
  const OPTION_ENCRYPTION_STRENGTH = "encryptionStrength";
3905
4079
  const OPTION_EXTENDED_TIMESTAMP = "extendedTimestamp";
4080
+ const OPTION_NTFS_TIMESTAMP = "ntfsTimestamp";
3906
4081
  const OPTION_KEEP_ORDER = "keepOrder";
3907
4082
  const OPTION_LEVEL = "level";
3908
4083
  const OPTION_BUFFERED_WRITE = "bufferedWrite";
@@ -3962,6 +4137,7 @@
3962
4137
  const ERR_SPLIT_ZIP_FILE = "Split zip file";
3963
4138
  const ERR_OVERLAPPING_ENTRY = "Overlapping entry found";
3964
4139
  const ERR_AMBIGUOUS_ARCHIVE = "Ambiguous archive";
4140
+ const ERR_ENCRYPTED_CENTRAL_DIRECTORY = "Encrypted central directory is not supported";
3965
4141
  const CHARSET_UTF8 = "utf-8";
3966
4142
  const PROPERTY_NAME_UTF8_SUFFIX = "UTF8";
3967
4143
  const CHARSET_CP437 = "cp437";
@@ -4039,6 +4215,7 @@
4039
4215
  let prependedDataLength = 0;
4040
4216
  let startOffset;
4041
4217
  let zip64EndOfDirectory;
4218
+ let zip64EndOfDirectoryVersion2;
4042
4219
  const requiresZip64 = directoryDataOffset == MAX_32_BITS || directoryDataLength == MAX_32_BITS || filesLength == MAX_16_BITS || diskNumber == MAX_16_BITS;
4043
4220
  if (directoryDataOffset != MAX_32_BITS && diskNumber != MAX_16_BITS) {
4044
4221
  directoryDataOffset += getDiskOffset$1(reader, diskNumber);
@@ -4068,6 +4245,7 @@
4068
4245
  throw new Error(ERR_EOCDR_LOCATOR_ZIP64_NOT_FOUND);
4069
4246
  }
4070
4247
  zip64EndOfDirectory = true;
4248
+ zip64EndOfDirectoryVersion2 = getBigUint64(endOfDirectoryView, 4) > ZIP64_END_OF_CENTRAL_DIR_LENGTH - 12;
4071
4249
  if (lastDiskNumber == MAX_16_BITS) {
4072
4250
  lastDiskNumber = getUint32(endOfDirectoryView, 16);
4073
4251
  } else if (checkAmbiguity && lastDiskNumber != getUint32(endOfDirectoryView, 16)) {
@@ -4147,6 +4325,9 @@
4147
4325
  for (let indexFile = 0; indexFile < filesLength; indexFile++) {
4148
4326
  const fileEntry = new ZipEntry$1(reader, config, zipReader.options);
4149
4327
  if (offset + CENTRAL_FILE_HEADER_LENGTH > directoryArray.length || getUint32(directoryView, offset) != CENTRAL_FILE_HEADER_SIGNATURE) {
4328
+ if (indexFile == 0 && (zip64EndOfDirectoryVersion2 || detectEncryptedCentralDirectory(directoryView))) {
4329
+ throw new Error(ERR_ENCRYPTED_CENTRAL_DIRECTORY);
4330
+ }
4150
4331
  throw new Error(ERR_CENTRAL_DIRECTORY_NOT_FOUND);
4151
4332
  }
4152
4333
  readCommonHeader(fileEntry, directoryView, offset + 6);
@@ -4334,7 +4515,8 @@
4334
4515
  throw new Error(ERR_UNSUPPORTED_COMPRESSION$1);
4335
4516
  }
4336
4517
  }
4337
- if ((compressionMethod != COMPRESSION_METHOD_STORE && compressionMethod != COMPRESSION_METHOD_DEFLATE && compressionMethod != COMPRESSION_METHOD_DEFLATE_64) && !passThrough) {
4518
+ const registeredCodec = passThrough ? UNDEFINED_VALUE : getRegisteredCodec(compressionMethod);
4519
+ if ((compressionMethod != COMPRESSION_METHOD_STORE && compressionMethod != COMPRESSION_METHOD_DEFLATE && compressionMethod != COMPRESSION_METHOD_DEFLATE_64 && !registeredCodec) && !passThrough) {
4338
4520
  throw new Error(ERR_UNSUPPORTED_COMPRESSION$1);
4339
4521
  }
4340
4522
  if (dataArray.length < HEADER_SIZE || getUint32(dataView, 0) != LOCAL_FILE_HEADER_SIGNATURE) {
@@ -4373,7 +4555,10 @@
4373
4555
  fileEntry.zipCrypto = zipCrypto;
4374
4556
  }
4375
4557
  if (encrypted) {
4376
- if (!zipCrypto && extraFieldAES.strength === UNDEFINED_VALUE) {
4558
+ if ((localDirectory.rawBitFlag & BITFLAG_STRONG_ENCRYPTION) == BITFLAG_STRONG_ENCRYPTION) {
4559
+ throw new Error(ERR_UNSUPPORTED_ENCRYPTION);
4560
+ }
4561
+ if (!zipCrypto && (extraFieldAES.strength < 1 || extraFieldAES.strength > 3)) {
4377
4562
  throw new Error(ERR_UNSUPPORTED_ENCRYPTION);
4378
4563
  } else if (!password && !rawPassword) {
4379
4564
  throw new Error(ERR_ENCRYPTED);
@@ -4412,6 +4597,8 @@
4412
4597
  useCompressionStream,
4413
4598
  transferStreams: getOptionValue$1(zipEntry, options, OPTION_TRANSFER_STREAMS),
4414
4599
  deflate64,
4600
+ format: registeredCodec ? registeredCodec.format : UNDEFINED_VALUE,
4601
+ codecURI: registeredCodec ? registeredCodec.codecURI : UNDEFINED_VALUE,
4415
4602
  checkPasswordOnly
4416
4603
  },
4417
4604
  config,
@@ -4464,6 +4651,16 @@
4464
4651
  }
4465
4652
  };
4466
4653
 
4654
+ function detectEncryptedCentralDirectory(directoryView) {
4655
+ const maxOffset = Math.min(directoryView.byteLength, 1024) - 3;
4656
+ for (let offset = 0; offset < maxOffset; offset++) {
4657
+ if (getUint32(directoryView, offset) == ARCHIVE_EXTRA_DATA_SIGNATURE) {
4658
+ return true;
4659
+ }
4660
+ }
4661
+ return false;
4662
+ }
4663
+
4467
4664
  function readCommonHeader(directory, dataView, offset) {
4468
4665
  const rawBitFlag = directory.rawBitFlag = getUint16(dataView, offset + 2);
4469
4666
  const encrypted = (rawBitFlag & BITFLAG_ENCRYPTED) == BITFLAG_ENCRYPTED;
@@ -4978,6 +5175,7 @@
4978
5175
  ERR_BAD_FORMAT: ERR_BAD_FORMAT,
4979
5176
  ERR_CENTRAL_DIRECTORY_NOT_FOUND: ERR_CENTRAL_DIRECTORY_NOT_FOUND,
4980
5177
  ERR_ENCRYPTED: ERR_ENCRYPTED,
5178
+ ERR_ENCRYPTED_CENTRAL_DIRECTORY: ERR_ENCRYPTED_CENTRAL_DIRECTORY,
4981
5179
  ERR_EOCDR_LOCATOR_ZIP64_NOT_FOUND: ERR_EOCDR_LOCATOR_ZIP64_NOT_FOUND,
4982
5180
  ERR_EOCDR_NOT_FOUND: ERR_EOCDR_NOT_FOUND,
4983
5181
  ERR_EXTRAFIELD_ZIP64_NOT_FOUND: ERR_EXTRAFIELD_ZIP64_NOT_FOUND,
@@ -5028,6 +5226,7 @@
5028
5226
  const ERR_INVALID_ENTRY_NAME = "File entry name exceeds 64KB";
5029
5227
  const ERR_INVALID_VERSION = "Version exceeds 65535";
5030
5228
  const ERR_INVALID_ENCRYPTION_STRENGTH = "The strength must equal 1, 2, or 3";
5229
+ const ERR_UNSUPPORTED_ENCRYPTION_USDZ = "Encryption is not supported in USDZ files";
5031
5230
  const ERR_INVALID_EXTRAFIELD_TYPE = "Extra field type exceeds 65535";
5032
5231
  const ERR_INVALID_EXTRAFIELD_DATA = "Extra field data exceeds 64KB";
5033
5232
  const ERR_UNSUPPORTED_COMPRESSION = "Compression method not supported";
@@ -5326,7 +5525,11 @@
5326
5525
  if (versionMadeBy > MAX_16_BITS) {
5327
5526
  throw new Error(ERR_INVALID_VERSION);
5328
5527
  }
5329
- let externalFileAttributes = getOptionValue(zipWriter, options, PROPERTY_NAME_EXTERNAL_FILE_ATTRIBUTES, 0);
5528
+ let externalFileAttributes = getOptionValue(zipWriter, options, PROPERTY_NAME_EXTERNAL_FILE_ATTRIBUTES);
5529
+ const externalFileAttributesProvided = externalFileAttributes !== UNDEFINED_VALUE;
5530
+ if (!externalFileAttributesProvided) {
5531
+ externalFileAttributes = 0;
5532
+ }
5330
5533
  if (!options[PROPERTY_NAME_DIRECTORY] && name.endsWith(DIRECTORY_SIGNATURE)) {
5331
5534
  options[PROPERTY_NAME_DIRECTORY] = true;
5332
5535
  }
@@ -5335,13 +5538,13 @@
5335
5538
  if (!name.endsWith(DIRECTORY_SIGNATURE)) {
5336
5539
  name += DIRECTORY_SIGNATURE;
5337
5540
  }
5338
- if (externalFileAttributes === 0) {
5541
+ if (!externalFileAttributesProvided) {
5339
5542
  externalFileAttributes = FILE_ATTR_MSDOS_DIR_MASK;
5340
5543
  if (!msDosCompatible) {
5341
5544
  externalFileAttributes |= (FILE_ATTR_UNIX_TYPE_DIR | FILE_ATTR_UNIX_EXECUTABLE_MASK | FILE_ATTR_UNIX_DEFAULT_MASK) << 16;
5342
5545
  }
5343
5546
  }
5344
- } else if (!msDosCompatible && externalFileAttributes === 0) {
5547
+ } else if (!msDosCompatible && !externalFileAttributesProvided) {
5345
5548
  if (executable) {
5346
5549
  externalFileAttributes = (FILE_ATTR_UNIX_EXECUTABLE_MASK | FILE_ATTR_UNIX_DEFAULT_MASK) << 16;
5347
5550
  } else {
@@ -5350,6 +5553,7 @@
5350
5553
  }
5351
5554
  let unixExternalUpper;
5352
5555
  if (!msDosCompatible) {
5556
+ const unixModeProvided = unixMode !== UNDEFINED_VALUE || Boolean(setuid || setgid || sticky);
5353
5557
  unixExternalUpper = (externalFileAttributes >> 16) & MAX_16_BITS;
5354
5558
  unixMode = unixMode === UNDEFINED_VALUE ? unixExternalUpper : (unixMode & MAX_16_BITS);
5355
5559
  if (setuid) {
@@ -5367,10 +5571,12 @@
5367
5571
  } else {
5368
5572
  sticky = Boolean(unixMode & FILE_ATTR_UNIX_STICKY_MASK);
5369
5573
  }
5370
- if (directory) {
5371
- unixMode |= FILE_ATTR_UNIX_TYPE_DIR;
5574
+ if (!externalFileAttributesProvided || unixModeProvided) {
5575
+ if (directory) {
5576
+ unixMode |= FILE_ATTR_UNIX_TYPE_DIR;
5577
+ }
5578
+ externalFileAttributes = ((unixMode & MAX_16_BITS) << 16) | (externalFileAttributes & MAX_16_BITS);
5372
5579
  }
5373
- externalFileAttributes = ((unixMode & MAX_16_BITS) << 16) | (externalFileAttributes & MAX_8_BITS);
5374
5580
  }
5375
5581
  ({ msdosAttributesRaw, msdosAttributes } = normalizeMsdosAttributes(msdosAttributesRaw, msdosAttributes));
5376
5582
  if (hasMsDosProvided) {
@@ -5430,6 +5636,7 @@
5430
5636
  const encryptionStrength = getOptionValue(zipWriter, options, OPTION_ENCRYPTION_STRENGTH, 3);
5431
5637
  const zipCrypto = getOptionValue(zipWriter, options, PROPERTY_NAME_ZIPCRYPTO);
5432
5638
  const extendedTimestamp = getOptionValue(zipWriter, options, OPTION_EXTENDED_TIMESTAMP, true);
5639
+ const ntfsTimestamp = getOptionValue(zipWriter, options, OPTION_NTFS_TIMESTAMP);
5433
5640
  const keepOrder = getOptionValue(zipWriter, options, OPTION_KEEP_ORDER, true);
5434
5641
  const useWebWorkers = getOptionValue(zipWriter, options, OPTION_USE_WEB_WORKERS);
5435
5642
  const transferStreams = getOptionValue(zipWriter, options, OPTION_TRANSFER_STREAMS);
@@ -5439,11 +5646,20 @@
5439
5646
  const signal = getOptionValue(zipWriter, options, OPTION_SIGNAL);
5440
5647
  const useUnicodeFileNames = getOptionValue(zipWriter, options, OPTION_USE_UNICODE_FILE_NAMES, true);
5441
5648
  const compressionMethod = getOptionValue(zipWriter, options, PROPERTY_NAME_COMPRESSION_METHOD);
5649
+ const registeredCodec = passThrough || compressionMethod === UNDEFINED_VALUE ? UNDEFINED_VALUE : getRegisteredCodec(compressionMethod);
5442
5650
  if (!passThrough && compressionMethod !== UNDEFINED_VALUE &&
5443
- compressionMethod !== COMPRESSION_METHOD_STORE && compressionMethod !== COMPRESSION_METHOD_DEFLATE) {
5651
+ compressionMethod !== COMPRESSION_METHOD_STORE && compressionMethod !== COMPRESSION_METHOD_DEFLATE && !registeredCodec) {
5444
5652
  throw new Error(ERR_UNSUPPORTED_COMPRESSION);
5445
5653
  }
5446
5654
  let level = getOptionValue(zipWriter, options, OPTION_LEVEL);
5655
+ if (zipWriter.options[OPTION_USDZ]) {
5656
+ if (password !== UNDEFINED_VALUE || rawPassword !== UNDEFINED_VALUE) {
5657
+ throw new Error(ERR_UNSUPPORTED_ENCRYPTION_USDZ);
5658
+ }
5659
+ if (level === UNDEFINED_VALUE && compressionMethod === UNDEFINED_VALUE) {
5660
+ level = 0;
5661
+ }
5662
+ }
5447
5663
  let useCompressionStream = getOptionValue(zipWriter, options, OPTION_USE_COMPRESSION_STREAM);
5448
5664
  let dataDescriptor = getOptionValue(zipWriter, options, OPTION_DATA_DESCRIPTOR);
5449
5665
  if (bufferedWrite && dataDescriptor === UNDEFINED_VALUE) {
@@ -5455,7 +5671,7 @@
5455
5671
  if (level !== UNDEFINED_VALUE && level != 6) {
5456
5672
  useCompressionStream = false;
5457
5673
  }
5458
- if (!useCompressionStream && (zipWriter.config.CompressionStream === UNDEFINED_VALUE && zipWriter.config.CompressionStreamZlib === UNDEFINED_VALUE)) {
5674
+ if (!useCompressionStream && !registeredCodec && (zipWriter.config.CompressionStream === UNDEFINED_VALUE && zipWriter.config.CompressionStreamZlib === UNDEFINED_VALUE)) {
5459
5675
  level = 0;
5460
5676
  }
5461
5677
  const zip64 = getOptionValue(zipWriter, options, PROPERTY_NAME_ZIP64);
@@ -5499,6 +5715,7 @@
5499
5715
  encryptionStrength,
5500
5716
  zipCrypto,
5501
5717
  extendedTimestamp,
5718
+ ntfsTimestamp,
5502
5719
  keepOrder,
5503
5720
  useWebWorkers,
5504
5721
  transferStreams,
@@ -5508,6 +5725,9 @@
5508
5725
  signal,
5509
5726
  useUnicodeFileNames,
5510
5727
  compressionMethod,
5728
+ format: registeredCodec ? registeredCodec.format : UNDEFINED_VALUE,
5729
+ codecURI: registeredCodec ? registeredCodec.codecURI : UNDEFINED_VALUE,
5730
+ codecVersionNeeded: registeredCodec ? registeredCodec.versionNeeded : UNDEFINED_VALUE,
5511
5731
  level,
5512
5732
  useCompressionStream,
5513
5733
  dataDescriptor,
@@ -5804,7 +6024,9 @@
5804
6024
  msdosAttributesRaw,
5805
6025
  msdosAttributes,
5806
6026
  useCompressionStream,
5807
- passThrough
6027
+ passThrough,
6028
+ format,
6029
+ codecURI
5808
6030
  } = options;
5809
6031
  const fileEntry = {
5810
6032
  lock,
@@ -5864,7 +6086,9 @@
5864
6086
  encrypted: encrypted && !passThrough,
5865
6087
  useWebWorkers,
5866
6088
  useCompressionStream,
5867
- transferStreams
6089
+ transferStreams,
6090
+ format,
6091
+ codecURI
5868
6092
  },
5869
6093
  config,
5870
6094
  streamOptions: { signal, size, onstart, onprogress, onend }
@@ -5936,6 +6160,7 @@
5936
6160
  rawExtraField,
5937
6161
  encryptionStrength,
5938
6162
  extendedTimestamp,
6163
+ ntfsTimestamp,
5939
6164
  passThrough,
5940
6165
  encrypted,
5941
6166
  zip64UncompressedSize,
@@ -5981,7 +6206,8 @@
5981
6206
  let extraFieldExtendedTimestampFlag;
5982
6207
  if (extendedTimestamp) {
5983
6208
  const lastModTimeUnix = getTimeUnix(lastModDate);
5984
- if (inUnixTimeRange(lastModTimeUnix)) {
6209
+ const lastModTimeUnixInRange = inUnixTimeRange(lastModTimeUnix);
6210
+ if (lastModTimeUnixInRange) {
5985
6211
  const extraFieldTimestampLength = 9 + (lastAccessDate ? 4 : 0) + (creationDate ? 4 : 0);
5986
6212
  const extraFieldTimestamp = createRecordWriter(extraFieldTimestampLength);
5987
6213
  extraFieldExtendedTimestampFlag = 0x1 + (lastAccessDate ? 0x2 : 0) + (creationDate ? 0x4 : 0);
@@ -5999,19 +6225,26 @@
5999
6225
  } else {
6000
6226
  rawExtraFieldExtendedTimestamp = EMPTY_UINT8_ARRAY;
6001
6227
  }
6002
- try {
6003
- const lastModTimeNTFS = getTimeNTFS(lastModDate);
6004
- const extraFieldNTFS = createRecordWriter(36);
6005
- extraFieldNTFS.uint16(EXTRAFIELD_TYPE_NTFS);
6006
- extraFieldNTFS.uint16(32);
6007
- extraFieldNTFS.skip(4);
6008
- extraFieldNTFS.uint16(EXTRAFIELD_TYPE_NTFS_TAG1);
6009
- extraFieldNTFS.uint16(24);
6010
- extraFieldNTFS.uint64(lastModTimeNTFS);
6011
- extraFieldNTFS.uint64(getTimeNTFS(lastAccessDate) || lastModTimeNTFS);
6012
- extraFieldNTFS.uint64(getTimeNTFS(creationDate) || lastModTimeNTFS);
6013
- rawExtraFieldNTFS = extraFieldNTFS.array;
6014
- } catch {
6228
+ const writeExtraFieldNTFS = ntfsTimestamp === UNDEFINED_VALUE ?
6229
+ !lastModTimeUnixInRange || Boolean(lastAccessDate || creationDate) :
6230
+ ntfsTimestamp;
6231
+ if (writeExtraFieldNTFS) {
6232
+ try {
6233
+ const lastModTimeNTFS = getTimeNTFS(lastModDate);
6234
+ const extraFieldNTFS = createRecordWriter(36);
6235
+ extraFieldNTFS.uint16(EXTRAFIELD_TYPE_NTFS);
6236
+ extraFieldNTFS.uint16(32);
6237
+ extraFieldNTFS.skip(4);
6238
+ extraFieldNTFS.uint16(EXTRAFIELD_TYPE_NTFS_TAG1);
6239
+ extraFieldNTFS.uint16(24);
6240
+ extraFieldNTFS.uint64(lastModTimeNTFS);
6241
+ extraFieldNTFS.uint64(getTimeNTFS(lastAccessDate) || lastModTimeNTFS);
6242
+ extraFieldNTFS.uint64(getTimeNTFS(creationDate) || lastModTimeNTFS);
6243
+ rawExtraFieldNTFS = extraFieldNTFS.array;
6244
+ } catch {
6245
+ rawExtraFieldNTFS = EMPTY_UINT8_ARRAY;
6246
+ }
6247
+ } else {
6015
6248
  rawExtraFieldNTFS = EMPTY_UINT8_ARRAY;
6016
6249
  }
6017
6250
  } else {
@@ -6049,6 +6282,10 @@
6049
6282
  if (compressionMethod === UNDEFINED_VALUE) {
6050
6283
  compressionMethod = compressed ? COMPRESSION_METHOD_DEFLATE : COMPRESSION_METHOD_STORE;
6051
6284
  }
6285
+ const { codecVersionNeeded } = options;
6286
+ if (compressed && codecVersionNeeded !== UNDEFINED_VALUE) {
6287
+ version = version > codecVersionNeeded ? version : codecVersionNeeded;
6288
+ }
6052
6289
  if (zip64) {
6053
6290
  version = version > VERSION_ZIP64 ? version : VERSION_ZIP64;
6054
6291
  }
@@ -6062,6 +6299,7 @@
6062
6299
  if (extraFieldLength > MAX_16_BITS) {
6063
6300
  throw new Error(ERR_INVALID_EXTRAFIELD_DATA);
6064
6301
  }
6302
+ const dosLastModDate = new Date(Math.ceil(lastModDate.getTime() / 2000) * 2000);
6065
6303
  const {
6066
6304
  headerArray,
6067
6305
  headerView,
@@ -6071,7 +6309,7 @@
6071
6309
  bitFlag: getBitFlag(level, useUnicodeFileNames, dataDescriptor, encrypted, compressionMethod),
6072
6310
  compressionMethod,
6073
6311
  uncompressedSize,
6074
- lastModDate: lastModDate < MIN_DATE ? MIN_DATE : lastModDate > MAX_DATE ? MAX_DATE : lastModDate,
6312
+ lastModDate: dosLastModDate < MIN_DATE ? MIN_DATE : dosLastModDate > MAX_DATE ? MAX_DATE : dosLastModDate,
6075
6313
  rawFilename,
6076
6314
  zip64CompressedSize,
6077
6315
  zip64UncompressedSize,