@@ -49,6 +49,7 @@ const {
4949 ERR_INVALID_ARG_TYPE ,
5050 ERR_OUT_OF_RANGE ,
5151 ERR_ZLIB_INITIALIZATION_FAILED ,
52+ ERR_ZSTD_INVALID_PARAM ,
5253 } ,
5354 genericNodeError,
5455 hideStackFrames,
@@ -88,9 +89,12 @@ const {
8889 // Node's compression stream modes (node_zlib_mode)
8990 DEFLATE , DEFLATERAW , INFLATE , INFLATERAW , GZIP , GUNZIP , UNZIP ,
9091 BROTLI_DECODE , BROTLI_ENCODE ,
92+ ZSTD_COMPRESS , ZSTD_DECOMPRESS ,
9193 // Brotli operations (~flush levels)
9294 BROTLI_OPERATION_PROCESS , BROTLI_OPERATION_FLUSH ,
9395 BROTLI_OPERATION_FINISH , BROTLI_OPERATION_EMIT_METADATA ,
96+ // Zstd end directives (~flush levels)
97+ ZSTD_e_continue, ZSTD_e_flush, ZSTD_e_end,
9498} = constants ;
9599
96100// Translation table for return codes.
@@ -237,9 +241,11 @@ const checkRangesOrGetDefault = hideStackFrames(
237241const FLUSH_BOUND = [
238242 [ Z_NO_FLUSH , Z_BLOCK ] ,
239243 [ BROTLI_OPERATION_PROCESS , BROTLI_OPERATION_EMIT_METADATA ] ,
244+ [ ZSTD_e_continue , ZSTD_e_end ] ,
240245] ;
241246const FLUSH_BOUND_IDX_NORMAL = 0 ;
242247const FLUSH_BOUND_IDX_BROTLI = 1 ;
248+ const FLUSH_BOUND_IDX_ZSTD = 2 ;
243249
244250// The base class for all Zlib-style streams.
245251function ZlibBase ( opts , mode , handle , { flush, finishFlush, fullFlush } ) {
@@ -248,13 +254,15 @@ function ZlibBase(opts, mode, handle, { flush, finishFlush, fullFlush }) {
248254 // The ZlibBase class is not exported to user land, the mode should only be
249255 // passed in by us.
250256 assert ( typeof mode === 'number' ) ;
251- assert ( mode >= DEFLATE && mode <= BROTLI_ENCODE ) ;
257+ assert ( mode >= DEFLATE && mode <= ZSTD_DECOMPRESS ) ;
252258
253259 let flushBoundIdx ;
254- if ( mode !== BROTLI_ENCODE && mode !== BROTLI_DECODE ) {
255- flushBoundIdx = FLUSH_BOUND_IDX_NORMAL ;
256- } else {
260+ if ( mode === BROTLI_ENCODE || mode === BROTLI_DECODE ) {
257261 flushBoundIdx = FLUSH_BOUND_IDX_BROTLI ;
262+ } else if ( mode === ZSTD_COMPRESS || mode === ZSTD_DECOMPRESS ) {
263+ flushBoundIdx = FLUSH_BOUND_IDX_ZSTD ;
264+ } else {
265+ flushBoundIdx = FLUSH_BOUND_IDX_NORMAL ;
258266 }
259267
260268 if ( opts ) {
@@ -888,6 +896,77 @@ ObjectSetPrototypeOf(BrotliDecompress.prototype, Brotli.prototype);
888896ObjectSetPrototypeOf ( BrotliDecompress , Brotli ) ;
889897
890898
899+ const kMaxZstdParam = MathMaxApply ( ArrayPrototypeMap (
900+ ObjectKeys ( constants ) ,
901+ ( key ) => ( StringPrototypeStartsWith ( key , 'ZSTD_c_' ) ?
902+ constants [ key ] :
903+ 0 ) ,
904+ ) ) ;
905+
906+ const zstdInitParamsArray = new Uint32Array ( kMaxZstdParam + 1 ) ;
907+
908+ const zstdDefaultOpts = {
909+ flush : ZSTD_e_continue ,
910+ finishFlush : ZSTD_e_end ,
911+ fullFlush : ZSTD_e_flush ,
912+ } ;
913+ function Zstd ( opts , mode ) {
914+ assert ( mode === ZSTD_COMPRESS || mode === ZSTD_DECOMPRESS ) ;
915+
916+ TypedArrayPrototypeFill ( zstdInitParamsArray , - 1 ) ;
917+ if ( opts ?. params ) {
918+ ArrayPrototypeForEach ( ObjectKeys ( opts . params ) , ( origKey ) => {
919+ const key = + origKey ;
920+ if ( NumberIsNaN ( key ) || key < 0 || key > kMaxZstdParam ||
921+ ( zstdInitParamsArray [ key ] | 0 ) !== - 1 ) {
922+ throw new ERR_ZSTD_INVALID_PARAM ( origKey ) ;
923+ }
924+
925+ const value = opts . params [ origKey ] ;
926+ if ( typeof value !== 'number' && typeof value !== 'boolean' ) {
927+ throw new ERR_INVALID_ARG_TYPE ( 'options.params[key]' ,
928+ 'number' , opts . params [ origKey ] ) ;
929+ }
930+ zstdInitParamsArray [ key ] = value ;
931+ } ) ;
932+ }
933+
934+ const handle = mode === ZSTD_COMPRESS ?
935+ new binding . ZstdCompress ( ) : new binding . ZstdDecompress ( ) ;
936+
937+ this . _writeState = new Uint32Array ( 2 ) ;
938+ if ( ! handle . init ( zstdInitParamsArray ,
939+ this . _writeState ,
940+ processCallback ) ) {
941+ throw new ERR_ZLIB_INITIALIZATION_FAILED ( ) ;
942+ }
943+
944+ ReflectApply ( ZlibBase , this , [ opts , mode , handle , zstdDefaultOpts ] ) ;
945+ }
946+ ObjectSetPrototypeOf ( Zstd . prototype , ZlibBase . prototype ) ;
947+ ObjectSetPrototypeOf ( Zstd , ZlibBase ) ;
948+
949+
950+ function ZstdCompress ( opts ) {
951+ if ( ! ( this instanceof ZstdCompress ) )
952+ return new ZstdCompress ( opts ) ;
953+
954+ ReflectApply ( Zstd , this , [ opts , ZSTD_COMPRESS ] ) ;
955+ }
956+ ObjectSetPrototypeOf ( ZstdCompress . prototype , Zstd . prototype ) ;
957+ ObjectSetPrototypeOf ( ZstdCompress , Zstd ) ;
958+
959+
960+ function ZstdDecompress ( opts ) {
961+ if ( ! ( this instanceof ZstdDecompress ) )
962+ return new ZstdDecompress ( opts ) ;
963+
964+ ReflectApply ( Zstd , this , [ opts , ZSTD_DECOMPRESS ] ) ;
965+ }
966+ ObjectSetPrototypeOf ( ZstdDecompress . prototype , Zstd . prototype ) ;
967+ ObjectSetPrototypeOf ( ZstdDecompress , Zstd ) ;
968+
969+
891970function createProperty ( ctor ) {
892971 return {
893972 __proto__ : null ,
@@ -917,6 +996,8 @@ module.exports = {
917996 Unzip,
918997 BrotliCompress,
919998 BrotliDecompress,
999+ ZstdCompress,
1000+ ZstdDecompress,
9201001
9211002 // Convenience methods.
9221003 // compress/decompress a string or buffer in one step.
@@ -938,6 +1019,10 @@ module.exports = {
9381019 brotliCompressSync : createConvenienceMethod ( BrotliCompress , true ) ,
9391020 brotliDecompress : createConvenienceMethod ( BrotliDecompress , false ) ,
9401021 brotliDecompressSync : createConvenienceMethod ( BrotliDecompress , true ) ,
1022+ zstdCompress : createConvenienceMethod ( ZstdCompress , false ) ,
1023+ zstdCompressSync : createConvenienceMethod ( ZstdCompress , true ) ,
1024+ zstdDecompress : createConvenienceMethod ( ZstdDecompress , false ) ,
1025+ zstdDecompressSync : createConvenienceMethod ( ZstdDecompress , true ) ,
9411026} ;
9421027
9431028ObjectDefineProperties ( module . exports , {
@@ -950,6 +1035,8 @@ ObjectDefineProperties(module.exports, {
9501035 createUnzip : createProperty ( Unzip ) ,
9511036 createBrotliCompress : createProperty ( BrotliCompress ) ,
9521037 createBrotliDecompress : createProperty ( BrotliDecompress ) ,
1038+ createZstdCompress : createProperty ( ZstdCompress ) ,
1039+ createZstdDecompress : createProperty ( ZstdDecompress ) ,
9531040 constants : {
9541041 __proto__ : null ,
9551042 configurable : false ,
0 commit comments