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');
};
Buffer.prototype.readUInt8 = function(offset, noAssert) {
var buffer = this;
if (!noAssert) {
assert.ok(offset !== undefined && offset !== null,
'missing offset');
/*
* Need to make sure that buffer isn't trying to write out of bounds.
* 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) {
val = buffer[offset] << 8;
val |= buffer[offset + 1];
@ -656,28 +649,24 @@ function readUInt16(buffer, offset, isBigEndian, noAssert) {
return val;
}
Buffer.prototype.readUInt16LE = function(offset, noAssert) {
if (!noAssert)
checkOffset(offset, 2, this.length);
return readUInt16(this, offset, false, noAssert);
};
Buffer.prototype.readUInt16BE = function(offset, noAssert) {
if (!noAssert)
checkOffset(offset, 2, this.length);
return readUInt16(this, offset, true, noAssert);
};
function readUInt32(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 + 3 < buffer.length,
'Trying to read beyond buffer length');
}
if (isBigEndian) {
val = buffer[offset + 1] << 16;
val |= buffer[offset + 2] << 8;
@ -693,11 +682,17 @@ function readUInt32(buffer, offset, isBigEndian, noAssert) {
return val;
}
Buffer.prototype.readUInt32LE = function(offset, noAssert) {
if (!noAssert)
checkOffset(offset, 4, this.length);
return readUInt32(this, offset, false, noAssert);
};
Buffer.prototype.readUInt32BE = function(offset, noAssert) {
if (!noAssert)
checkOffset(offset, 4, this.length);
return readUInt32(this, offset, true, noAssert);
};
@ -747,113 +742,82 @@ Buffer.prototype.readUInt32BE = function(offset, noAssert) {
* (0x007f + 1) * -1
* (0x0080) * -1
*/
Buffer.prototype.readInt8 = function(offset, noAssert) {
var buffer = this;
var neg;
if (!noAssert) {
assert.ok(offset !== undefined && offset !== null,
'missing offset');
assert.ok(offset < buffer.length,
'Trying to read beyond buffer length');
}
neg = buffer[offset] & 0x80;
if (!neg) {
return (buffer[offset]);
}
return ((0xff - buffer[offset] + 1) * -1);
Buffer.prototype.readInt8 = function(offset, noAssert) {
if (!noAssert)
checkOffset(offset, 1, this.length);
if (!(this[offset] & 0x80))
return (this[offset]);
return ((0xff - this[offset] + 1) * -1);
};
function readInt16(buffer, offset, isBigEndian, noAssert) {
var neg, val;
if (!noAssert) {
assert.ok(typeof (isBigEndian) === 'boolean',
'missing or invalid endian');
function readInt16(buffer, offset, isBigEndian) {
var val = readUInt16(buffer, offset, isBigEndian);
assert.ok(offset !== undefined && offset !== null,
'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) {
if (!(val & 0x8000))
return val;
}
return (0xffff - val + 1) * -1;
}
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) {
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,
'missing offset');
function readInt32(buffer, offset, isBigEndian) {
var val = readUInt32(buffer, offset, isBigEndian);
assert.ok(offset + 3 < buffer.length,
'Trying to read beyond buffer length');
}
val = readUInt32(buffer, offset, isBigEndian, noAssert);
neg = val & 0x80000000;
if (!neg) {
if (!(val & 0x80000000))
return (val);
}
return (0xffffffff - val + 1) * -1;
}
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) {
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) {
if (!noAssert)
checkOffset(offset, 4, this.length);
return this.parent.readFloatLE(this.offset + offset, !!noAssert);
};
Buffer.prototype.readFloatBE = function(offset, noAssert) {
if (!noAssert)
checkOffset(offset, 4, this.length);
return this.parent.readFloatBE(this.offset + offset, !!noAssert);
};
Buffer.prototype.readDoubleLE = function(offset, noAssert) {
if (!noAssert)
checkOffset(offset, 8, this.length);
return this.parent.readDoubleLE(this.offset + offset, !!noAssert);
};
Buffer.prototype.readDoubleBE = function(offset, noAssert) {
if (!noAssert)
checkOffset(offset, 8, this.length);
@ -861,63 +825,24 @@ Buffer.prototype.readDoubleBE = function(offset, noAssert) {
};
/*
* We have to make sure that the value is a valid integer. This means that it is
* non-negative. It has no fractional component and that it does not exceed the
* maximum allowed value.
*
* value The number to check for validity
*
* 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');
function checkInt(buffer, value, offset, ext, max, min) {
if ((value % 1) !== 0 || value > max || value < min)
throw TypeError("value is out of bounds");
if ((offset % 1) !== 0 || offset < 0)
throw TypeError("offset is not uint");
if (offset + ext > buffer.length || buffer.length + offset < 0)
throw RangeError("Trying to write outside buffer length");
}
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[offset] = value;
Buffer.prototype.writeUInt8 = function(value, offset, noAssert) {
if (!noAssert)
checkInt(this, value, offset, 1, 0xff, 0);
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) {
buffer[offset] = (value & 0xff00) >>> 8;
buffer[offset + 1] = value & 0x00ff;
@ -927,31 +852,22 @@ function writeUInt16(buffer, value, offset, isBigEndian, 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) {
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) {
buffer[offset] = (value >>> 24) & 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) {
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) {
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.
*/
/*
* 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) {
var buffer = this;
if (!noAssert) {
verifsint(value, 0x7f, -0x80);
}
if (value >= 0) {
buffer.writeUInt8(value, offset, noAssert);
} else {
buffer.writeUInt8(0xff + value + 1, offset, noAssert);
}
if (!noAssert)
checkInt(this, value, offset, 1, 0x7f, -0x80);
if (value < 0) value = 0xff + value + 1;
this[offset] = value;
};
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) {
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) {
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) {
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) {
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) {
if (!noAssert)
checkOffset(offset, 4, this.length);
this.parent.writeFloatLE(value, this.offset + offset, !!noAssert);
};
Buffer.prototype.writeFloatBE = function(value, offset, noAssert) {
if (!noAssert)
checkOffset(offset, 4, this.length);
this.parent.writeFloatBE(value, this.offset + offset, !!noAssert);
};
Buffer.prototype.writeDoubleLE = function(value, offset, noAssert) {
if (!noAssert)
checkOffset(offset, 8, this.length);
this.parent.writeDoubleLE(value, this.offset + offset, !!noAssert);
};
Buffer.prototype.writeDoubleBE = function(value, offset, noAssert) {
if (!noAssert)
checkOffset(offset, 8, this.length);

Loading…
Cancel
Save