From 61b86687792c327fd9800eb7e3c1aa136194b8c0 Mon Sep 17 00:00:00 2001 From: islandryu Date: Sun, 19 Jul 2026 22:12:45 +0900 Subject: [PATCH 1/3] zlib: accept ArrayBuffer dictionary in Zstd Fixes: https://github.com/nodejs/node/issues/64598 Signed-off-by: islandryu --- doc/api/zlib.md | 8 ++++++-- lib/zlib.js | 11 ++++++++++- test/parallel/test-zlib-zstd-dictionary.js | 16 ++++++++++++++++ 3 files changed, 32 insertions(+), 3 deletions(-) diff --git a/doc/api/zlib.md b/doc/api/zlib.md index f32715ba6cc6b2..a06e57c9180c87 100644 --- a/doc/api/zlib.md +++ b/doc/api/zlib.md @@ -1099,6 +1099,10 @@ added: - v23.8.0 - v22.15.0 changes: + - version: REPLACEME + pr-url: https://github.com/nodejs/node/pull/64599 + description: The `dictionary` option can be a `TypedArray`, `DataView`, or + `ArrayBuffer`. - version: v26.5.0 pr-url: https://github.com/nodejs/node/pull/64023 description: The `rejectGarbageAfterEnd` option was added. @@ -1115,8 +1119,8 @@ Each Zstd-based class takes an `options` object. All options are optional. * `maxOutputLength` {integer} Limits output size when using [convenience methods][]. **Default:** [`buffer.kMaxLength`][] * `info` {boolean} If `true`, returns an object with `buffer` and `engine`. **Default:** `false` -* `dictionary` {Buffer} Optional dictionary used to - improve compression efficiency when compressing or decompressing data that +* `dictionary` {Buffer|TypedArray|DataView|ArrayBuffer} Optional dictionary used + to improve compression efficiency when compressing or decompressing data that shares common patterns with the dictionary. * `rejectGarbageAfterEnd` {boolean} If `true`, decompression fails when input remains after the first complete compressed stream. **Default:** `false` diff --git a/lib/zlib.js b/lib/zlib.js index 47726337cf720d..c7ff90edbb572d 100644 --- a/lib/zlib.js +++ b/lib/zlib.js @@ -926,6 +926,15 @@ class Zstd extends ZlibBase { }); } + let dictionary = opts?.dictionary; + if (dictionary !== undefined && !isArrayBufferView(dictionary)) { + if (isAnyArrayBuffer(dictionary)) { + dictionary = Buffer.from(dictionary); + } else { + dictionary = undefined; + } + } + const handle = mode === ZSTD_COMPRESS ? new binding.ZstdCompress() : new binding.ZstdDecompress(); @@ -938,7 +947,7 @@ class Zstd extends ZlibBase { pledgedSrcSize, writeState, processCallback, - opts?.dictionary && isArrayBufferView(opts.dictionary) ? opts.dictionary : undefined, + dictionary, ); super(opts, mode, handle, zstdDefaultOpts); diff --git a/test/parallel/test-zlib-zstd-dictionary.js b/test/parallel/test-zlib-zstd-dictionary.js index 28dde28cb055b7..41b2ab90238c69 100644 --- a/test/parallel/test-zlib-zstd-dictionary.js +++ b/test/parallel/test-zlib-zstd-dictionary.js @@ -24,3 +24,19 @@ zlib.zstdCompress(input, { dictionary }, common.mustSucceed((compressed) => { assert.strictEqual(decompressed.toString(), input.toString()); })); })); + +const baseline = zlib.zstdCompressSync(input, { dictionary }).length; + +const arrayBuffer = dictionary.buffer.slice( + dictionary.byteOffset, dictionary.byteOffset + dictionary.byteLength); +const uint8 = new Uint8Array(arrayBuffer); +const dataView = new DataView(arrayBuffer); + +for (const dict of [arrayBuffer, uint8, dataView]) { + assert.strictEqual(zlib.zstdCompressSync(input, { dictionary: dict }).length, + baseline); + + const compressed = zlib.zstdCompressSync(input, { dictionary: dict }); + const decompressed = zlib.zstdDecompressSync(compressed, { dictionary: dict }); + assert.strictEqual(decompressed.toString(), input.toString()); +} From 0f815b64e8be7a9f95094cacf068a5bf31eb0da0 Mon Sep 17 00:00:00 2001 From: Ryuhei Shima <65934663+islandryu@users.noreply.github.com> Date: Mon, 20 Jul 2026 01:12:09 +0900 Subject: [PATCH 2/3] Update lib/zlib.js Co-authored-by: James M Snell --- lib/zlib.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/zlib.js b/lib/zlib.js index c7ff90edbb572d..11c199bde5d00a 100644 --- a/lib/zlib.js +++ b/lib/zlib.js @@ -929,7 +929,7 @@ class Zstd extends ZlibBase { let dictionary = opts?.dictionary; if (dictionary !== undefined && !isArrayBufferView(dictionary)) { if (isAnyArrayBuffer(dictionary)) { - dictionary = Buffer.from(dictionary); + dictionary = new Uint8Array(dictionary); } else { dictionary = undefined; } From db7a201f95353aa074084d18859284379714f96d Mon Sep 17 00:00:00 2001 From: islandryu Date: Mon, 20 Jul 2026 01:20:48 +0900 Subject: [PATCH 3/3] zlib: import Uint8Array from primordials Signed-off-by: islandryu --- lib/zlib.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/zlib.js b/lib/zlib.js index 11c199bde5d00a..5caaf797c484e7 100644 --- a/lib/zlib.js +++ b/lib/zlib.js @@ -33,6 +33,7 @@ const { ObjectSetPrototypeOf, Symbol, Uint32Array, + Uint8Array, } = primordials; const {