mirror of
https://github.com/danbulant/pngjs
synced 2026-07-07 12:10:59 +00:00
* Fixed bug #78. Implemented support for PNGs with unterminated IDAT stream. Implemented synchronous inflater with length limit support. * Removed duplicate line. * Fixing linter errors. * Fixing linter errors. * no finishFlushFlag on Node 4 * It now passes tests on Node 4
This commit is contained in:
parent
8bb2686bb9
commit
70f55344de
4 changed files with 204 additions and 6 deletions
|
|
@ -46,12 +46,48 @@ ParserAsync.prototype._handleError = function(err) {
|
||||||
|
|
||||||
ParserAsync.prototype._inflateData = function(data) {
|
ParserAsync.prototype._inflateData = function(data) {
|
||||||
if (!this._inflate) {
|
if (!this._inflate) {
|
||||||
this._inflate = zlib.createInflate();
|
if (this._bitmapInfo.interlace) {
|
||||||
|
this._inflate = zlib.createInflate();
|
||||||
|
|
||||||
this._inflate.on('error', this.emit.bind(this, 'error'));
|
this._inflate.on('error', this.emit.bind(this, 'error'));
|
||||||
this._filter.on('complete', this._complete.bind(this));
|
this._filter.on('complete', this._complete.bind(this));
|
||||||
|
|
||||||
this._inflate.pipe(this._filter);
|
this._inflate.pipe(this._filter);
|
||||||
|
} else {
|
||||||
|
var rowSize = ((this._bitmapInfo.width * this._bitmapInfo.bpp * this._bitmapInfo.depth + 7) >> 3) + 1;
|
||||||
|
var imageSize = rowSize * this._bitmapInfo.height;
|
||||||
|
var chunkSize = Math.max(imageSize, zlib.Z_MIN_CHUNK);
|
||||||
|
|
||||||
|
this._inflate = zlib.createInflate({ chunkSize: chunkSize });
|
||||||
|
var leftToInflate = imageSize;
|
||||||
|
|
||||||
|
var emitError = this.emit.bind(this, 'error');
|
||||||
|
this._inflate.on('error', function(err) {
|
||||||
|
if (!leftToInflate) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
emitError(err);
|
||||||
|
});
|
||||||
|
this._filter.on('complete', this._complete.bind(this));
|
||||||
|
|
||||||
|
var filterWrite = this._filter.write.bind(this._filter);
|
||||||
|
this._inflate.on('data', function(chunk) {
|
||||||
|
if (!leftToInflate) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chunk.length > leftToInflate) {
|
||||||
|
chunk = chunk.slice(0, leftToInflate);
|
||||||
|
}
|
||||||
|
|
||||||
|
leftToInflate -= chunk.length;
|
||||||
|
|
||||||
|
filterWrite(chunk);
|
||||||
|
});
|
||||||
|
|
||||||
|
this._inflate.on('end', this._filter.end.bind(this._filter));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
this._inflate.write(data);
|
this._inflate.write(data);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
var hasSyncZlib = true;
|
var hasSyncZlib = true;
|
||||||
var zlib = require('zlib');
|
var zlib = require('zlib');
|
||||||
|
var inflateSync = require('./sync-inflate');
|
||||||
var SyncReader = require('./sync-reader');
|
var SyncReader = require('./sync-reader');
|
||||||
var FilterSync = require('./filter-parse-sync');
|
var FilterSync = require('./filter-parse-sync');
|
||||||
var Parser = require('./parser');
|
var Parser = require('./parser');
|
||||||
|
|
@ -66,7 +67,14 @@ module.exports = function(buffer, options) {
|
||||||
var inflateData = Buffer.concat(inflateDataList);
|
var inflateData = Buffer.concat(inflateDataList);
|
||||||
inflateDataList.length = 0;
|
inflateDataList.length = 0;
|
||||||
|
|
||||||
var inflatedData = zlib.inflateSync(inflateData);
|
var inflatedData;
|
||||||
|
if (metaData.interlace) {
|
||||||
|
inflatedData = zlib.inflateSync(inflateData);
|
||||||
|
} else {
|
||||||
|
var rowSize = ((metaData.width * metaData.bpp * metaData.depth + 7) >> 3) + 1;
|
||||||
|
var imageSize = rowSize * metaData.height;
|
||||||
|
inflatedData = inflateSync(inflateData, { chunkSize: imageSize, maxLength: imageSize });
|
||||||
|
}
|
||||||
inflateData = null;
|
inflateData = null;
|
||||||
|
|
||||||
if (!inflatedData || !inflatedData.length) {
|
if (!inflatedData || !inflatedData.length) {
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,6 @@ var Parser = module.exports = function(options, dependencies) {
|
||||||
this.palette = dependencies.palette;
|
this.palette = dependencies.palette;
|
||||||
this.parsed = dependencies.parsed;
|
this.parsed = dependencies.parsed;
|
||||||
this.inflateData = dependencies.inflateData;
|
this.inflateData = dependencies.inflateData;
|
||||||
this.inflateData = dependencies.inflateData;
|
|
||||||
this.finished = dependencies.finished;
|
this.finished = dependencies.finished;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
155
lib/sync-inflate.js
Normal file
155
lib/sync-inflate.js
Normal file
|
|
@ -0,0 +1,155 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var assert = require('assert').ok;
|
||||||
|
var zlib = require('zlib');
|
||||||
|
var util = require('util');
|
||||||
|
|
||||||
|
var kMaxLength = require('buffer').kMaxLength;
|
||||||
|
|
||||||
|
function Inflate(opts) {
|
||||||
|
if (!(this instanceof Inflate)) {
|
||||||
|
return new Inflate(opts);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opts && opts.chunkSize < zlib.Z_MIN_CHUNK) {
|
||||||
|
opts.chunkSize = zlib.Z_MIN_CHUNK;
|
||||||
|
}
|
||||||
|
|
||||||
|
zlib.Inflate.call(this, opts);
|
||||||
|
|
||||||
|
if (opts && opts.maxLength != null) {
|
||||||
|
this._maxLength = opts.maxLength;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function createInflate(opts) {
|
||||||
|
return new Inflate(opts);
|
||||||
|
}
|
||||||
|
|
||||||
|
function _close(engine, callback) {
|
||||||
|
if (callback) {
|
||||||
|
process.nextTick(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Caller may invoke .close after a zlib error (which will null _handle).
|
||||||
|
if (!engine._handle) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
engine._handle.close();
|
||||||
|
engine._handle = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Inflate.prototype._processChunk = function(chunk, flushFlag, asyncCb) {
|
||||||
|
if (typeof asyncCb === 'function') {
|
||||||
|
return zlib.Inflate._processChunk.call(this, chunk, flushFlag, asyncCb);
|
||||||
|
}
|
||||||
|
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
var availInBefore = chunk && chunk.length;
|
||||||
|
var availOutBefore = this._chunkSize - this._offset;
|
||||||
|
var leftToInflate = this._maxLength;
|
||||||
|
var inOff = 0;
|
||||||
|
|
||||||
|
var buffers = [];
|
||||||
|
var nread = 0;
|
||||||
|
|
||||||
|
var error;
|
||||||
|
this.on('error', function(err) {
|
||||||
|
error = err;
|
||||||
|
});
|
||||||
|
|
||||||
|
function handleChunk(availInAfter, availOutAfter) {
|
||||||
|
if (self._hadError) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var have = availOutBefore - availOutAfter;
|
||||||
|
assert(have >= 0, 'have should not go down');
|
||||||
|
|
||||||
|
if (have > 0) {
|
||||||
|
var out = self._buffer.slice(self._offset, self._offset + have);
|
||||||
|
self._offset += have;
|
||||||
|
|
||||||
|
if (out.length > leftToInflate) {
|
||||||
|
out = out.slice(0, leftToInflate);
|
||||||
|
}
|
||||||
|
|
||||||
|
buffers.push(out);
|
||||||
|
nread += out.length;
|
||||||
|
leftToInflate -= out.length;
|
||||||
|
|
||||||
|
if (leftToInflate === 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (availOutAfter === 0 || self._offset >= self._chunkSize) {
|
||||||
|
availOutBefore = self._chunkSize;
|
||||||
|
self._offset = 0;
|
||||||
|
self._buffer = Buffer.allocUnsafe(self._chunkSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (availOutAfter === 0) {
|
||||||
|
inOff += (availInBefore - availInAfter);
|
||||||
|
availInBefore = availInAfter;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(this._handle, 'zlib binding closed');
|
||||||
|
do {
|
||||||
|
var res = this._handle.writeSync(flushFlag,
|
||||||
|
chunk, // in
|
||||||
|
inOff, // in_off
|
||||||
|
availInBefore, // in_len
|
||||||
|
this._buffer, // out
|
||||||
|
this._offset, //out_off
|
||||||
|
availOutBefore); // out_len
|
||||||
|
} while (!this._hadError && handleChunk(res[0], res[1]));
|
||||||
|
|
||||||
|
if (this._hadError) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nread >= kMaxLength) {
|
||||||
|
_close(this);
|
||||||
|
throw new RangeError('Cannot create final Buffer. It would be larger than 0x' + kMaxLength.toString(16) + ' bytes');
|
||||||
|
}
|
||||||
|
|
||||||
|
var buf = Buffer.concat(buffers, nread);
|
||||||
|
_close(this);
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
};
|
||||||
|
|
||||||
|
util.inherits(Inflate, zlib.Inflate);
|
||||||
|
|
||||||
|
function zlibBufferSync(engine, buffer) {
|
||||||
|
if (typeof buffer === 'string') {
|
||||||
|
buffer = Buffer.from(buffer);
|
||||||
|
}
|
||||||
|
if (!(buffer instanceof Buffer)) {
|
||||||
|
throw new TypeError('Not a string or buffer');
|
||||||
|
}
|
||||||
|
|
||||||
|
var flushFlag = engine._finishFlushFlag;
|
||||||
|
if (flushFlag == null) {
|
||||||
|
flushFlag = zlib.Z_FINISH;
|
||||||
|
}
|
||||||
|
|
||||||
|
return engine._processChunk(buffer, flushFlag);
|
||||||
|
}
|
||||||
|
|
||||||
|
function inflateSync(buffer, opts) {
|
||||||
|
return zlibBufferSync(new Inflate(opts), buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = exports = inflateSync;
|
||||||
|
exports.Inflate = Inflate;
|
||||||
|
exports.createInflate = createInflate;
|
||||||
|
exports.inflateSync = inflateSync;
|
||||||
Loading…
Reference in a new issue