module.exports = Buffers; function Buffers (bufs) { if (!(this instanceof Buffers)) return new Buffers(bufs); this.buffers = bufs || []; this.length = this.buffers.reduce(function (size, buf) { return size + buf.length }, 0); } Buffers.prototype.push = function () { for (var i = 0; i < arguments.length; i++) { if (!Buffer.isBuffer(arguments[i])) { throw new TypeError('Tried to push a non-buffer'); } } for (var i = 0; i < arguments.length; i++) { var buf = arguments[i]; this.buffers.push(buf); this.length += buf.length; } return this.length; }; Buffers.prototype.unshift = function () { for (var i = 0; i < arguments.length; i++) { if (!Buffer.isBuffer(arguments[i])) { throw new TypeError('Tried to unshift a non-buffer'); } } for (var i = 0; i < arguments.length; i++) { var buf = arguments[i]; this.buffers.unshift(buf); this.length += buf.length; } return this.length; }; Buffers.prototype.copy = function (dst, dStart, start, end) { return this.slice(start, end).copy(dst, dStart, 0, end - start); }; Buffers.prototype.splice = function (i, howMany) { var buffers = this.buffers; var index = i >= 0 ? i : this.length - i; var reps = [].slice.call(arguments, 2); if (howMany === undefined) { howMany = this.length - index; } else if (howMany > this.length - index) { howMany = this.length - index; } for (var i = 0; i < reps.length; i++) { this.length += reps[i].length; } var removed = new Buffers(); var bytes = 0; var startBytes = 0; for ( var ii = 0; ii < buffers.length && startBytes + buffers[ii].length < index; ii ++ ) { startBytes += buffers[ii].length } if (index - startBytes > 0) { var start = index - startBytes; if (start + howMany < buffers[ii].length) { removed.push(buffers[ii].slice(start, start + howMany)); var orig = buffers[ii]; //var buf = new Buffer(orig.length - howMany); var buf0 = new Buffer(start); for (var i = 0; i < start; i++) { buf0[i] = orig[i]; } var buf1 = new Buffer(orig.length - start - howMany); for (var i = start + howMany; i < orig.length; i++) { buf1[ i - howMany - start ] = orig[i] } if (reps.length > 0) { var reps_ = reps.slice(); reps_.unshift(buf0); reps_.push(buf1); buffers.splice.apply(buffers, [ ii, 1 ].concat(reps_)); ii += reps_.length; reps = []; } else { buffers.splice(ii, 1, buf0, buf1); //buffers[ii] = buf; ii += 2; } } else { removed.push(buffers[ii].slice(start)); buffers[ii] = buffers[ii].slice(0, start); ii ++; } } if (reps.length > 0) { buffers.splice.apply(buffers, [ ii, 0 ].concat(reps)); ii += reps.length; } while (removed.length < howMany) { var buf = buffers[ii]; var len = buf.length; var take = Math.min(len, howMany - removed.length); if (take === len) { removed.push(buf); buffers.splice(ii, 1); } else { removed.push(buf.slice(0, take)); buffers[ii] = buffers[ii].slice(take); } } this.length -= removed.length; return removed; }; Buffers.prototype.slice = function (i, j) { var buffers = this.buffers; if (j === undefined) j = this.length; if (i === undefined) i = 0; if (j > this.length) j = this.length; var startBytes = 0; for ( var si = 0; si < buffers.length && startBytes + buffers[si].length <= i; si ++ ) { startBytes += buffers[si].length } var target = new Buffer(j - i); var ti = 0; for (var ii = si; ti < j - i && ii < buffers.length; ii++) { var len = buffers[ii].length; var start = ti === 0 ? i - startBytes : 0; var end = ti + len >= j - i ? Math.min(start + (j - i) - ti, len) : len ; buffers[ii].copy(target, ti, start, end); ti += end - start; } return target; }; Buffers.prototype.pos = function (i) { if (i < 0 || i >= this.length) throw new Error('oob'); var l = i, bi = 0, bu = null; for (;;) { bu = this.buffers[bi]; if (l < bu.length) { return {buf: bi, offset: l}; } else { l -= bu.length; } bi++; } }; Buffers.prototype.get = function get (i) { var pos = this.pos(i); return this.buffers[pos.buf].get(pos.offset); }; Buffers.prototype.set = function set (i, b) { var pos = this.pos(i); return this.buffers[pos.buf].set(pos.offset, b); }; Buffers.prototype.indexOf = function (needle, offset) { if ("string" === typeof needle) { needle = new Buffer(needle); } else if (needle instanceof Buffer) { // already a buffer } else { throw new Error('Invalid type for a search string'); } if (!needle.length) { return 0; } if (!this.length) { return -1; } var i = 0, j = 0, match = 0, mstart, pos = 0; // start search from a particular point in the virtual buffer if (offset) { var p = this.pos(offset); i = p.buf; j = p.offset; pos = offset; } // for each character in virtual buffer for (;;) { while (j >= this.buffers[i].length) { j = 0; i++; if (i >= this.buffers.length) { // search string not found return -1; } } var char = this.buffers[i][j]; if (char == needle[match]) { // keep track where match started if (match == 0) { mstart = { i: i, j: j, pos: pos }; } match++; if (match == needle.length) { // full match return mstart.pos; } } else if (match != 0) { // a partial match ended, go back to match starting position // this will continue the search at the next character i = mstart.i; j = mstart.j; pos = mstart.pos; match = 0; } j++; pos++; } }; Buffers.prototype.toBuffer = function() { return this.slice(); } Buffers.prototype.toString = function(encoding, start, end) { return this.slice(start, end).toString(encoding); }