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>
This commit is contained in:
parent
e9ca7b9d8d
commit
83d7d9e6d8
@ -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
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;
|
||||
|
@ -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…
x
Reference in New Issue
Block a user