From f8ff2ef7dde535a509814d100b6bebbde0cb5053 Mon Sep 17 00:00:00 2001 From: Solly Ross Date: Tue, 22 Sep 2015 16:19:52 -0400 Subject: [PATCH] Make sure Pako always has enough room Previously, we used a fixed chunkSize of 100KiB for Pako's output buffer. Using a hardcoded size caused issues, since Pako would assume we wanted to use multiple chunks, and we didn't deal with this. Now, `Inflator#inflate()` takes a new `expected` argument, which indicates the expected output size. If this is bigger than the current chunkSize, Inflator allocates a new output buffer that's big enough to hold the output. Fixes #531 --- docs/notes | 2 +- include/inflator.js | 35 ++++++++++++++++++++++------------- include/rfb.js | 9 +++++---- utils/inflator.partial.js | 14 +++++++++++--- 4 files changed, 39 insertions(+), 21 deletions(-) diff --git a/docs/notes b/docs/notes index 6ff5ec1..036cd51 100644 --- a/docs/notes +++ b/docs/notes @@ -2,4 +2,4 @@ Rebuilding inflator.js - Download pako from npm - Install browserify using npm -- browserify utils/inflator.partial.js -o include/inflator.js +- browserify utils/inflator.partial.js -o include/inflator.js -s inflator diff --git a/include/inflator.js b/include/inflator.js index a9c75a6..48ede20 100644 --- a/include/inflator.js +++ b/include/inflator.js @@ -234,7 +234,8 @@ module.exports = function inflate_fast(strm, start) { var wsize; /* window size or zero if not using window */ var whave; /* valid bytes in the window */ var wnext; /* window write index */ - var window; /* allocated sliding window, if wsize != 0 */ + // Use `s_window` instead `window`, avoid conflict with instrumentation tools + var s_window; /* allocated sliding window, if wsize != 0 */ var hold; /* local strm.hold */ var bits; /* local strm.bits */ var lcode; /* local strm.lencode */ @@ -268,7 +269,7 @@ module.exports = function inflate_fast(strm, start) { wsize = state.wsize; whave = state.whave; wnext = state.wnext; - window = state.window; + s_window = state.window; hold = state.hold; bits = state.bits; lcode = state.lencode; @@ -386,13 +387,13 @@ module.exports = function inflate_fast(strm, start) { //#endif } from = 0; // window index - from_source = window; + from_source = s_window; if (wnext === 0) { /* very common case */ from += wsize - op; if (op < len) { /* some from window */ len -= op; do { - output[_out++] = window[from++]; + output[_out++] = s_window[from++]; } while (--op); from = _out - dist; /* rest from output */ from_source = output; @@ -404,14 +405,14 @@ module.exports = function inflate_fast(strm, start) { if (op < len) { /* some from end of window */ len -= op; do { - output[_out++] = window[from++]; + output[_out++] = s_window[from++]; } while (--op); from = 0; if (wnext < len) { /* some from start of window */ op = wnext; len -= op; do { - output[_out++] = window[from++]; + output[_out++] = s_window[from++]; } while (--op); from = _out - dist; /* rest from output */ from_source = output; @@ -423,7 +424,7 @@ module.exports = function inflate_fast(strm, start) { if (op < len) { /* some from window */ len -= op; do { - output[_out++] = window[from++]; + output[_out++] = s_window[from++]; } while (--op); from = _out - dist; /* rest from output */ from_source = output; @@ -2371,9 +2372,9 @@ function ZStream() { module.exports = ZStream; -},{}],"/partial_inflator.js":[function(require,module,exports){ -var zlib = require('./lib/zlib/inflate.js'); -var ZStream = require('./lib/zlib/zstream.js'); +},{}],8:[function(require,module,exports){ +var zlib = require('../node_modules/pako/lib/zlib/inflate.js'); +var ZStream = require('../node_modules/pako/lib/zlib/zstream.js'); var Inflate = function () { this.strm = new ZStream(); @@ -2385,12 +2386,20 @@ var Inflate = function () { }; Inflate.prototype = { - inflate: function (data, flush) { + inflate: function (data, flush, expected) { this.strm.input = data; this.strm.avail_in = this.strm.input.length; this.strm.next_in = 0; this.strm.next_out = 0; + // resize our output buffer if it's too small + // (we could just use multiple chunks, but that would cause an extra + // allocation each time to flatten the chunks) + if (expected > this.chunkSize) { + this.chunkSize = expected; + this.strm.output = new Uint8Array(this.chunkSize); + } + this.strm.avail_out = this.chunkSize; zlib.inflate(this.strm, flush); @@ -2405,5 +2414,5 @@ Inflate.prototype = { module.exports = {Inflate: Inflate}; -},{"./lib/zlib/inflate.js":5,"./lib/zlib/zstream.js":7}]},{},[])("/partial_inflator.js") -}); +},{"../node_modules/pako/lib/zlib/inflate.js":5,"../node_modules/pako/lib/zlib/zstream.js":7}]},{},[8])(8) +}); \ No newline at end of file diff --git a/include/rfb.js b/include/rfb.js index b45537c..4ea5fd0 100644 --- a/include/rfb.js +++ b/include/rfb.js @@ -1688,16 +1688,17 @@ var RFB; var resetStreams = 0; var streamId = -1; - var decompress = function (data) { + var decompress = function (data, expected) { for (var i = 0; i < 4; i++) { if ((resetStreams >> i) & 1) { this._FBU.zlibs[i].reset(); + console.debug('RESET!'); Util.Info("Reset zlib stream " + i); } } //var uncompressed = this._FBU.zlibs[streamId].uncompress(data, 0); - var uncompressed = this._FBU.zlibs[streamId].inflate(data, true); + var uncompressed = this._FBU.zlibs[streamId].inflate(data, true, expected); /*if (uncompressed.status !== 0) { Util.Error("Invalid data in zlib stream"); }*/ @@ -1830,7 +1831,7 @@ var RFB; if (raw) { data = this._sock.rQshiftBytes(cl_data); } else { - data = decompress(this._sock.rQshiftBytes(cl_data)); + data = decompress(this._sock.rQshiftBytes(cl_data), rowSize * this._FBU.height); } // Convert indexed (palette based) image data to RGB @@ -1879,7 +1880,7 @@ var RFB; if (raw) { data = this._sock.rQshiftBytes(cl_data); } else { - data = decompress(this._sock.rQshiftBytes(cl_data)); + data = decompress(this._sock.rQshiftBytes(cl_data), uncompressedSize); } this._display.blitRgbImage(this._FBU.x, this._FBU.y, this._FBU.width, this._FBU.height, data, 0, false); diff --git a/utils/inflator.partial.js b/utils/inflator.partial.js index 2522d78..8b6d109 100644 --- a/utils/inflator.partial.js +++ b/utils/inflator.partial.js @@ -1,5 +1,5 @@ -var zlib = require('./lib/zlib/inflate.js'); -var ZStream = require('./lib/zlib/zstream.js'); +var zlib = require('../node_modules/pako/lib/zlib/inflate.js'); +var ZStream = require('../node_modules/pako/lib/zlib/zstream.js'); var Inflate = function () { this.strm = new ZStream(); @@ -11,12 +11,20 @@ var Inflate = function () { }; Inflate.prototype = { - inflate: function (data, flush) { + inflate: function (data, flush, expected) { this.strm.input = data; this.strm.avail_in = this.strm.input.length; this.strm.next_in = 0; this.strm.next_out = 0; + // resize our output buffer if it's too small + // (we could just use multiple chunks, but that would cause an extra + // allocation each time to flatten the chunks) + if (expected > this.chunkSize) { + this.chunkSize = expected; + this.strm.output = new Uint8Array(this.chunkSize); + } + this.strm.avail_out = this.chunkSize; zlib.inflate(this.strm, flush);