Browse Source

buffer: improve read/write speed with assert

Improved assert check order of execution and added additional checks on
parameters to ensure no bad values make it through (e.g. negative offset
values).
v0.9.7-release
Trevor Norris 12 years ago
committed by isaacs
parent
commit
7393740c7b
  1. 333
      lib/buffer.js

333
lib/buffer.js

@ -616,35 +616,28 @@ Buffer.prototype.asciiWrite = function(string, offset) {
return this.write(string, offset, 'ascii'); return this.write(string, offset, 'ascii');
}; };
Buffer.prototype.readUInt8 = function(offset, noAssert) {
var buffer = this;
if (!noAssert) { /*
assert.ok(offset !== undefined && offset !== null, * Need to make sure that buffer isn't trying to write out of bounds.
'missing offset'); * This check is far too slow internally for fast buffers.
*/
function checkOffset(offset, ext, length) {
if ((offset % 1) !== 0 || offset < 0)
throw new RangeError('offset is not uint');
if (offset + ext > length)
throw new RangeError('Trying to access beyond buffer length');
}
assert.ok(offset < buffer.length,
'Trying to read beyond buffer length');
}
return buffer[offset]; Buffer.prototype.readUInt8 = function(offset, noAssert) {
if (!noAssert)
checkOffset(offset, 1, this.length);
return this[offset];
}; };
function readUInt16(buffer, offset, isBigEndian, noAssert) {
var val = 0;
if (!noAssert) {
assert.ok(typeof (isBigEndian) === 'boolean',
'missing or invalid endian');
assert.ok(offset !== undefined && offset !== null,
'missing offset');
assert.ok(offset + 1 < buffer.length,
'Trying to read beyond buffer length');
}
function readUInt16(buffer, offset, isBigEndian) {
var val = 0;
if (isBigEndian) { if (isBigEndian) {
val = buffer[offset] << 8; val = buffer[offset] << 8;
val |= buffer[offset + 1]; val |= buffer[offset + 1];
@ -656,28 +649,24 @@ function readUInt16(buffer, offset, isBigEndian, noAssert) {
return val; return val;
} }
Buffer.prototype.readUInt16LE = function(offset, noAssert) { Buffer.prototype.readUInt16LE = function(offset, noAssert) {
if (!noAssert)
checkOffset(offset, 2, this.length);
return readUInt16(this, offset, false, noAssert); return readUInt16(this, offset, false, noAssert);
}; };
Buffer.prototype.readUInt16BE = function(offset, noAssert) { Buffer.prototype.readUInt16BE = function(offset, noAssert) {
if (!noAssert)
checkOffset(offset, 2, this.length);
return readUInt16(this, offset, true, noAssert); return readUInt16(this, offset, true, noAssert);
}; };
function readUInt32(buffer, offset, isBigEndian, noAssert) { function readUInt32(buffer, offset, isBigEndian, noAssert) {
var val = 0; var val = 0;
if (!noAssert) {
assert.ok(typeof (isBigEndian) === 'boolean',
'missing or invalid endian');
assert.ok(offset !== undefined && offset !== null,
'missing offset');
assert.ok(offset + 3 < buffer.length,
'Trying to read beyond buffer length');
}
if (isBigEndian) { if (isBigEndian) {
val = buffer[offset + 1] << 16; val = buffer[offset + 1] << 16;
val |= buffer[offset + 2] << 8; val |= buffer[offset + 2] << 8;
@ -693,11 +682,17 @@ function readUInt32(buffer, offset, isBigEndian, noAssert) {
return val; return val;
} }
Buffer.prototype.readUInt32LE = function(offset, noAssert) { Buffer.prototype.readUInt32LE = function(offset, noAssert) {
if (!noAssert)
checkOffset(offset, 4, this.length);
return readUInt32(this, offset, false, noAssert); return readUInt32(this, offset, false, noAssert);
}; };
Buffer.prototype.readUInt32BE = function(offset, noAssert) { Buffer.prototype.readUInt32BE = function(offset, noAssert) {
if (!noAssert)
checkOffset(offset, 4, this.length);
return readUInt32(this, offset, true, noAssert); return readUInt32(this, offset, true, noAssert);
}; };
@ -747,113 +742,82 @@ Buffer.prototype.readUInt32BE = function(offset, noAssert) {
* (0x007f + 1) * -1 * (0x007f + 1) * -1
* (0x0080) * -1 * (0x0080) * -1
*/ */
Buffer.prototype.readInt8 = function(offset, noAssert) {
var buffer = this;
var neg;
if (!noAssert) { Buffer.prototype.readInt8 = function(offset, noAssert) {
assert.ok(offset !== undefined && offset !== null, if (!noAssert)
'missing offset'); checkOffset(offset, 1, this.length);
if (!(this[offset] & 0x80))
assert.ok(offset < buffer.length, return (this[offset]);
'Trying to read beyond buffer length'); return ((0xff - this[offset] + 1) * -1);
}
neg = buffer[offset] & 0x80;
if (!neg) {
return (buffer[offset]);
}
return ((0xff - buffer[offset] + 1) * -1);
}; };
function readInt16(buffer, offset, isBigEndian, noAssert) {
var neg, val;
if (!noAssert) { function readInt16(buffer, offset, isBigEndian) {
assert.ok(typeof (isBigEndian) === 'boolean', var val = readUInt16(buffer, offset, isBigEndian);
'missing or invalid endian');
assert.ok(offset !== undefined && offset !== null, if (!(val & 0x8000))
'missing offset');
assert.ok(offset + 1 < buffer.length,
'Trying to read beyond buffer length');
}
val = readUInt16(buffer, offset, isBigEndian, noAssert);
neg = val & 0x8000;
if (!neg) {
return val; return val;
}
return (0xffff - val + 1) * -1; return (0xffff - val + 1) * -1;
} }
Buffer.prototype.readInt16LE = function(offset, noAssert) { Buffer.prototype.readInt16LE = function(offset, noAssert) {
return readInt16(this, offset, false, noAssert); if (!noAssert)
checkOffset(offset, 2, this.length);
return readInt16(this, offset, false);
}; };
Buffer.prototype.readInt16BE = function(offset, noAssert) { Buffer.prototype.readInt16BE = function(offset, noAssert) {
return readInt16(this, offset, true, noAssert); if (!noAssert)
checkOffset(offset, 2, this.length);
return readInt16(this, offset, true);
}; };
function readInt32(buffer, offset, isBigEndian, noAssert) {
var neg, val;
if (!noAssert) {
assert.ok(typeof (isBigEndian) === 'boolean',
'missing or invalid endian');
assert.ok(offset !== undefined && offset !== null, function readInt32(buffer, offset, isBigEndian) {
'missing offset'); var val = readUInt32(buffer, offset, isBigEndian);
assert.ok(offset + 3 < buffer.length, if (!(val & 0x80000000))
'Trying to read beyond buffer length');
}
val = readUInt32(buffer, offset, isBigEndian, noAssert);
neg = val & 0x80000000;
if (!neg) {
return (val); return (val);
}
return (0xffffffff - val + 1) * -1; return (0xffffffff - val + 1) * -1;
} }
Buffer.prototype.readInt32LE = function(offset, noAssert) { Buffer.prototype.readInt32LE = function(offset, noAssert) {
return readInt32(this, offset, false, noAssert); if (!noAssert)
checkOffset(offset, 2, this.length);
return readInt32(this, offset, false);
}; };
Buffer.prototype.readInt32BE = function(offset, noAssert) { Buffer.prototype.readInt32BE = function(offset, noAssert) {
return readInt32(this, offset, true, noAssert); if (!noAssert)
checkOffset(offset, 2, this.length);
return readInt32(this, offset, true);
}; };
function checkOffset(offset, ext, length) {
if ((offset % 1) !== 0 || offset < 0)
throw new RangeError('offset is not uint');
if (offset + ext > length)
throw new RangeError('Trying to access beyond buffer length');
}
Buffer.prototype.readFloatLE = function(offset, noAssert) { Buffer.prototype.readFloatLE = function(offset, noAssert) {
if (!noAssert) if (!noAssert)
checkOffset(offset, 4, this.length); checkOffset(offset, 4, this.length);
return this.parent.readFloatLE(this.offset + offset, !!noAssert); return this.parent.readFloatLE(this.offset + offset, !!noAssert);
}; };
Buffer.prototype.readFloatBE = function(offset, noAssert) { Buffer.prototype.readFloatBE = function(offset, noAssert) {
if (!noAssert) if (!noAssert)
checkOffset(offset, 4, this.length); checkOffset(offset, 4, this.length);
return this.parent.readFloatBE(this.offset + offset, !!noAssert); return this.parent.readFloatBE(this.offset + offset, !!noAssert);
}; };
Buffer.prototype.readDoubleLE = function(offset, noAssert) { Buffer.prototype.readDoubleLE = function(offset, noAssert) {
if (!noAssert) if (!noAssert)
checkOffset(offset, 8, this.length); checkOffset(offset, 8, this.length);
return this.parent.readDoubleLE(this.offset + offset, !!noAssert); return this.parent.readDoubleLE(this.offset + offset, !!noAssert);
}; };
Buffer.prototype.readDoubleBE = function(offset, noAssert) { Buffer.prototype.readDoubleBE = function(offset, noAssert) {
if (!noAssert) if (!noAssert)
checkOffset(offset, 8, this.length); checkOffset(offset, 8, this.length);
@ -861,63 +825,24 @@ Buffer.prototype.readDoubleBE = function(offset, noAssert) {
}; };
/* function checkInt(buffer, value, offset, ext, max, min) {
* We have to make sure that the value is a valid integer. This means that it is if ((value % 1) !== 0 || value > max || value < min)
* non-negative. It has no fractional component and that it does not exceed the throw TypeError("value is out of bounds");
* maximum allowed value. if ((offset % 1) !== 0 || offset < 0)
* throw TypeError("offset is not uint");
* value The number to check for validity if (offset + ext > buffer.length || buffer.length + offset < 0)
* throw RangeError("Trying to write outside buffer length");
* max The maximum value
*/
function verifuint(value, max) {
assert.ok(typeof (value) == 'number',
'cannot write a non-number as a number');
assert.ok(value >= 0,
'specified a negative value for writing an unsigned value');
assert.ok(value <= max, 'value is larger than maximum value for type');
assert.ok(Math.floor(value) === value, 'value has a fractional component');
} }
Buffer.prototype.writeUInt8 = function(value, offset, noAssert) {
var buffer = this;
if (!noAssert) {
assert.ok(value !== undefined && value !== null,
'missing value');
assert.ok(offset !== undefined && offset !== null,
'missing offset');
assert.ok(offset < buffer.length,
'trying to write beyond buffer length');
verifuint(value, 0xff); Buffer.prototype.writeUInt8 = function(value, offset, noAssert) {
} if (!noAssert)
checkInt(this, value, offset, 1, 0xff, 0);
buffer[offset] = value; this[offset] = value;
}; };
function writeUInt16(buffer, value, offset, isBigEndian, noAssert) {
if (!noAssert) {
assert.ok(value !== undefined && value !== null,
'missing value');
assert.ok(typeof (isBigEndian) === 'boolean',
'missing or invalid endian');
assert.ok(offset !== undefined && offset !== null,
'missing offset');
assert.ok(offset + 1 < buffer.length,
'trying to write beyond buffer length');
verifuint(value, 0xffff);
}
function writeUInt16(buffer, value, offset, isBigEndian) {
if (isBigEndian) { if (isBigEndian) {
buffer[offset] = (value & 0xff00) >>> 8; buffer[offset] = (value & 0xff00) >>> 8;
buffer[offset + 1] = value & 0x00ff; buffer[offset + 1] = value & 0x00ff;
@ -927,31 +852,22 @@ function writeUInt16(buffer, value, offset, isBigEndian, noAssert) {
} }
} }
Buffer.prototype.writeUInt16LE = function(value, offset, noAssert) { Buffer.prototype.writeUInt16LE = function(value, offset, noAssert) {
writeUInt16(this, value, offset, false, noAssert); if (!noAssert)
checkInt(this, value, offset, 2, 0xffff, 0);
writeUInt16(this, value, offset, false);
}; };
Buffer.prototype.writeUInt16BE = function(value, offset, noAssert) { Buffer.prototype.writeUInt16BE = function(value, offset, noAssert) {
writeUInt16(this, value, offset, true, noAssert); if (!noAssert)
checkInt(this, value, offset, 2, 0xffff, 0);
writeUInt16(this, value, offset, true);
}; };
function writeUInt32(buffer, value, offset, isBigEndian, noAssert) {
if (!noAssert) {
assert.ok(value !== undefined && value !== null,
'missing value');
assert.ok(typeof (isBigEndian) === 'boolean',
'missing or invalid endian');
assert.ok(offset !== undefined && offset !== null,
'missing offset');
assert.ok(offset + 3 < buffer.length,
'trying to write beyond buffer length');
verifuint(value, 0xffffffff);
}
function writeUInt32(buffer, value, offset, isBigEndian) {
if (isBigEndian) { if (isBigEndian) {
buffer[offset] = (value >>> 24) & 0xff; buffer[offset] = (value >>> 24) & 0xff;
buffer[offset + 1] = (value >>> 16) & 0xff; buffer[offset + 1] = (value >>> 16) & 0xff;
@ -965,12 +881,18 @@ function writeUInt32(buffer, value, offset, isBigEndian, noAssert) {
} }
} }
Buffer.prototype.writeUInt32LE = function(value, offset, noAssert) { Buffer.prototype.writeUInt32LE = function(value, offset, noAssert) {
writeUInt32(this, value, offset, false, noAssert); if (!noAssert)
checkInt(this, value, offset, 4, 0xffffffff, 0);
writeUInt32(this, value, offset, false);
}; };
Buffer.prototype.writeUInt32BE = function(value, offset, noAssert) { Buffer.prototype.writeUInt32BE = function(value, offset, noAssert) {
writeUInt32(this, value, offset, true, noAssert); if (!noAssert)
checkInt(this, value, offset, 4, 0xffffffff, 0);
writeUInt32(this, value, offset, true);
}; };
@ -1011,92 +933,67 @@ Buffer.prototype.writeUInt32BE = function(value, offset, noAssert) {
* hacky, but it should work and get the job done which is our goal here. * hacky, but it should work and get the job done which is our goal here.
*/ */
/*
* A series of checks to make sure we actually have a signed 32-bit number
*/
function verifsint(value, max, min) {
assert.ok(typeof (value) == 'number',
'cannot write a non-number as a number');
assert.ok(value <= max, 'value larger than maximum allowed value');
assert.ok(value >= min, 'value smaller than minimum allowed value');
assert.ok(Math.floor(value) === value, 'value has a fractional component');
}
Buffer.prototype.writeInt8 = function(value, offset, noAssert) { Buffer.prototype.writeInt8 = function(value, offset, noAssert) {
var buffer = this; if (!noAssert)
checkInt(this, value, offset, 1, 0x7f, -0x80);
if (!noAssert) { if (value < 0) value = 0xff + value + 1;
verifsint(value, 0x7f, -0x80); this[offset] = value;
}
if (value >= 0) {
buffer.writeUInt8(value, offset, noAssert);
} else {
buffer.writeUInt8(0xff + value + 1, offset, noAssert);
}
}; };
function writeInt16(buffer, value, offset, isBigEndian, noAssert) {
if (!noAssert) {
verifsint(value, 0x7fff, -0x8000);
}
if (value >= 0) {
writeUInt16(buffer, value, offset, isBigEndian, noAssert);
} else {
writeUInt16(buffer, 0xffff + value + 1, offset, isBigEndian, noAssert);
}
}
Buffer.prototype.writeInt16LE = function(value, offset, noAssert) { Buffer.prototype.writeInt16LE = function(value, offset, noAssert) {
writeInt16(this, value, offset, false, noAssert); if (!noAssert)
checkInt(this, value, offset, 2, 0x7fff, -0x8000);
if (value < 0) value = 0xffff + value + 1;
writeUInt16(this, value, offset, false);
}; };
Buffer.prototype.writeInt16BE = function(value, offset, noAssert) { Buffer.prototype.writeInt16BE = function(value, offset, noAssert) {
writeInt16(this, value, offset, true, noAssert); if (!noAssert)
checkInt(this, value, offset, 2, 0x7fff, -0x8000);
if (value < 0) value = 0xffff + value + 1;
writeUInt16(this, value, offset, true);
}; };
function writeInt32(buffer, value, offset, isBigEndian, noAssert) {
if (!noAssert) {
verifsint(value, 0x7fffffff, -0x80000000);
}
if (value >= 0) {
writeUInt32(buffer, value, offset, isBigEndian, noAssert);
} else {
writeUInt32(buffer, 0xffffffff + value + 1, offset, isBigEndian, noAssert);
}
}
Buffer.prototype.writeInt32LE = function(value, offset, noAssert) { Buffer.prototype.writeInt32LE = function(value, offset, noAssert) {
writeInt32(this, value, offset, false, noAssert); if (!noAssert)
checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000);
if (value < 0) value = 0xffffffff + value + 1;
writeUInt32(this, value, offset, false);
}; };
Buffer.prototype.writeInt32BE = function(value, offset, noAssert) { Buffer.prototype.writeInt32BE = function(value, offset, noAssert) {
writeInt32(this, value, offset, true, noAssert); if (!noAssert)
checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000);
if (value < 0) value = 0xffffffff + value + 1;
writeUInt32(this, value, offset, true);
}; };
Buffer.prototype.writeFloatLE = function(value, offset, noAssert) { Buffer.prototype.writeFloatLE = function(value, offset, noAssert) {
if (!noAssert) if (!noAssert)
checkOffset(offset, 4, this.length); checkOffset(offset, 4, this.length);
this.parent.writeFloatLE(value, this.offset + offset, !!noAssert); this.parent.writeFloatLE(value, this.offset + offset, !!noAssert);
}; };
Buffer.prototype.writeFloatBE = function(value, offset, noAssert) { Buffer.prototype.writeFloatBE = function(value, offset, noAssert) {
if (!noAssert) if (!noAssert)
checkOffset(offset, 4, this.length); checkOffset(offset, 4, this.length);
this.parent.writeFloatBE(value, this.offset + offset, !!noAssert); this.parent.writeFloatBE(value, this.offset + offset, !!noAssert);
}; };
Buffer.prototype.writeDoubleLE = function(value, offset, noAssert) { Buffer.prototype.writeDoubleLE = function(value, offset, noAssert) {
if (!noAssert) if (!noAssert)
checkOffset(offset, 8, this.length); checkOffset(offset, 8, this.length);
this.parent.writeDoubleLE(value, this.offset + offset, !!noAssert); this.parent.writeDoubleLE(value, this.offset + offset, !!noAssert);
}; };
Buffer.prototype.writeDoubleBE = function(value, offset, noAssert) { Buffer.prototype.writeDoubleBE = function(value, offset, noAssert) {
if (!noAssert) if (!noAssert)
checkOffset(offset, 8, this.length); checkOffset(offset, 8, this.length);

Loading…
Cancel
Save