@zip.js/zip.js 2.8.36 → 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.
@@ -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;
@@ -1171,6 +1171,61 @@
1171
1171
  return reader.readUint8Array(offset, size);
1172
1172
  }
1173
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
+
1174
1229
  /*
1175
1230
  Copyright (c) 2022 Gildas Lormeau. All rights reserved.
1176
1231
 
@@ -2663,6 +2718,7 @@
2663
2718
 
2664
2719
  const ERR_INVALID_UNCOMPRESSED_SIZE = "Invalid uncompressed size";
2665
2720
  const ERR_INVALID_COMPRESSED_DATA = "Invalid compressed data";
2721
+ const ERR_UNSUPPORTED_COMPRESSION$2 = "Compression method not supported";
2666
2722
  const FORMAT_DEFLATE_RAW = "deflate-raw";
2667
2723
  const FORMAT_DEFLATE64_RAW = "deflate64-raw";
2668
2724
  const FORMAT_GZIP = "gzip";
@@ -2673,18 +2729,21 @@
2673
2729
 
2674
2730
  constructor(options, { chunkSize, CompressionStreamZlib, CompressionStream }) {
2675
2731
  super({});
2676
- const { compressed, encrypted, useCompressionStream, zipCrypto, signed, level, deflate64 } = options;
2732
+ const { compressed, encrypted, useCompressionStream, zipCrypto, signed, level, deflate64, format } = options;
2677
2733
  const stream = this;
2678
2734
  let crc32Stream, encryptionStream, gzipCrc32Stream;
2679
2735
  let readable = super.readable;
2680
- const useGzipCrc32 = signed && compressed && !deflate64 && (!encrypted || zipCrypto) &&
2736
+ const codecStreams = format && getCodecStreams(format);
2737
+ const useGzipCrc32 = signed && compressed && !deflate64 && !codecStreams && (!encrypted || zipCrypto) &&
2681
2738
  Boolean(useCompressionStream && CompressionStream);
2682
2739
  if ((!encrypted || zipCrypto) && signed && !useGzipCrc32) {
2683
2740
  crc32Stream = new Crc32Stream();
2684
2741
  readable = pipeThrough(readable, crc32Stream);
2685
2742
  }
2686
2743
  if (compressed) {
2687
- if (useGzipCrc32) {
2744
+ if (codecStreams) {
2745
+ readable = pipeThroughBackpressured(readable, createCodecStream(codecStreams.CompressionStream, format, { level, chunkSize }));
2746
+ } else if (useGzipCrc32) {
2688
2747
  gzipCrc32Stream = new GzipToRawDeflateStream();
2689
2748
  readable = pipeThroughBackpressured(readable, new CompressionStream(FORMAT_GZIP));
2690
2749
  readable = pipeThrough(readable, gzipCrc32Stream);
@@ -2758,7 +2817,7 @@
2758
2817
 
2759
2818
  constructor(options, { chunkSize, DecompressionStreamZlib, DecompressionStream }) {
2760
2819
  super({});
2761
- const { zipCrypto, encrypted, signed, signature, compressed, useCompressionStream, deflate64 } = options;
2820
+ const { zipCrypto, encrypted, signed, signature, compressed, useCompressionStream, deflate64, format } = options;
2762
2821
  let crc32Stream, decryptionStream;
2763
2822
  let readable = super.readable;
2764
2823
  if (encrypted) {
@@ -2770,7 +2829,12 @@
2770
2829
  }
2771
2830
  }
2772
2831
  if (compressed) {
2773
- 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
+ }
2774
2838
  readable = mapInflateStreamError(readable);
2775
2839
  }
2776
2840
  if ((!encrypted || zipCrypto) && signed) {
@@ -2797,6 +2861,13 @@
2797
2861
  });
2798
2862
  }
2799
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
+
2800
2871
  function pipeThroughCommpressionStream(readable, useCompressionStream, options, CompressionStreamNative, CompressionStreamZlib, CompressionStream) {
2801
2872
  const Stream = useCompressionStream && CompressionStreamNative ? CompressionStreamNative : CompressionStreamZlib || CompressionStream;
2802
2873
  const format = options.deflate64 ? FORMAT_DEFLATE64_RAW : FORMAT_DEFLATE_RAW;
@@ -3541,11 +3612,18 @@
3541
3612
 
3542
3613
  async function runWorker(stream, workerOptions) {
3543
3614
  const { options, config } = workerOptions;
3544
- const { transferStreams, useWebWorkers, useCompressionStream, compressed, signed, encrypted } = options;
3615
+ const { transferStreams, useWebWorkers, useCompressionStream, compressed, signed, encrypted, format, codecURI } = options;
3545
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
+ }
3546
3623
  workerOptions.transferStreams = transferStreams || (transferStreams === UNDEFINED_VALUE && config.transferStreams);
3547
3624
  const streamCopy = !compressed && !signed && !encrypted;
3548
- 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));
3549
3627
  workerOptions.workerURI = workerOptions.useWebWorkers && workerURI ? workerURI : UNDEFINED_VALUE;
3550
3628
  options.useCompressionStream = useCompressionStream || (useCompressionStream === UNDEFINED_VALUE && config.useCompressionStream);
3551
3629
  return (await getWorker()).run();
@@ -3585,6 +3663,14 @@
3585
3663
  }
3586
3664
  }
3587
3665
 
3666
+ function resolveCodecURI(codecURI, baseURI) {
3667
+ try {
3668
+ return new URL(codecURI, baseURI).toString();
3669
+ } catch {
3670
+ return codecURI;
3671
+ }
3672
+ }
3673
+
3588
3674
  function armStarvationTimeout() {
3589
3675
  if (!starvationTimeout && pendingRequests.length && Number.isFinite(starvationDelay) && starvationDelay >= 0) {
3590
3676
  starvationTimeout = setTimeout(onWorkerStarvation, starvationDelay);
@@ -3903,6 +3989,7 @@
3903
3989
  const OPTION_PREVENT_CLOSE = "preventClose";
3904
3990
  const OPTION_ENCRYPTION_STRENGTH = "encryptionStrength";
3905
3991
  const OPTION_EXTENDED_TIMESTAMP = "extendedTimestamp";
3992
+ const OPTION_NTFS_TIMESTAMP = "ntfsTimestamp";
3906
3993
  const OPTION_KEEP_ORDER = "keepOrder";
3907
3994
  const OPTION_LEVEL = "level";
3908
3995
  const OPTION_BUFFERED_WRITE = "bufferedWrite";
@@ -4334,7 +4421,8 @@
4334
4421
  throw new Error(ERR_UNSUPPORTED_COMPRESSION$1);
4335
4422
  }
4336
4423
  }
4337
- 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) {
4338
4426
  throw new Error(ERR_UNSUPPORTED_COMPRESSION$1);
4339
4427
  }
4340
4428
  if (dataArray.length < HEADER_SIZE || getUint32(dataView, 0) != LOCAL_FILE_HEADER_SIGNATURE) {
@@ -4373,7 +4461,7 @@
4373
4461
  fileEntry.zipCrypto = zipCrypto;
4374
4462
  }
4375
4463
  if (encrypted) {
4376
- if (!zipCrypto && extraFieldAES.strength === UNDEFINED_VALUE) {
4464
+ if (!zipCrypto && (extraFieldAES.strength < 1 || extraFieldAES.strength > 3)) {
4377
4465
  throw new Error(ERR_UNSUPPORTED_ENCRYPTION);
4378
4466
  } else if (!password && !rawPassword) {
4379
4467
  throw new Error(ERR_ENCRYPTED);
@@ -4412,6 +4500,8 @@
4412
4500
  useCompressionStream,
4413
4501
  transferStreams: getOptionValue$1(zipEntry, options, OPTION_TRANSFER_STREAMS),
4414
4502
  deflate64,
4503
+ format: registeredCodec ? registeredCodec.format : UNDEFINED_VALUE,
4504
+ codecURI: registeredCodec ? registeredCodec.codecURI : UNDEFINED_VALUE,
4415
4505
  checkPasswordOnly
4416
4506
  },
4417
4507
  config,
@@ -5028,6 +5118,7 @@
5028
5118
  const ERR_INVALID_ENTRY_NAME = "File entry name exceeds 64KB";
5029
5119
  const ERR_INVALID_VERSION = "Version exceeds 65535";
5030
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";
5031
5122
  const ERR_INVALID_EXTRAFIELD_TYPE = "Extra field type exceeds 65535";
5032
5123
  const ERR_INVALID_EXTRAFIELD_DATA = "Extra field data exceeds 64KB";
5033
5124
  const ERR_UNSUPPORTED_COMPRESSION = "Compression method not supported";
@@ -5430,6 +5521,7 @@
5430
5521
  const encryptionStrength = getOptionValue(zipWriter, options, OPTION_ENCRYPTION_STRENGTH, 3);
5431
5522
  const zipCrypto = getOptionValue(zipWriter, options, PROPERTY_NAME_ZIPCRYPTO);
5432
5523
  const extendedTimestamp = getOptionValue(zipWriter, options, OPTION_EXTENDED_TIMESTAMP, true);
5524
+ const ntfsTimestamp = getOptionValue(zipWriter, options, OPTION_NTFS_TIMESTAMP);
5433
5525
  const keepOrder = getOptionValue(zipWriter, options, OPTION_KEEP_ORDER, true);
5434
5526
  const useWebWorkers = getOptionValue(zipWriter, options, OPTION_USE_WEB_WORKERS);
5435
5527
  const transferStreams = getOptionValue(zipWriter, options, OPTION_TRANSFER_STREAMS);
@@ -5439,11 +5531,20 @@
5439
5531
  const signal = getOptionValue(zipWriter, options, OPTION_SIGNAL);
5440
5532
  const useUnicodeFileNames = getOptionValue(zipWriter, options, OPTION_USE_UNICODE_FILE_NAMES, true);
5441
5533
  const compressionMethod = getOptionValue(zipWriter, options, PROPERTY_NAME_COMPRESSION_METHOD);
5534
+ const registeredCodec = passThrough || compressionMethod === UNDEFINED_VALUE ? UNDEFINED_VALUE : getRegisteredCodec(compressionMethod);
5442
5535
  if (!passThrough && compressionMethod !== UNDEFINED_VALUE &&
5443
- compressionMethod !== COMPRESSION_METHOD_STORE && compressionMethod !== COMPRESSION_METHOD_DEFLATE) {
5536
+ compressionMethod !== COMPRESSION_METHOD_STORE && compressionMethod !== COMPRESSION_METHOD_DEFLATE && !registeredCodec) {
5444
5537
  throw new Error(ERR_UNSUPPORTED_COMPRESSION);
5445
5538
  }
5446
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
+ }
5447
5548
  let useCompressionStream = getOptionValue(zipWriter, options, OPTION_USE_COMPRESSION_STREAM);
5448
5549
  let dataDescriptor = getOptionValue(zipWriter, options, OPTION_DATA_DESCRIPTOR);
5449
5550
  if (bufferedWrite && dataDescriptor === UNDEFINED_VALUE) {
@@ -5455,7 +5556,7 @@
5455
5556
  if (level !== UNDEFINED_VALUE && level != 6) {
5456
5557
  useCompressionStream = false;
5457
5558
  }
5458
- 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)) {
5459
5560
  level = 0;
5460
5561
  }
5461
5562
  const zip64 = getOptionValue(zipWriter, options, PROPERTY_NAME_ZIP64);
@@ -5499,6 +5600,7 @@
5499
5600
  encryptionStrength,
5500
5601
  zipCrypto,
5501
5602
  extendedTimestamp,
5603
+ ntfsTimestamp,
5502
5604
  keepOrder,
5503
5605
  useWebWorkers,
5504
5606
  transferStreams,
@@ -5508,6 +5610,9 @@
5508
5610
  signal,
5509
5611
  useUnicodeFileNames,
5510
5612
  compressionMethod,
5613
+ format: registeredCodec ? registeredCodec.format : UNDEFINED_VALUE,
5614
+ codecURI: registeredCodec ? registeredCodec.codecURI : UNDEFINED_VALUE,
5615
+ codecVersionNeeded: registeredCodec ? registeredCodec.versionNeeded : UNDEFINED_VALUE,
5511
5616
  level,
5512
5617
  useCompressionStream,
5513
5618
  dataDescriptor,
@@ -5804,7 +5909,9 @@
5804
5909
  msdosAttributesRaw,
5805
5910
  msdosAttributes,
5806
5911
  useCompressionStream,
5807
- passThrough
5912
+ passThrough,
5913
+ format,
5914
+ codecURI
5808
5915
  } = options;
5809
5916
  const fileEntry = {
5810
5917
  lock,
@@ -5864,7 +5971,9 @@
5864
5971
  encrypted: encrypted && !passThrough,
5865
5972
  useWebWorkers,
5866
5973
  useCompressionStream,
5867
- transferStreams
5974
+ transferStreams,
5975
+ format,
5976
+ codecURI
5868
5977
  },
5869
5978
  config,
5870
5979
  streamOptions: { signal, size, onstart, onprogress, onend }
@@ -5936,6 +6045,7 @@
5936
6045
  rawExtraField,
5937
6046
  encryptionStrength,
5938
6047
  extendedTimestamp,
6048
+ ntfsTimestamp,
5939
6049
  passThrough,
5940
6050
  encrypted,
5941
6051
  zip64UncompressedSize,
@@ -5981,7 +6091,8 @@
5981
6091
  let extraFieldExtendedTimestampFlag;
5982
6092
  if (extendedTimestamp) {
5983
6093
  const lastModTimeUnix = getTimeUnix(lastModDate);
5984
- if (inUnixTimeRange(lastModTimeUnix)) {
6094
+ const lastModTimeUnixInRange = inUnixTimeRange(lastModTimeUnix);
6095
+ if (lastModTimeUnixInRange) {
5985
6096
  const extraFieldTimestampLength = 9 + (lastAccessDate ? 4 : 0) + (creationDate ? 4 : 0);
5986
6097
  const extraFieldTimestamp = createRecordWriter(extraFieldTimestampLength);
5987
6098
  extraFieldExtendedTimestampFlag = 0x1 + (lastAccessDate ? 0x2 : 0) + (creationDate ? 0x4 : 0);
@@ -5999,19 +6110,26 @@
5999
6110
  } else {
6000
6111
  rawExtraFieldExtendedTimestamp = EMPTY_UINT8_ARRAY;
6001
6112
  }
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 {
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 {
6015
6133
  rawExtraFieldNTFS = EMPTY_UINT8_ARRAY;
6016
6134
  }
6017
6135
  } else {
@@ -6049,6 +6167,10 @@
6049
6167
  if (compressionMethod === UNDEFINED_VALUE) {
6050
6168
  compressionMethod = compressed ? COMPRESSION_METHOD_DEFLATE : COMPRESSION_METHOD_STORE;
6051
6169
  }
6170
+ const { codecVersionNeeded } = options;
6171
+ if (compressed && codecVersionNeeded !== UNDEFINED_VALUE) {
6172
+ version = version > codecVersionNeeded ? version : codecVersionNeeded;
6173
+ }
6052
6174
  if (zip64) {
6053
6175
  version = version > VERSION_ZIP64 ? version : VERSION_ZIP64;
6054
6176
  }