From 5e3ad3d09d6c0cef60520adc17af2a1c5fac8cb8 Mon Sep 17 00:00:00 2001 From: "Ryan X. Charles" <ryan@bitpay.com> Date: Mon, 18 Aug 2014 18:04:47 -0700 Subject: [PATCH] BufferReader --- lib/bufferreader.js | 90 +++++++++++++++++++ test/test.bufferreader.js | 177 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 267 insertions(+) create mode 100644 lib/bufferreader.js create mode 100644 test/test.bufferreader.js diff --git a/lib/bufferreader.js b/lib/bufferreader.js new file mode 100644 index 0000000..fc06b17 --- /dev/null +++ b/lib/bufferreader.js @@ -0,0 +1,90 @@ +var BufferReader = function BufferReader(buf, pos) { + if (!(this instanceof BufferReader)) + return new BufferReader(buf); + this.buf = buf; + this.pos = pos || 0; +}; + +BufferReader.prototype.eof = function eof() { + return this.pos >= this.buf.length; +}; + +BufferReader.prototype.read = function() { + var buf = this.buf.slice(this.pos); + this.pos = this.buf.length; + return buf; +}; + +BufferReader.prototype.readUInt8 = function() { + var val = this.buf.readUInt8(this.pos); + this.pos = this.pos + 1; + return val; +}; + +BufferReader.prototype.readUInt16BE = function() { + var val = this.buf.readUInt16BE(this.pos); + this.pos = this.pos + 2; + return val; +}; + +BufferReader.prototype.readUInt16LE = function() { + var val = this.buf.readUInt16LE(this.pos); + this.pos = this.pos + 2; + return val; +}; + +BufferReader.prototype.readUInt32BE = function() { + var val = this.buf.readUInt32BE(this.pos); + this.pos = this.pos + 4; + return val; +}; + +BufferReader.prototype.readUInt32LE = function() { + var val = this.buf.readUInt32LE(this.pos); + this.pos = this.pos + 4; + return val; +}; + +//TODO: What if n is so large that it loses precision? +BufferReader.prototype.readUInt64BE = function() { + var val = 0; + for (var i = 0; i < 8; i++) { + val += Math.pow(256, i) * this.buf[this.pos + 8 - 1 - i]; + } + this.pos = this.pos + 8; + return val; +}; + +//TODO: What if n is so large that it loses precision? +BufferReader.prototype.readUInt64LE = function() { + var val = 0; + for (var i = 0; i < 8; i++) { + val += Math.pow(256, i) * this.buf[this.pos + i]; + } + this.pos = this.pos + 8; + return val; +}; + +BufferReader.prototype.readVarInt = function() { + var first = this.readUInt8(); + switch (first) { + case 0xFD: + return this.readUInt16LE(); + case 0xFE: + return this.readUInt32LE(); + case 0xFF: + return this.readUInt64LE(); + default: + return first; + } +}; + +BufferReader.prototype.reverse = function() { + var buf = new Buffer(this.buf.length); + for (var i = 0; i < buf.length; i++) + buf[i] = this.buf[this.buf.length - 1 - i] + this.buf = buf; + return this; +}; + +module.exports = BufferReader; diff --git a/test/test.bufferreader.js b/test/test.bufferreader.js new file mode 100644 index 0000000..bca7b63 --- /dev/null +++ b/test/test.bufferreader.js @@ -0,0 +1,177 @@ +var BufferReader = require('../lib/bufferreader'); +var should = require('chai').should(); + +describe('BufferReader', function() { + + it('should make a new BufferReader', function() { + var br = new BufferReader(); + should.exist(br); + }); + + describe('#eof', function() { + + it('should return true for a blank br', function() { + var br = new BufferReader(new Buffer([])); + br.eof().should.equal(true); + }); + + }); + + describe('read', function() { + + it('should return the same buffer', function() { + var buf = new Buffer([0]); + var br = new BufferReader(buf); + br.read().toString('hex').should.equal(buf.toString('hex')); + }); + + }); + + describe('#readUInt8', function() { + + it('should return 1', function() { + var buf = new Buffer(1); + buf.writeUInt8(1, 0); + var br = new BufferReader(buf); + br.readUInt8().should.equal(1); + }); + + }); + + describe('#readUInt16BE', function() { + + it('should return 1', function() { + var buf = new Buffer(2); + buf.writeUInt16BE(1, 0); + var br = new BufferReader(buf); + br.readUInt16BE().should.equal(1); + }); + + }); + + describe('#readUInt16LE', function() { + + it('should return 1', function() { + var buf = new Buffer(2); + buf.writeUInt16LE(1, 0); + var br = new BufferReader(buf); + br.readUInt16LE().should.equal(1); + }); + + }); + + describe('#readUInt32BE', function() { + + it('should return 1', function() { + var buf = new Buffer(4); + buf.writeUInt32BE(1, 0); + var br = new BufferReader(buf); + br.readUInt32BE().should.equal(1); + }); + + }); + + describe('#readUInt32LE', function() { + + it('should return 1', function() { + var buf = new Buffer(4); + buf.writeUInt32LE(1, 0); + var br = new BufferReader(buf); + br.readUInt32LE().should.equal(1); + }); + + }); + + describe('#readUInt64BE', function() { + + it('should return 1', function() { + var buf = new Buffer(8); + buf.fill(0); + buf.writeUInt32BE(1, 4); + var br = new BufferReader(buf); + br.readUInt64BE().should.equal(1); + }); + + it('should return 2^64', function() { + var buf = new Buffer(8); + buf.fill(0xff); + var br = new BufferReader(buf); + br.readUInt64BE().should.equal(Math.pow(2, 64)); + }); + + }); + + describe('#readUInt64LE', function() { + + it('should return 1', function() { + var buf = new Buffer(8); + buf.fill(0); + buf.writeUInt32LE(1, 0); + var br = new BufferReader(buf); + br.readUInt64LE().should.equal(1); + }); + + it('should return 2^30', function() { + var buf = new Buffer(8); + buf.fill(0); + buf.writeUInt32LE(Math.pow(2, 30), 0); + var br = new BufferReader(buf); + br.readUInt64LE().should.equal(Math.pow(2, 30)); + }); + + it('should return 0', function() { + var buf = new Buffer(8); + buf.fill(0); + var br = new BufferReader(buf); + br.readUInt64LE().should.equal(0); + }); + + it('should return 2^64', function() { + var buf = new Buffer(8); + buf.fill(0xff); + var br = new BufferReader(buf); + br.readUInt64LE().should.equal(Math.pow(2, 64)); + }); + + }); + + describe('#readVarInt', function() { + + it('should read a 1 byte varint', function() { + var buf = new Buffer([50]); + var br = new BufferReader(buf); + br.readVarInt().should.equal(50); + }); + + it('should read a 3 byte varint', function() { + var buf = new Buffer([253, 253, 0]); + var br = new BufferReader(buf); + br.readVarInt().should.equal(253); + }); + + it('should read a 5 byte varint', function() { + var buf = new Buffer([254, 0, 0, 0, 0]); + buf.writeUInt32LE(50000, 1); + var br = new BufferReader(buf); + br.readVarInt().should.equal(50000); + }); + + it('should read a 9 byte varint', function() { + var buf = Buffer.concat([new Buffer([255]), new Buffer('ffffffffffffffff', 'hex')]); + var br = new BufferReader(buf); + br.readVarInt().should.equal(Math.pow(2, 64)); + }); + + }); + + describe('#reverse', function() { + + it('should reverse this [0, 1]', function() { + var buf = new Buffer([0, 1]); + var br = new BufferReader(buf); + br.reverse().read().toString('hex').should.equal('0100'); + }); + + }); + +});