diff --git a/lib/deflate.js b/lib/deflate.js index 9cd0392..6768561 100644 --- a/lib/deflate.js +++ b/lib/deflate.js @@ -17,6 +17,7 @@ var Z_FINISH = 4; var Z_OK = 0; var Z_STREAM_END = 1; +var Z_SYNC_FLUSH = 2; var Z_DEFAULT_COMPRESSION = -1; @@ -46,7 +47,9 @@ var Z_DEFLATED = 8; * * Compressed result, generated by default [[Deflate#onData]] * and [[Deflate#onEnd]] handlers. Filled after you push last chunk - * (call [[Deflate#push]] with `Z_FINISH` / `true` param). + * (call [[Deflate#push]] with `Z_FINISH` / `true` param) or if you + * push a chunk with explicit flush (call [[Deflate#push]] with + * `Z_SYNC_FLUSH` param). **/ /** @@ -170,8 +173,9 @@ var Deflate = function(options) { * * Sends input data to deflate pipe, generating [[Deflate#onData]] calls with * new compressed chunks. Returns `true` on success. The last data block must have - * mode Z_FINISH (or `true`). That flush internal pending buffers and call - * [[Deflate#onEnd]]. + * mode Z_FINISH (or `true`). That will flush internal pending buffers and call + * [[Deflate#onEnd]]. For interim explicit flushes (without ending the stream) you + * can use mode Z_SYNC_FLUSH, keeping the compression context. * * On fail call [[Deflate#onEnd]] with error code and return false. * @@ -224,7 +228,7 @@ Deflate.prototype.push = function(data, mode) { this.ended = true; return false; } - if (strm.avail_out === 0 || (strm.avail_in === 0 && _mode === Z_FINISH)) { + if (strm.avail_out === 0 || (strm.avail_in === 0 && (_mode === Z_FINISH || _mode === Z_SYNC_FLUSH))) { if (this.options.to === 'string') { this.onData(strings.buf2binstring(utils.shrinkBuf(strm.output, strm.next_out))); } else { @@ -241,6 +245,13 @@ Deflate.prototype.push = function(data, mode) { return status === Z_OK; } + // callback interim results if Z_SYNC_FLUSH. + if (_mode === Z_SYNC_FLUSH) { + this.onEnd(Z_OK); + strm.avail_out = 0; + return true; + } + return true; }; @@ -264,8 +275,9 @@ Deflate.prototype.onData = function(chunk) { * - status (Number): deflate status. 0 (Z_OK) on success, * other if not. * - * Called once after you tell deflate that input stream complete - * or error happenned. By default - join collected chunks, + * Called once after you tell deflate that the input stream is + * complete (Z_FINISH) or should be flushed (Z_SYNC_FLUSH) + * or if an error happened. By default - join collected chunks, * free memory and fill `results` / `err` properties. **/ Deflate.prototype.onEnd = function(status) { diff --git a/lib/inflate.js b/lib/inflate.js index 96915bc..f754336 100644 --- a/lib/inflate.js +++ b/lib/inflate.js @@ -30,7 +30,9 @@ var toString = Object.prototype.toString; * * Uncompressed result, generated by default [[Inflate#onData]] * and [[Inflate#onEnd]] handlers. Filled after you push last chunk - * (call [[Inflate#push]] with `Z_FINISH` / `true` param). + * (call [[Inflate#push]] with `Z_FINISH` / `true` param) or if you + * push a chunk with explicit flush (call [[Inflate#push]] with + * `Z_SYNC_FLUSH` param). **/ /** @@ -150,8 +152,9 @@ var Inflate = function(options) { * * Sends input data to inflate pipe, generating [[Inflate#onData]] calls with * new output chunks. Returns `true` on success. The last data block must have - * mode Z_FINISH (or `true`). That flush internal pending buffers and call - * [[Inflate#onEnd]]. + * mode Z_FINISH (or `true`). That will flush internal pending buffers and call + * [[Inflate#onEnd]]. For interim explicit flushes (without ending the stream) you + * can use mode Z_SYNC_FLUSH, keeping the decompression context. * * On fail call [[Inflate#onEnd]] with error code and return false. * @@ -207,7 +210,7 @@ Inflate.prototype.push = function(data, mode) { } if (strm.next_out) { - if (strm.avail_out === 0 || status === c.Z_STREAM_END || (strm.avail_in === 0 && _mode === c.Z_FINISH)) { + if (strm.avail_out === 0 || status === c.Z_STREAM_END || (strm.avail_in === 0 && (_mode === c.Z_FINISH || _mode === c.Z_SYNC_FLUSH))) { if (this.options.to === 'string') { @@ -233,6 +236,7 @@ Inflate.prototype.push = function(data, mode) { if (status === c.Z_STREAM_END) { _mode = c.Z_FINISH; } + // Finalize on the last chunk. if (_mode === c.Z_FINISH) { status = zlib_inflate.inflateEnd(this.strm); @@ -241,6 +245,13 @@ Inflate.prototype.push = function(data, mode) { return status === c.Z_OK; } + // callback interim results if Z_SYNC_FLUSH. + if (_mode === c.Z_SYNC_FLUSH) { + this.onEnd(c.Z_OK); + strm.avail_out = 0; + return true; + } + return true; }; @@ -264,8 +275,9 @@ Inflate.prototype.onData = function(chunk) { * - status (Number): inflate status. 0 (Z_OK) on success, * other if not. * - * Called once after you tell inflate that input stream complete - * or error happenned. By default - join collected chunks, + * Called either after you tell inflate that the input stream is + * complete (Z_FINISH) or should be flushed (Z_SYNC_FLUSH) + * or if an error happened. By default - join collected chunks, * free memory and fill `results` / `err` properties. **/ Inflate.prototype.onEnd = function(status) {