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..5caaf797c484e7 100644 --- a/lib/zlib.js +++ b/lib/zlib.js @@ -33,6 +33,7 @@ const { ObjectSetPrototypeOf, Symbol, Uint32Array, + Uint8Array, } = primordials; const { @@ -926,6 +927,15 @@ class Zstd extends ZlibBase { }); } + let dictionary = opts?.dictionary; + if (dictionary !== undefined && !isArrayBufferView(dictionary)) { + if (isAnyArrayBuffer(dictionary)) { + dictionary = new Uint8Array(dictionary); + } else { + dictionary = undefined; + } + } + const handle = mode === ZSTD_COMPRESS ? new binding.ZstdCompress() : new binding.ZstdDecompress(); @@ -938,7 +948,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()); +}