@@ -31,6 +31,7 @@ const {
3131 ObjectFreeze,
3232 ObjectKeys,
3333 ReflectApply,
34+ SafeMap,
3435 Symbol,
3536 SymbolHasInstance,
3637 Uint32Array,
@@ -176,43 +177,128 @@ function zlibBufferOnEnd() {
176177 this . cb ( null , buf ) ;
177178}
178179
179- function zlibBufferSync ( engine , buffer ) {
180+ function toSyncInput ( buffer ) {
180181 if ( typeof buffer === 'string' ) {
181- buffer = Buffer . from ( buffer ) ;
182- } else if ( ! isArrayBufferView ( buffer ) ) {
182+ return Buffer . from ( buffer ) ;
183+ }
184+ if ( ! isArrayBufferView ( buffer ) ) {
183185 if ( isAnyArrayBuffer ( buffer ) ) {
184- buffer = Buffer . from ( buffer ) ;
185- } else {
186- throw new ERR_INVALID_ARG_TYPE (
187- 'buffer' ,
188- [ 'string' , 'Buffer' , 'TypedArray' , 'DataView' , 'ArrayBuffer' ] ,
189- buffer ,
190- ) ;
186+ return Buffer . from ( buffer ) ;
191187 }
188+ throw new ERR_INVALID_ARG_TYPE (
189+ 'buffer' ,
190+ [ 'string' , 'Buffer' , 'TypedArray' , 'DataView' , 'ArrayBuffer' ] ,
191+ buffer ,
192+ ) ;
192193 }
194+ return buffer ;
195+ }
196+
197+ function zlibBufferSync ( engine , buffer ) {
198+ buffer = toSyncInput ( buffer ) ;
193199 buffer = processChunkSync ( engine , buffer , engine . _finishFlushFlag ) ;
194200 if ( engine . _info )
195201 return { buffer, engine } ;
196202 return buffer ;
197203}
198204
205+ function zlibError ( message , errno , code ) {
206+ if ( code === 'ERR_TRAILING_JUNK_AFTER_STREAM_END' ) {
207+ return new ERR_TRAILING_JUNK_AFTER_STREAM_END ( ) ;
208+ }
209+ const error = genericNodeError ( message , { errno, code } ) ;
210+ error . errno = errno ;
211+ error . code = code ;
212+ return error ;
213+ }
214+
199215function zlibOnError ( message , errno , code ) {
200216 const self = this [ owner_symbol ] ;
201217 // There is no way to cleanly recover.
202218 // Continuing only obscures problems.
203-
204- let error ;
205- if ( code === 'ERR_TRAILING_JUNK_AFTER_STREAM_END' ) {
206- error = new ERR_TRAILING_JUNK_AFTER_STREAM_END ( ) ;
207- } else {
208- error = genericNodeError ( message , { errno, code } ) ;
209- error . errno = errno ;
210- error . code = code ;
211- }
219+ const error = zlibError ( message , errno , code ) ;
212220 self . destroy ( error ) ;
213221 self [ kError ] = error ;
214222}
215223
224+ // Without options, a synchronous convenience call (zlib.inflateSync(buffer),
225+ // ...) uses the defaults and its engine is never exposed, so it drives a
226+ // native handle directly instead of constructing a Transform stream. It also
227+ // decompresses into a scratch buffer kept between calls and copies the result
228+ // out, instead of allocating a whole output chunk per call.
229+ let syncScratchBuffer ;
230+
231+ function zlibSyncOnError ( message , errno , code ) {
232+ this [ kError ] = zlibError ( message , errno , code ) ;
233+ }
234+
235+ function zlibBufferSyncWithDefaults ( ctor , buffer ) {
236+ const chunk = toSyncInput ( buffer ) ;
237+ const mode = kEngineModes . get ( ctor ) ;
238+ const writeState = new Uint32Array ( 2 ) ;
239+ const handle = createDefaultHandle ( mode , writeState ) ;
240+ handle . onerror = zlibSyncOnError ;
241+ // Take the scratch buffer, so that a nested call (e.g. from an async hook)
242+ // allocates its own.
243+ const scratch = syncScratchBuffer ?? Buffer . allocUnsafeSlow ( Z_DEFAULT_CHUNK ) ;
244+ syncScratchBuffer = undefined ;
245+ try {
246+ return processSyncWithDefaults ( handle , writeState , chunk ,
247+ defaultFinishFlush ( mode ) , scratch ) ;
248+ } finally {
249+ handle . close ( ) ;
250+ syncScratchBuffer = scratch ;
251+ }
252+ }
253+
254+ // Same as processChunkSync() for an engine created without options.
255+ function processSyncWithDefaults ( handle , writeState , chunk , flushFlag ,
256+ scratch ) {
257+ const chunkSize = Z_DEFAULT_CHUNK ;
258+ let out = scratch ;
259+ let inOff = 0 ;
260+ let availIn = chunk . byteLength ;
261+ let buffers = null ;
262+ let nread = 0 ;
263+
264+ while ( true ) {
265+ handle . writeSync ( flushFlag , chunk , inOff , availIn , out , 0 , chunkSize ) ;
266+ if ( handle [ kError ] !== undefined )
267+ throw handle [ kError ] ;
268+
269+ const availOutAfter = writeState [ 0 ] ;
270+ const availInAfter = writeState [ 1 ] ;
271+ const have = chunkSize - availOutAfter ;
272+ if ( have > 0 ) {
273+ nread += have ;
274+ if ( nread > kMaxLength )
275+ throw new ERR_BUFFER_TOO_LARGE ( kMaxLength ) ;
276+ if ( out !== scratch ) {
277+ buffers . push ( out . subarray ( 0 , have ) ) ;
278+ } else if ( availOutAfter === 0 ) {
279+ buffers = [ out ] ;
280+ }
281+ }
282+ if ( availOutAfter !== 0 )
283+ break ;
284+
285+ // The output buffer is full. Continue with the rest of the input.
286+ inOff += availIn - availInAfter ;
287+ availIn = availInAfter ;
288+ out = Buffer . allocUnsafe ( chunkSize ) ;
289+ }
290+
291+ if ( nread === 0 )
292+ return new FastBuffer ( ) ;
293+ if ( buffers === null ) {
294+ // All of the output is in the scratch buffer.
295+ const result = Buffer . allocUnsafe ( nread ) ;
296+ scratch . copy ( result , 0 , 0 , nread ) ;
297+ return result ;
298+ }
299+ return Buffer . concat ( buffers , nread ) ;
300+ }
301+
216302const FLUSH_BOUND = [
217303 [ Z_NO_FLUSH , Z_BLOCK ] ,
218304 [ BROTLI_OPERATION_PROCESS , BROTLI_OPERATION_EMIT_METADATA ] ,
@@ -794,6 +880,8 @@ class Unzip extends Zlib {
794880function createConvenienceMethod ( ctor , sync , prepareOpts ) {
795881 if ( sync ) {
796882 return function syncBufferWrapper ( buffer , opts ) {
883+ if ( opts === undefined )
884+ return zlibBufferSyncWithDefaults ( ctor , buffer ) ;
797885 return zlibBufferSync ( new ctor ( opts ) , buffer ) ;
798886 } ;
799887 }
@@ -999,6 +1087,61 @@ class ZstdDecompress extends Zstd {
9991087 }
10001088}
10011089
1090+ const kEngineModes = new SafeMap ( [
1091+ [ Deflate , DEFLATE ] ,
1092+ [ Inflate , INFLATE ] ,
1093+ [ Gzip , GZIP ] ,
1094+ [ Gunzip , GUNZIP ] ,
1095+ [ DeflateRaw , DEFLATERAW ] ,
1096+ [ InflateRaw , INFLATERAW ] ,
1097+ [ Unzip , UNZIP ] ,
1098+ [ BrotliCompress , BROTLI_ENCODE ] ,
1099+ [ BrotliDecompress , BROTLI_DECODE ] ,
1100+ [ ZstdCompress , ZSTD_COMPRESS ] ,
1101+ [ ZstdDecompress , ZSTD_DECOMPRESS ] ,
1102+ ] ) ;
1103+
1104+ // Creates the native handle that the engine for `mode` creates when its
1105+ // constructor gets no options.
1106+ function createDefaultHandle ( mode , writeState ) {
1107+ let handle ;
1108+ switch ( mode ) {
1109+ case BROTLI_ENCODE :
1110+ case BROTLI_DECODE :
1111+ handle = mode === BROTLI_DECODE ?
1112+ new binding . BrotliDecoder ( mode ) : new binding . BrotliEncoder ( mode ) ;
1113+ brotliInitParamsArray . fill ( - 1 ) ;
1114+ handle . init ( brotliInitParamsArray , writeState , processCallback , undefined ) ;
1115+ return handle ;
1116+ case ZSTD_COMPRESS :
1117+ zstdInitCParamsArray . fill ( - 1 ) ;
1118+ handle = new binding . ZstdCompress ( ) ;
1119+ handle . init ( zstdInitCParamsArray , undefined , writeState , processCallback ,
1120+ undefined , false ) ;
1121+ return handle ;
1122+ case ZSTD_DECOMPRESS :
1123+ zstdInitDParamsArray . fill ( - 1 ) ;
1124+ handle = new binding . ZstdDecompress ( ) ;
1125+ handle . init ( zstdInitDParamsArray , undefined , writeState , processCallback ,
1126+ undefined , false ) ;
1127+ return handle ;
1128+ default :
1129+ handle = new binding . Zlib ( mode ) ;
1130+ handle . init ( Z_DEFAULT_WINDOWBITS , Z_DEFAULT_COMPRESSION ,
1131+ Z_DEFAULT_MEMLEVEL , Z_DEFAULT_STRATEGY , writeState ,
1132+ processCallback , undefined , false ) ;
1133+ return handle ;
1134+ }
1135+ }
1136+
1137+ function defaultFinishFlush ( mode ) {
1138+ if ( mode === BROTLI_ENCODE || mode === BROTLI_DECODE )
1139+ return brotliDefaultOpts . finishFlush ;
1140+ if ( mode === ZSTD_COMPRESS || mode === ZSTD_DECOMPRESS )
1141+ return zstdDefaultOpts . finishFlush ;
1142+ return zlibDefaultOpts . finishFlush ;
1143+ }
1144+
10021145function createProperty ( ctor ) {
10031146 return {
10041147 __proto__ : null ,
0 commit comments