Browse Source

buffer: add generic functions for (u)int ops

Add generic functions for (U)Int read/write operations on Buffers. These
support up to and including 48 bit reads and writes.

Include documentation and tests.

Additional work done by Trevor Norris to include 40 and 48 bit write
support. Because bitwise operations cannot be used on values greater
than 32 bits, the operations have been replaced with mathematical
calculations. Regardless, they are still faster than floating point
operations.

Reviewed-by: Trevor Norris <trev.norris@gmail.com>
v0.11.15-release
Yazhong Liu 10 years ago
committed by Trevor Norris
parent
commit
83d7d9e6d8
  1. 42
      doc/api/buffer.markdown
  2. 151
      lib/buffer.js
  3. 87
      test/simple/test-buffer.js

42
doc/api/buffer.markdown

@ -180,6 +180,48 @@ The method will not write partial characters.
len = buf.write('\u00bd + \u00bc = \u00be', 0);
console.log(len + " bytes: " + buf.toString('utf8', 0, len));
### buf.writeUIntLE(value, offset, byteLength[, noAssert])
### buf.writeUIntBE(value, offset, byteLength[, noAssert])
### buf.writeIntLE(value, offset, byteLength[, noAssert])
### buf.writeIntBE(value, offset, byteLength[, noAssert])
* `value` {Number} Bytes to be written to buffer
* `offset` {Number} `0 <= offset <= buf.length`
* `byteLength` {Number} `0 < byteLength <= 6`
* `noAssert` {Boolean} Default: false
* Return: {Number}
Writes `value` to the buffer at the specified `offset` and `byteLength`.
Supports up to 48 bits of accuracy. For example:
var b = new Buffer(6);
b.writeUIntBE(0x1234567890ab, 0, 6);
// <Buffer 12 34 56 78 90 ab>
Set `noAssert` to `true` to skip validation of `value` and `offset`. Defaults
to `false`.
### buf.readUIntLE(offset, byteLength[, noAssert])
### buf.readUIntBE(offset, byteLength[, noAssert])
### buf.readIntLE(offset, byteLength[, noAssert])
### buf.readIntBE(offset, byteLength[, noAssert])
* `offset` {Number} `0 <= offset <= buf.length`
* `byteLength` {Number} `0 < byteLength <= 6`
* `noAssert` {Boolean} Default: false
* Return: {Number}
A generalized version of all numeric read methods. Supports up to 48 bits of
accuracy. For example:
var b = new Buffer(6);
b.writeUint16LE(0x90ab, 0);
b.writeUInt32LE(0x12345678, 2);
b.readUIntLE(0, 6).toString(16); // Specify 6 bytes (48 bits)
// output: '1234567890ab'
Set `noAssert` to true to skip validation of `offset`. This means that `offset`
may be beyond the end of the buffer. Defaults to `false`.
### buf.toString([encoding][, start][, end])

151
lib/buffer.js

@ -482,6 +482,37 @@ function checkOffset(offset, ext, length) {
}
Buffer.prototype.readUIntLE = function(offset, byteLength, noAssert) {
offset = offset >>> 0;
byteLength = byteLength >>> 0;
if (!noAssert)
checkOffset(offset, byteLength, this.length);
var val = this[offset];
var mul = 1;
var i = 0;
while (++i < byteLength && (mul *= 0x100))
val += this[offset + i] * mul;
return val;
};
Buffer.prototype.readUIntBE = function(offset, byteLength, noAssert) {
offset = offset >>> 0;
byteLength = byteLength >>> 0;
if (!noAssert)
checkOffset(offset, byteLength, this.length);
var val = this[offset + --byteLength];
var mul = 1;
while (byteLength > 0 && (mul *= 0x100))
val += this[offset + --byteLength] * mul;
return val;
};
Buffer.prototype.readUInt8 = function(offset, noAssert) {
offset = offset >>> 0;
if (!noAssert)
@ -530,6 +561,46 @@ Buffer.prototype.readUInt32BE = function(offset, noAssert) {
};
Buffer.prototype.readIntLE = function(offset, byteLength, noAssert) {
offset = offset >>> 0;
byteLength = byteLength >>> 0;
if (!noAssert)
checkOffset(offset, byteLength, this.length);
var val = this[offset];
var mul = 1;
var i = 0;
while (++i < byteLength && (mul *= 0x100))
val += this[offset + i] * mul;
mul *= 0x80;
if (val >= mul)
val -= Math.pow(2, 8 * byteLength);
return val;
};
Buffer.prototype.readIntBE = function(offset, byteLength, noAssert) {
offset = offset >>> 0;
byteLength = byteLength >>> 0;
if (!noAssert)
checkOffset(offset, byteLength, this.length);
var i = byteLength;
var mul = 1;
var val = this[offset + --i];
while (i > 0 && (mul *= 0x100))
val += this[offset + --i] * mul;
mul *= 0x80;
if (val >= mul)
val -= Math.pow(2, 8 * byteLength);
return val;
};
Buffer.prototype.readInt8 = function(offset, noAssert) {
offset = offset >>> 0;
if (!noAssert)
@ -623,6 +694,40 @@ function checkInt(buffer, value, offset, ext, max, min) {
}
Buffer.prototype.writeUIntLE = function(value, offset, byteLength, noAssert) {
value = +value;
offset = offset >>> 0;
byteLength = byteLength >>> 0;
if (!noAssert)
checkInt(this, value, offset, byteLength, Math.pow(2, 8 * byteLength), 0);
var mul = 1;
var i = 0;
this[offset] = value;
while (++i < byteLength && (mul *= 0x100))
this[offset + i] = (value / mul) >>> 0;
return offset + byteLength;
};
Buffer.prototype.writeUIntBE = function(value, offset, byteLength, noAssert) {
value = +value;
offset = offset >>> 0;
byteLength = byteLength >>> 0;
if (!noAssert)
checkInt(this, value, offset, byteLength, Math.pow(2, 8 * byteLength), 0);
var i = byteLength - 1;
var mul = 1;
this[offset + i] = value;
while (--i >= 0 && (mul *= 0x100))
this[offset + i] = (value / mul) >>> 0;
return offset + byteLength;
};
Buffer.prototype.writeUInt8 = function(value, offset, noAssert) {
value = +value;
offset = offset >>> 0;
@ -681,6 +786,52 @@ Buffer.prototype.writeUInt32BE = function(value, offset, noAssert) {
};
Buffer.prototype.writeIntLE = function(value, offset, byteLength, noAssert) {
value = +value;
offset = offset >>> 0;
if (!noAssert) {
checkInt(this,
value,
offset,
byteLength,
Math.pow(2, 8 * byteLength - 1) - 1,
-Math.pow(2, 8 * byteLength - 1));
}
var i = 0;
var mul = 1;
var sub = value < 0 ? 1 : 0;
this[offset] = value;
while (++i < byteLength && (mul *= 0x100))
this[offset + i] = ((value / mul) >> 0) - sub;
return offset + byteLength;
};
Buffer.prototype.writeIntBE = function(value, offset, byteLength, noAssert) {
value = +value;
offset = offset >>> 0;
if (!noAssert) {
checkInt(this,
value,
offset,
byteLength,
Math.pow(2, 8 * byteLength - 1) - 1,
-Math.pow(2, 8 * byteLength - 1));
}
var i = byteLength - 1;
var mul = 1;
var sub = value < 0 ? 1 : 0;
this[offset + i] = value;
while (--i >= 0 && (mul *= 0x100))
this[offset + i] = ((value / mul) >> 0) - sub;
return offset + byteLength;
};
Buffer.prototype.writeInt8 = function(value, offset, noAssert) {
value = +value;
offset = offset >>> 0;

87
test/simple/test-buffer.js

@ -950,8 +950,6 @@ var buf = new Buffer([0xFF]);
assert.equal(buf.readUInt8(0), 255);
assert.equal(buf.readInt8(0), -1);
[16, 32].forEach(function(bits) {
var buf = new Buffer(bits / 8 - 1);
@ -988,6 +986,91 @@ assert.equal(buf.readInt8(0), -1);
(0xFFFFFFFF >> (32 - bits)));
});
// test for common read(U)IntLE/BE
(function() {
var buf = new Buffer([0x01, 0x02, 0x03, 0x04, 0x05, 0x06]);
assert.equal(buf.readUIntLE(0, 1), 0x01);
assert.equal(buf.readUIntBE(0, 1), 0x01);
assert.equal(buf.readUIntLE(0, 3), 0x030201);
assert.equal(buf.readUIntBE(0, 3), 0x010203);
assert.equal(buf.readUIntLE(0, 5), 0x0504030201);
assert.equal(buf.readUIntBE(0, 5), 0x0102030405);
assert.equal(buf.readUIntLE(0, 6), 0x060504030201);
assert.equal(buf.readUIntBE(0, 6), 0x010203040506);
assert.equal(buf.readIntLE(0, 1), 0x01);
assert.equal(buf.readIntBE(0, 1), 0x01);
assert.equal(buf.readIntLE(0, 3), 0x030201);
assert.equal(buf.readIntBE(0, 3), 0x010203);
assert.equal(buf.readIntLE(0, 5), 0x0504030201);
assert.equal(buf.readIntBE(0, 5), 0x0102030405);
assert.equal(buf.readIntLE(0, 6), 0x060504030201);
assert.equal(buf.readIntBE(0, 6), 0x010203040506);
})();
// test for common write(U)IntLE/BE
(function() {
var buf = new Buffer(3);
buf.writeUIntLE(0x123456, 0, 3);
assert.deepEqual(buf.toJSON().data, [0x56, 0x34, 0x12]);
assert.equal(buf.readUIntLE(0, 3), 0x123456);
buf = new Buffer(3);
buf.writeUIntBE(0x123456, 0, 3);
assert.deepEqual(buf.toJSON().data, [0x12, 0x34, 0x56]);
assert.equal(buf.readUIntBE(0, 3), 0x123456);
buf = new Buffer(3);
buf.writeIntLE(0x123456, 0, 3);
assert.deepEqual(buf.toJSON().data, [0x56, 0x34, 0x12]);
assert.equal(buf.readIntLE(0, 3), 0x123456);
buf = new Buffer(3);
buf.writeIntBE(0x123456, 0, 3);
assert.deepEqual(buf.toJSON().data, [0x12, 0x34, 0x56]);
assert.equal(buf.readIntBE(0, 3), 0x123456);
buf = new Buffer(3);
buf.writeIntLE(-0x123456, 0, 3);
assert.deepEqual(buf.toJSON().data, [0xaa, 0xcb, 0xed]);
assert.equal(buf.readIntLE(0, 3), -0x123456);
buf = new Buffer(3);
buf.writeIntBE(-0x123456, 0, 3);
assert.deepEqual(buf.toJSON().data, [0xed, 0xcb, 0xaa]);
assert.equal(buf.readIntBE(0, 3), -0x123456);
buf = new Buffer(5);
buf.writeUIntLE(0x1234567890, 0, 5);
assert.deepEqual(buf.toJSON().data, [0x90, 0x78, 0x56, 0x34, 0x12]);
assert.equal(buf.readUIntLE(0, 5), 0x1234567890);
buf = new Buffer(5);
buf.writeUIntBE(0x1234567890, 0, 5);
assert.deepEqual(buf.toJSON().data, [0x12, 0x34, 0x56, 0x78, 0x90]);
assert.equal(buf.readUIntBE(0, 5), 0x1234567890);
buf = new Buffer(5);
buf.writeIntLE(0x1234567890, 0, 5);
assert.deepEqual(buf.toJSON().data, [0x90, 0x78, 0x56, 0x34, 0x12]);
assert.equal(buf.readIntLE(0, 5), 0x1234567890);
buf = new Buffer(5);
buf.writeIntBE(0x1234567890, 0, 5);
assert.deepEqual(buf.toJSON().data, [0x12, 0x34, 0x56, 0x78, 0x90]);
assert.equal(buf.readIntBE(0, 5), 0x1234567890);
buf = new Buffer(5);
buf.writeIntLE(-0x1234567890, 0, 5);
assert.deepEqual(buf.toJSON().data, [0x70, 0x87, 0xa9, 0xcb, 0xed]);
assert.equal(buf.readIntLE(0, 5), -0x1234567890);
buf = new Buffer(5);
buf.writeIntBE(-0x1234567890, 0, 5);
assert.deepEqual(buf.toJSON().data, [0xed, 0xcb, 0xa9, 0x87, 0x70]);
assert.equal(buf.readIntBE(0, 5), -0x1234567890);
})();
// test Buffer slice
(function() {
var buf = new Buffer('0123456789');

Loading…
Cancel
Save