@zip.js/zip.js 2.16.1 → 2.18.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 (45) hide show
  1. package/deno.json +1 -1
  2. package/dist/zip-core-external.js +211 -130
  3. package/dist/zip-core-external.min.js +1 -1
  4. package/dist/zip-core.js +180 -117
  5. package/dist/zip-core.min.js +1 -1
  6. package/dist/zip-fs-core-external.js +223 -132
  7. package/dist/zip-fs-core-external.min.js +1 -1
  8. package/dist/zip-fs-core.js +192 -119
  9. package/dist/zip-fs-core.min.js +1 -1
  10. package/dist/zip-fs-external.js +223 -132
  11. package/dist/zip-fs-external.min.js +1 -1
  12. package/dist/zip-fs-native.js +194 -121
  13. package/dist/zip-fs-native.min.js +1 -1
  14. package/dist/zip-fs.js +224 -132
  15. package/dist/zip-fs.min.js +1 -1
  16. package/dist/zip-legacy.js +181 -118
  17. package/dist/zip-legacy.min.js +1 -1
  18. package/dist/zip-native.js +182 -119
  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 +212 -130
  23. package/dist/zip.min.js +1 -1
  24. package/index-native.cjs +194 -121
  25. package/index-native.min.js +1 -1
  26. package/index.cjs +224 -132
  27. package/index.d.cts +87 -24
  28. package/index.d.ts +87 -24
  29. package/index.min.js +1 -1
  30. package/lib/core/codec-pool.js +2 -0
  31. package/lib/core/codec-worker-web.js +16 -3
  32. package/lib/core/codec-worker.js +2 -1
  33. package/lib/core/streams/codec-stream.js +2 -0
  34. package/lib/core/streams/zip-entry-stream.js +123 -102
  35. package/lib/core/streams/zlib-js/zlib-streams.min.js +1 -1
  36. package/lib/core/streams/zlib-wasm/zlib-streams.js +31 -12
  37. package/lib/core/version.js +1 -1
  38. package/lib/core/web-worker-base.js +2 -2
  39. package/lib/core/web-worker-inline-native.js +1 -1
  40. package/lib/core/web-worker-inline-wasm.js +1 -1
  41. package/lib/core/zip-fs.js +16 -3
  42. package/lib/core/zip-reader.js +40 -11
  43. package/lib/core/zip-writer.js +1 -0
  44. package/lib/zip-core-reader.js +1 -0
  45. package/package.json +1 -1
@@ -1900,7 +1900,9 @@
1900
1900
 
1901
1901
  const ERR_INVALID_UNCOMPRESSED_SIZE = "Invalid uncompressed size";
1902
1902
  const ERR_INVALID_COMPRESSED_DATA = "Invalid compressed data";
1903
+ const ERR_CODEC_OUT_OF_MEMORY = "Codec out of memory";
1903
1904
  const ERR_INVALID_CRC32 = "Invalid CRC32";
1905
+ const Z_MEM_ERROR_CODE = "Z_MEM_ERROR";
1904
1906
  const FORMAT_DEFLATE_RAW = "deflate-raw";
1905
1907
  const FORMAT_DEFLATE64_RAW = "deflate64-raw";
1906
1908
  const FORMAT_GZIP = "gzip";
@@ -1935,13 +1937,13 @@
1935
1937
  readable = pipeThroughCompressionStream(readable, useCompressionStream, { level, chunkSize }, CompressionStream, CompressionStreamFallback);
1936
1938
  } catch (error) {
1937
1939
  if (!useCompressionStream && CompressionStreamFallback) {
1938
- throw error;
1940
+ throw mapMemoryError(error);
1939
1941
  }
1940
1942
  let gzipStream;
1941
1943
  try {
1942
1944
  gzipStream = new CompressionStream(FORMAT_GZIP);
1943
1945
  } catch {
1944
- throw error;
1946
+ throw mapMemoryError(error);
1945
1947
  }
1946
1948
  readable = pipeThroughBackpressured(readable, gzipStream);
1947
1949
  readable = pipeThrough(readable, new GzipToRawDeflateStream());
@@ -2005,50 +2007,30 @@
2005
2007
  }
2006
2008
  }
2007
2009
 
2008
- function pipeThroughGzipDecompressionStream(readable, gzipStream, outputSize, crc32) {
2010
+ function pipeThroughGzipDecompressionStream(readable, gzipStream, outputSize, crc32, sourceErrors) {
2009
2011
  const writer = gzipStream.writable.getWriter();
2010
2012
  const reader = gzipStream.readable.getReader();
2011
2013
  const outputCrc32 = crc32 === UNDEFINED_VALUE ? new Crc32() : UNDEFINED_VALUE;
2012
2014
  let outputLength = 0;
2013
- let inputDone = false;
2014
2015
  let trailerWritten = false;
2015
- let idleCheckArmed = false;
2016
- let readCount = 0;
2017
- let readPending = false;
2018
- let resolveTrailerReady, rejectTrailerReady;
2019
- const trailerReady = new Promise((resolve, reject) => {
2020
- resolveTrailerReady = resolve;
2021
- rejectTrailerReady = reject;
2022
- });
2023
- trailerReady.catch(() => { });
2024
- pump();
2025
- return new ReadableStream({
2026
- async pull(controller) {
2027
- try {
2028
- const { value, done } = await read();
2029
- if (done) {
2030
- controller.close();
2031
- } else {
2032
- outputLength += value.length;
2033
- if (outputLength > outputSize) {
2034
- throw new Error(ERR_INVALID_UNCOMPRESSED_SIZE);
2035
- }
2036
- if (outputCrc32) {
2037
- outputCrc32.append(value);
2038
- }
2039
- controller.enqueue(value);
2040
- }
2041
- } catch (error) {
2042
- rejectTrailerReady(error);
2043
- await cancel(reader, error);
2044
- throw trailerWritten ? getTrailerError(error) : error;
2045
- }
2016
+ let settled = false;
2017
+ let resolvePull, controller;
2018
+ const output = new ReadableStream({
2019
+ start(streamController) {
2020
+ controller = streamController;
2021
+ },
2022
+ pull() {
2023
+ resumePump();
2046
2024
  },
2047
2025
  cancel(reason) {
2048
- rejectTrailerReady(reason);
2026
+ settled = true;
2027
+ resumePump();
2049
2028
  return reader.cancel(reason);
2050
2029
  }
2051
2030
  });
2031
+ pump();
2032
+ drain();
2033
+ return output;
2052
2034
 
2053
2035
  async function pump() {
2054
2036
  const inputReader = readable.getReader();
@@ -2057,19 +2039,16 @@
2057
2039
  header.set(GZIP_HEADER_BYTES);
2058
2040
  await writer.write(header);
2059
2041
  for (; ;) {
2042
+ await outputCapacity();
2060
2043
  await writer.ready;
2061
- const { value, done } = await inputReader.read();
2044
+ const { value, done } = await readSource(inputReader, sourceErrors);
2062
2045
  if (done) {
2063
2046
  break;
2064
2047
  }
2065
2048
  await writer.write(value);
2066
2049
  }
2067
- inputDone = true;
2068
2050
  if (outputCrc32) {
2069
- if (readPending) {
2070
- armIdleCheck();
2071
- }
2072
- await trailerReady;
2051
+ await writer.write(new Uint8Array(0));
2073
2052
  }
2074
2053
  const trailer = new Uint8Array(GZIP_TRAILER_LENGTH);
2075
2054
  const dataView = getDataView(trailer);
@@ -2084,54 +2063,68 @@
2084
2063
  }
2085
2064
  }
2086
2065
 
2087
- function read() {
2088
- readCount++;
2089
- readPending = true;
2090
- const result = reader.read();
2091
- result.then(onReadSettled, onReadSettled);
2092
- if (inputDone && outputCrc32) {
2093
- armIdleCheck();
2066
+ async function drain() {
2067
+ try {
2068
+ for (; ;) {
2069
+ const { value, done } = await read();
2070
+ if (done) {
2071
+ break;
2072
+ }
2073
+ outputLength += value.length;
2074
+ if (outputLength > outputSize) {
2075
+ throw new Error(ERR_INVALID_UNCOMPRESSED_SIZE);
2076
+ }
2077
+ if (outputCrc32) {
2078
+ outputCrc32.append(value);
2079
+ }
2080
+ controller.enqueue(value);
2081
+ }
2082
+ if (!settled) {
2083
+ settled = true;
2084
+ controller.close();
2085
+ }
2086
+ } catch (error) {
2087
+ fail(error);
2088
+ await cancel(reader, error);
2094
2089
  }
2095
- return result;
2096
2090
  }
2097
2091
 
2098
- function onReadSettled() {
2099
- readPending = false;
2100
- }
2101
-
2102
- async function armIdleCheck() {
2103
- if (!idleCheckArmed) {
2104
- idleCheckArmed = true;
2105
- const count = readCount;
2106
- await nextTask();
2107
- idleCheckArmed = false;
2108
- if (readPending) {
2109
- if (readCount == count) {
2110
- resolveTrailerReady();
2111
- } else {
2112
- armIdleCheck();
2092
+ function read() {
2093
+ return reader.read().catch(error => {
2094
+ if (trailerWritten) {
2095
+ if (!outputCrc32) {
2096
+ throw mapError(error, ERR_INVALID_CRC32);
2097
+ }
2098
+ if (outputLength != outputSize) {
2099
+ throw mapError(error, ERR_INVALID_UNCOMPRESSED_SIZE);
2113
2100
  }
2101
+ return { done: true };
2114
2102
  }
2115
- }
2103
+ throw mapCodecError(error, sourceErrors);
2104
+ });
2116
2105
  }
2117
2106
 
2118
- function getTrailerError(error) {
2119
- const trailerError = new Error(outputLength == outputSize ? ERR_INVALID_CRC32 : ERR_INVALID_UNCOMPRESSED_SIZE);
2120
- trailerError.cause = error;
2121
- return trailerError;
2107
+ function outputCapacity() {
2108
+ if (!settled && controller.desiredSize <= 0) {
2109
+ return new Promise(resolve => resolvePull = resolve);
2110
+ }
2122
2111
  }
2123
- }
2124
2112
 
2125
- function nextTask() {
2126
- return new Promise(resolve => {
2127
- const { port1, port2 } = new MessageChannel();
2128
- port2.onmessage = () => {
2129
- port1.close();
2130
- port2.close();
2113
+ function resumePump() {
2114
+ if (resolvePull) {
2115
+ const resolve = resolvePull;
2116
+ resolvePull = UNDEFINED_VALUE;
2131
2117
  resolve();
2132
- };
2133
- port1.postMessage(UNDEFINED_VALUE);
2134
- });
2118
+ }
2119
+ }
2120
+
2121
+ function fail(error) {
2122
+ if (!settled) {
2123
+ settled = true;
2124
+ controller.error(error);
2125
+ resumePump();
2126
+ }
2127
+ }
2135
2128
  }
2136
2129
 
2137
2130
  class InflateStream extends TransformStream {
@@ -2150,11 +2143,12 @@
2150
2143
  }
2151
2144
  }
2152
2145
  if (compressed) {
2146
+ const sourceErrors = new Set();
2153
2147
  const codecStreams = format && getCodecStreams(format);
2148
+ let gzipStream;
2154
2149
  if (codecStreams) {
2155
- readable = pipeThroughBackpressured(readable, createCodecStream(codecStreams.DecompressionStream, format, { chunkSize, compressionMethod, rawBitFlag, uncompressedSize: outputSize }));
2150
+ readable = pipeThroughBackpressured(readable, createCodecStream(codecStreams.DecompressionStream, format, { chunkSize, compressionMethod, rawBitFlag, uncompressedSize: outputSize }), sourceErrors);
2156
2151
  } else {
2157
- let gzipStream;
2158
2152
  const GzipDecompressionStream = getGzipCodecStream(useCompressionStream, DecompressionStream, DecompressionStreamFallback);
2159
2153
  if (checkCrc32 && !deflate64 && crc32 !== UNDEFINED_VALUE && outputSize !== UNDEFINED_VALUE && GzipDecompressionStream) {
2160
2154
  try {
@@ -2165,24 +2159,25 @@
2165
2159
  }
2166
2160
  if (!gzipStream) {
2167
2161
  try {
2168
- readable = pipeThroughCompressionStream(readable, useCompressionStream, { chunkSize, deflate64 }, DecompressionStream, DecompressionStreamFallback);
2162
+ readable = pipeThroughCompressionStream(readable, useCompressionStream, { chunkSize, deflate64 }, DecompressionStream, DecompressionStreamFallback, sourceErrors);
2169
2163
  } catch (error) {
2170
2164
  if (deflate64 || outputSize === UNDEFINED_VALUE || (!useCompressionStream && DecompressionStreamFallback)) {
2171
- throw error;
2165
+ throw mapMemoryError(error);
2172
2166
  }
2173
2167
  try {
2174
2168
  gzipStream = new DecompressionStream(FORMAT_GZIP);
2175
2169
  } catch {
2176
- throw error;
2170
+ throw mapMemoryError(error);
2177
2171
  }
2178
2172
  }
2179
2173
  }
2180
- if (gzipStream) {
2181
- gzipCrc32 = true;
2182
- readable = pipeThroughGzipDecompressionStream(readable, gzipStream, outputSize, crc32);
2183
- }
2184
2174
  }
2185
- readable = mapInflateStreamError(readable);
2175
+ if (gzipStream) {
2176
+ gzipCrc32 = true;
2177
+ readable = pipeThroughGzipDecompressionStream(readable, gzipStream, outputSize, crc32, sourceErrors);
2178
+ } else {
2179
+ readable = mapInflateStreamError(readable, sourceErrors);
2180
+ }
2186
2181
  }
2187
2182
  if (checkCrc32 && !gzipCrc32) {
2188
2183
  crc32Stream = new Crc32Stream();
@@ -2255,7 +2250,7 @@
2255
2250
  }
2256
2251
  }
2257
2252
 
2258
- function pipeThroughCompressionStream(readable, useCompressionStream, options, CompressionStreamNative, CompressionStreamFallback) {
2253
+ function pipeThroughCompressionStream(readable, useCompressionStream, options, CompressionStreamNative, CompressionStreamFallback, sourceErrors) {
2259
2254
  const Stream = useCompressionStream && CompressionStreamNative ?
2260
2255
  CompressionStreamNative :
2261
2256
  CompressionStreamFallback || CompressionStreamNative;
@@ -2270,14 +2265,14 @@
2270
2265
  throw error;
2271
2266
  }
2272
2267
  }
2273
- return pipeThroughBackpressured(readable, codecStream);
2268
+ return pipeThroughBackpressured(readable, codecStream, sourceErrors);
2274
2269
  }
2275
2270
 
2276
2271
  function pipeThrough(readable, transformStream) {
2277
2272
  return toCompatibleReadable(readable).pipeThrough(transformStream);
2278
2273
  }
2279
2274
 
2280
- function pipeThroughBackpressured(readable, transformStream) {
2275
+ function pipeThroughBackpressured(readable, transformStream, sourceErrors) {
2281
2276
  const writer = transformStream.writable.getWriter();
2282
2277
  const reader = readable.getReader();
2283
2278
  pump();
@@ -2287,7 +2282,7 @@
2287
2282
  try {
2288
2283
  for (; ;) {
2289
2284
  await writer.ready;
2290
- const result = await reader.read();
2285
+ const result = await readSource(reader, sourceErrors);
2291
2286
  if (result.done) {
2292
2287
  await writer.close();
2293
2288
  break;
@@ -2317,7 +2312,36 @@
2317
2312
  }
2318
2313
  }
2319
2314
 
2320
- function mapInflateStreamError(readable) {
2315
+ function readSource(reader, sourceErrors) {
2316
+ const result = reader.read();
2317
+ return sourceErrors ? result.catch(error => {
2318
+ sourceErrors.add(error);
2319
+ throw error;
2320
+ }) : result;
2321
+ }
2322
+
2323
+ function mapCodecError(error, sourceErrors) {
2324
+ if (sourceErrors.has(error)) {
2325
+ return error;
2326
+ }
2327
+ return mapError(error, isMemoryError(error) ? ERR_CODEC_OUT_OF_MEMORY : ERR_INVALID_COMPRESSED_DATA);
2328
+ }
2329
+
2330
+ function mapMemoryError(error) {
2331
+ return isMemoryError(error) ? mapError(error, ERR_CODEC_OUT_OF_MEMORY) : error;
2332
+ }
2333
+
2334
+ function isMemoryError(error) {
2335
+ return isErrorObject(error) && error.code == Z_MEM_ERROR_CODE;
2336
+ }
2337
+
2338
+ function mapError(error, message) {
2339
+ const mappedError = new Error(message);
2340
+ mappedError.cause = error;
2341
+ return mappedError;
2342
+ }
2343
+
2344
+ function mapInflateStreamError(readable, sourceErrors) {
2321
2345
  const reader = readable.getReader();
2322
2346
  return new ReadableStream({
2323
2347
  async pull(controller) {
@@ -2330,12 +2354,7 @@
2330
2354
  }
2331
2355
  } catch (error) {
2332
2356
  await cancel(reader, error);
2333
- if (error && error.message) {
2334
- throw error;
2335
- }
2336
- const mappedError = new Error(ERR_INVALID_COMPRESSED_DATA);
2337
- mappedError.cause = error;
2338
- throw mappedError;
2357
+ throw mapCodecError(error, sourceErrors);
2339
2358
  }
2340
2359
  },
2341
2360
  cancel(reason) {
@@ -2699,10 +2718,11 @@
2699
2718
  }
2700
2719
  codecStream = new CodecStream(options, config);
2701
2720
  chunkStream = new ChunkStream(getChunkSize(config));
2721
+ const { signal } = workerOptions.streamOptions;
2702
2722
  await readable
2703
2723
  .pipeThrough(codecStream)
2704
2724
  .pipeThrough(chunkStream)
2705
- .pipeTo(writable, { preventClose: true, preventAbort: true });
2725
+ .pipeTo(writable, { preventClose: true, preventAbort: true, signal });
2706
2726
  const {
2707
2727
  crc32,
2708
2728
  inputSize,
@@ -2770,6 +2790,7 @@
2770
2790
  const MODULE_WORKER_OPTIONS = { type: "module" };
2771
2791
  const ERROR_EVENT_TYPE = "error";
2772
2792
  const MESSAGE_ERROR_EVENT_TYPE = "messageerror";
2793
+ const ABORT_EVENT_TYPE = "abort";
2773
2794
 
2774
2795
  let webWorkerSource, webWorkerURI, webWorkerOptions;
2775
2796
  let transferStreamsSupported = true;
@@ -2946,6 +2967,13 @@
2946
2967
  Object.assign(workerData, { destinationFailed: true, destinationError: error });
2947
2968
  }
2948
2969
  });
2970
+ const { signal } = workerData.workerOptions.streamOptions;
2971
+ if (signal) {
2972
+ const onAbort = () => abortController.abort(signal.reason);
2973
+ const removeAbortListener = () => signal.removeEventListener(ABORT_EVENT_TYPE, onAbort);
2974
+ signal.addEventListener(ABORT_EVENT_TYPE, onAbort);
2975
+ closed.then(removeAbortListener, removeAbortListener);
2976
+ }
2949
2977
  return {
2950
2978
  writable, closed, abortPipe: () => {
2951
2979
  aborting = true;
@@ -3208,9 +3236,6 @@
3208
3236
  responseError = errorValue.value;
3209
3237
  } else {
3210
3238
  responseError = Object.assign(new Error(message), { stack, code, name });
3211
- if (cause) {
3212
- responseError.cause = Object.assign(new Error(cause.message), { name: cause.name });
3213
- }
3214
3239
  }
3215
3240
  if (isErrorObject(responseError)) {
3216
3241
  try {
@@ -3220,6 +3245,14 @@
3220
3245
  if (codecImportFailed) {
3221
3246
  responseError.codecImportFailed = true;
3222
3247
  }
3248
+ if (cause) {
3249
+ if (!isErrorObject(responseError.cause)) {
3250
+ responseError.cause = Object.assign(new Error(cause.message), { name: cause.name });
3251
+ }
3252
+ if (cause.code !== UNDEFINED_VALUE && responseError.cause.code !== cause.code) {
3253
+ responseError.cause.code = cause.code;
3254
+ }
3255
+ }
3223
3256
  if (errorValue) {
3224
3257
  if (responseError.name !== name) {
3225
3258
  responseError.name = name;
@@ -4810,7 +4843,7 @@
4810
4843
  const CHARSET_UTF8 = "utf-8";
4811
4844
  const PROPERTY_NAME_UTF8_SUFFIX = "UTF8";
4812
4845
  const CHARSET_CP437 = "cp437";
4813
- const BITFLAG_AMBIGUITY_MASK = BITFLAG_ENCRYPTED | BITFLAG_DATA_DESCRIPTOR | BITFLAG_LANG_ENCODING_FLAG;
4846
+ const BITFLAG_AMBIGUITY_MASK = BITFLAG_ENCRYPTED | BITFLAG_DATA_DESCRIPTOR | BITFLAG_STRONG_ENCRYPTION | BITFLAG_LANG_ENCODING_FLAG;
4814
4847
  const VENDOR_VERSION_AE_1$1 = 1;
4815
4848
  const ZIP64_PROPERTIES = [
4816
4849
  [PROPERTY_NAME_UNCOMPRESSED_SIZE, MAX_32_BITS],
@@ -5464,12 +5497,12 @@
5464
5497
  fileEntry.gid = gid;
5465
5498
  }
5466
5499
  const checkPasswordOnly = getOptionValue$1(zipEntry, options, OPTION_CHECK_PASSWORD_ONLY);
5467
- const encrypted = zipEntry.encrypted && localDirectory.encrypted && (!passThroughEncryption || checkPasswordOnly);
5500
+ const encrypted = zipEntry.encrypted && (!passThroughEncryption || checkPasswordOnly);
5468
5501
  const zipCrypto = encrypted && !extraFieldAES;
5469
5502
  if (!passThroughEncryption) {
5470
5503
  fileEntry.zipCrypto = zipCrypto;
5471
5504
  }
5472
- if (encrypted && (localDirectory.rawBitFlag & BITFLAG_STRONG_ENCRYPTION) == BITFLAG_STRONG_ENCRYPTION) {
5505
+ if (encrypted && (zipEntry.rawBitFlag & BITFLAG_STRONG_ENCRYPTION) == BITFLAG_STRONG_ENCRYPTION) {
5473
5506
  throw new Error(ERR_UNSUPPORTED_ENCRYPTION);
5474
5507
  }
5475
5508
  const registeredCodec = passThroughCompression ? UNDEFINED_VALUE : getRegisteredCodec(compressionMethod);
@@ -5562,6 +5595,7 @@
5562
5595
  ({ writable } = writer);
5563
5596
  const readable = toCompatibleReadable(reader.createReadable({ offset: dataOffset, size }));
5564
5597
  const { outputSize: writtenSize } = await runWorker({ readable, writable }, workerOptions);
5598
+ throwIfAborted(signal);
5565
5599
  if (writtenSize != outputSize) {
5566
5600
  throw Object.assign(new Error(ERR_INVALID_UNCOMPRESSED_SIZE), { outputSize: writtenSize });
5567
5601
  }
@@ -5708,8 +5742,16 @@
5708
5742
  });
5709
5743
  const extraFieldZip64 = extraField.get(EXTRAFIELD_TYPE_ZIP64);
5710
5744
  if (extraFieldZip64) {
5711
- readExtraFieldZip64(extraFieldZip64, directory);
5745
+ if (!readExtraFieldZip64(extraFieldZip64, directory, localDirectory)) {
5746
+ malformedExtraField = true;
5747
+ }
5712
5748
  directory.extraFieldZip64 = extraFieldZip64;
5749
+ } else if (ZIP64_PROPERTIES.some(([propertyName, max]) => directory[propertyName] == max)) {
5750
+ if (localDirectory) {
5751
+ malformedExtraField = true;
5752
+ } else {
5753
+ throw new Error(ERR_EXTRAFIELD_ZIP64_NOT_FOUND);
5754
+ }
5713
5755
  }
5714
5756
  const extraFieldUnicodePath = extraField.get(EXTRAFIELD_TYPE_UNICODE_PATH);
5715
5757
  if (extraFieldUnicodePath) {
@@ -5722,10 +5764,13 @@
5722
5764
  directory.extraFieldUnicodeComment = extraFieldUnicodeComment;
5723
5765
  }
5724
5766
  const extraFieldAES = extraField.get(EXTRAFIELD_TYPE_AES);
5725
- if (extraFieldAES && extraFieldAES.data.length >= 7) {
5767
+ if (extraFieldAES && (compressionMethod == COMPRESSION_METHOD_AES || directory.encrypted) && extraFieldAES.data.length >= 7) {
5726
5768
  readExtraFieldAES(extraFieldAES, directory, compressionMethod);
5727
5769
  directory.extraFieldAES = extraFieldAES;
5728
5770
  } else {
5771
+ if (extraFieldAES) {
5772
+ malformedExtraField = true;
5773
+ }
5729
5774
  directory.compressionMethod = compressionMethod;
5730
5775
  }
5731
5776
  const extraFieldPkwareUnix = extraField.get(EXTRAFIELD_TYPE_PKWARE_UNIX);
@@ -5768,20 +5813,35 @@
5768
5813
  return malformedExtraField;
5769
5814
  }
5770
5815
 
5771
- function readExtraFieldZip64(extraFieldZip64, directory) {
5816
+ function readExtraFieldZip64(extraFieldZip64, directory, localDirectory) {
5772
5817
  directory.zip64 = true;
5773
5818
  const extraFieldView = getDataView(extraFieldZip64.data);
5774
5819
  const missingProperties = ZIP64_PROPERTIES.filter(([propertyName, max]) => directory[propertyName] == max);
5775
5820
  const requiredLength = missingProperties.reduce((length, [, max]) => length + ZIP64_EXTRACTION[max].bytes, 0);
5776
5821
  if (extraFieldZip64.data.length < requiredLength) {
5822
+ if (localDirectory) {
5823
+ return false;
5824
+ }
5777
5825
  throw new Error(ERR_EXTRAFIELD_ZIP64_NOT_FOUND);
5778
5826
  }
5779
- for (let indexMissingProperty = 0, offset = 0; indexMissingProperty < missingProperties.length; indexMissingProperty++) {
5780
- const [propertyName, max] = missingProperties[indexMissingProperty];
5781
- const extraction = ZIP64_EXTRACTION[max];
5782
- directory[propertyName] = extraFieldZip64[propertyName] = extraction.getValue(extraFieldView, offset);
5783
- offset += extraction.bytes;
5827
+ const values = [];
5828
+ try {
5829
+ for (let indexMissingProperty = 0, offset = 0; indexMissingProperty < missingProperties.length; indexMissingProperty++) {
5830
+ const [, max] = missingProperties[indexMissingProperty];
5831
+ const extraction = ZIP64_EXTRACTION[max];
5832
+ values.push(extraction.getValue(extraFieldView, offset));
5833
+ offset += extraction.bytes;
5834
+ }
5835
+ } catch (error) {
5836
+ if (localDirectory) {
5837
+ return false;
5838
+ }
5839
+ throw error;
5784
5840
  }
5841
+ missingProperties.forEach(([propertyName], indexMissingProperty) => {
5842
+ directory[propertyName] = extraFieldZip64[propertyName] = values[indexMissingProperty];
5843
+ });
5844
+ return true;
5785
5845
  }
5786
5846
 
5787
5847
  function readExtraFieldUnicode(extraFieldUnicode, propertyName, rawPropertyName, directory, fileEntry) {
@@ -6357,6 +6417,7 @@
6357
6417
  ERR_AMBIGUOUS_ARCHIVE: ERR_AMBIGUOUS_ARCHIVE,
6358
6418
  ERR_BAD_FORMAT: ERR_BAD_FORMAT,
6359
6419
  ERR_CENTRAL_DIRECTORY_NOT_FOUND: ERR_CENTRAL_DIRECTORY_NOT_FOUND,
6420
+ ERR_CODEC_OUT_OF_MEMORY: ERR_CODEC_OUT_OF_MEMORY,
6360
6421
  ERR_ENCRYPTED: ERR_ENCRYPTED,
6361
6422
  ERR_ENCRYPTED_CENTRAL_DIRECTORY: ERR_ENCRYPTED_CENTRAL_DIRECTORY,
6362
6423
  ERR_ENTRY_DATA_OUT_OF_BOUNDS: ERR_ENTRY_DATA_OUT_OF_BOUNDS,
@@ -7804,6 +7865,7 @@
7804
7865
  const result = await runWorker({ readable, writable }, workerOptions);
7805
7866
  compressedSize = result.outputSize;
7806
7867
  writer.size += compressedSize;
7868
+ throwIfAborted(signal);
7807
7869
  if (!passThroughCompression) {
7808
7870
  uncompressedSize = result.inputSize;
7809
7871
  if (!encrypted || zipCrypto) {
@@ -8983,7 +9045,7 @@
8983
9045
  EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
8984
9046
  */
8985
9047
 
8986
- const VERSION = "2.16.1";
9048
+ const VERSION = "2.18.0";
8987
9049
 
8988
9050
  /*
8989
9051
  Copyright (c) 2025 Gildas Lormeau. All rights reserved.
@@ -9481,6 +9543,7 @@
9481
9543
  const ERR_ABORT_EXPORT = "zipjs-abort-export";
9482
9544
  const ABORT_ERROR_NAME = "AbortError";
9483
9545
  const EMPTY_RAW_PASSWORD = new Uint8Array(0);
9546
+ const FALSE_ACCEPT_ERRORS = new Set([ERR_INVALID_CRC32, ERR_INVALID_UNCOMPRESSED_SIZE, ERR_INVALID_COMPRESSED_DATA]);
9484
9547
 
9485
9548
  class ZipEntry {
9486
9549
 
@@ -10468,7 +10531,12 @@
10468
10531
  release();
10469
10532
  }
10470
10533
  }
10471
- throw new Error(tried.size ? ERR_INVALID_PASSWORD : ERR_ENCRYPTED);
10534
+ if (!tried.size) {
10535
+ throw new Error(ERR_ENCRYPTED);
10536
+ }
10537
+ const passwordError = new Error(ERR_INVALID_PASSWORD);
10538
+ passwordError.cause = error;
10539
+ throw passwordError;
10472
10540
 
10473
10541
  async function tryPasswordCandidate(candidate) {
10474
10542
  tried.add(candidate.key);
@@ -10489,7 +10557,7 @@
10489
10557
  rememberPassword(passwordState, candidate);
10490
10558
  return { done: true, data };
10491
10559
  } catch (readError) {
10492
- if (isAbortError(readError, signal) || (!entry.zipCrypto && !isInvalidPasswordError(readError))) {
10560
+ if (isAbortError(readError, signal) || !isWrongPasswordError(readError, entry)) {
10493
10561
  throw readError;
10494
10562
  }
10495
10563
  return { done: false, error: readError };
@@ -10501,6 +10569,10 @@
10501
10569
  return isErrorObject(error) && error.message == ERR_INVALID_PASSWORD;
10502
10570
  }
10503
10571
 
10572
+ function isWrongPasswordError(error, entry) {
10573
+ return isInvalidPasswordError(error) || (entry.zipCrypto && isErrorObject(error) && FALSE_ACCEPT_ERRORS.has(error.message));
10574
+ }
10575
+
10504
10576
  function isAbortError(error, signal) {
10505
10577
  return Boolean(signal && signal.aborted) || (isErrorObject(error) && error.name == ABORT_ERROR_NAME);
10506
10578
  }
@@ -10930,6 +11002,7 @@
10930
11002
  exports.ERR_ANCESTOR_ENTRY = ERR_ANCESTOR_ENTRY;
10931
11003
  exports.ERR_BAD_FORMAT = ERR_BAD_FORMAT;
10932
11004
  exports.ERR_CENTRAL_DIRECTORY_NOT_FOUND = ERR_CENTRAL_DIRECTORY_NOT_FOUND;
11005
+ exports.ERR_CODEC_OUT_OF_MEMORY = ERR_CODEC_OUT_OF_MEMORY;
10933
11006
  exports.ERR_DUPLICATED_NAME = ERR_DUPLICATED_NAME;
10934
11007
  exports.ERR_DUPLICATE_IMPORTED_ENTRY = ERR_DUPLICATE_IMPORTED_ENTRY;
10935
11008
  exports.ERR_ENCRYPTED = ERR_ENCRYPTED;