Returns true if the `encoding` is a valid encoding argument, or false
otherwise.
+### Class Method: Buffer.isBuffer(obj)
+
+* `obj` Object
+* Return: Boolean
+
+Tests if `obj` is a `Buffer`.
+
+### Class Method: Buffer.byteLength(string, [encoding])
+
+* `string` String
+* `encoding` String, Optional, Default: 'utf8'
+* Return: Number
+
+Gives the actual byte length of a string. `encoding` defaults to `'utf8'`.
+This is not the same as `String.prototype.length` since that returns the
+number of *characters* in a string.
+
+Example:
+
+ str = '\u00bd + \u00bc = \u00be';
+
+ console.log(str + ": " + str.length + " characters, " +
+ Buffer.byteLength(str, 'utf8') + " bytes");
+
+ // ½ + ¼ = ¾: 9 characters, 12 bytes
+
+### Class Method: Buffer.concat(list, [totalLength])
+
+* `list` {Array} List of Buffer objects to concat
+* `totalLength` {Number} Total length of the buffers when concatenated
+
+Returns a buffer which is the result of concatenating all the buffers in
+the list together.
+
+If the list has no items, or if the totalLength is 0, then it returns a
+zero-length buffer.
+
+If the list has exactly one item, then the first item of the list is
+returned.
+
+If the list has more than one item, then a new Buffer is created.
+
+If totalLength is not provided, it is read from the buffers in the list.
+However, this adds an additional loop to the function, so it is faster
+to provide the length explicitly.
+
+### buf.length
+
+* Number
+
+The size of the buffer in bytes. Note that this is not necessarily the size
+of the contents. `length` refers to the amount of memory allocated for the
+buffer object. It does not change when the contents of the buffer are changed.
+
+ buf = new Buffer(1234);
+
+ console.log(buf.length);
+ buf.write("some string", 0, "ascii");
+ console.log(buf.length);
+
+ // 1234
+ // 1234
+
### buf.write(string, [offset], [length], [encoding])
* `string` String - data to be written to buffer
// node.js
-### Class Method: Buffer.isBuffer(obj)
-
-* `obj` Object
-* Return: Boolean
-
-Tests if `obj` is a `Buffer`.
-
-### Class Method: Buffer.byteLength(string, [encoding])
-
-* `string` String
-* `encoding` String, Optional, Default: 'utf8'
-* Return: Number
-
-Gives the actual byte length of a string. `encoding` defaults to `'utf8'`.
-This is not the same as `String.prototype.length` since that returns the
-number of *characters* in a string.
-
-Example:
-
- str = '\u00bd + \u00bc = \u00be';
-
- console.log(str + ": " + str.length + " characters, " +
- Buffer.byteLength(str, 'utf8') + " bytes");
-
- // ½ + ¼ = ¾: 9 characters, 12 bytes
-
-### Class Method: Buffer.concat(list, [totalLength])
-
-* `list` {Array} List of Buffer objects to concat
-* `totalLength` {Number} Total length of the buffers when concatenated
-
-Returns a buffer which is the result of concatenating all the buffers in
-the list together.
-
-If the list has no items, or if the totalLength is 0, then it returns a
-zero-length buffer.
-
-If the list has exactly one item, then the first item of the list is
-returned.
-
-If the list has more than one item, then a new Buffer is created.
-
-If totalLength is not provided, it is read from the buffers in the list.
-However, this adds an additional loop to the function, so it is faster
-to provide the length explicitly.
-
-### buf.length
-
-* Number
-
-The size of the buffer in bytes. Note that this is not necessarily the size
-of the contents. `length` refers to the amount of memory allocated for the
-buffer object. It does not change when the contents of the buffer are changed.
-
- buf = new Buffer(1234);
-
- console.log(buf.length);
- buf.write("some string", 0, "ascii");
- console.log(buf.length);
-
- // 1234
- // 1234
-
### buf.copy(targetBuffer, [targetStart], [sourceStart], [sourceEnd])
* `targetBuffer` Buffer object - Buffer to copy into
## Class: SlowBuffer
-This class is primarily for internal use. JavaScript programs should
-use Buffer instead of using SlowBuffer.
+Deprecated. SlowBuffer now returns an instance of Buffer.
In order to avoid the overhead of allocating many C++ Buffer objects for
small blocks of memory in the lifetime of a server, Node allocates memory
-in 8Kb (8192 byte) chunks. If a buffer is smaller than this size, then it
-will be backed by a parent SlowBuffer object. If it is larger than this,
-then Node will allocate a SlowBuffer slab for it directly.
+in 8Kb (8192 byte) chunks. This is now handled by Smalloc.
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
-var SlowBuffer = process.binding('buffer').SlowBuffer;
+var smalloc = process.binding('smalloc');
+var buffer = process.binding('buffer');
var assert = require('assert');
+var alloc = smalloc.alloc;
+var sliceOnto = smalloc.sliceOnto;
+var kMaxLength = smalloc.kMaxLength;
+exports.Buffer = Buffer;
+// backwards compatibility (DEPRECATE)
+exports.SlowBuffer = Buffer;
exports.INSPECT_MAX_BYTES = 50;
-// Make SlowBuffer inherit from Buffer.
-// This is an exception to the rule that __proto__ is not allowed in core.
-SlowBuffer.prototype.__proto__ = Buffer.prototype;
+// add methods to Buffer prototype
+buffer.setupBufferJS(Buffer);
+function Buffer(subject, encoding) {
+ if (!(this instanceof Buffer))
+ return new Buffer(subject, encoding);
-function clamp(index, len, defaultValue) {
- if (typeof index !== 'number') return defaultValue;
- index = ~~index; // Coerce to integer.
- if (index >= len) return len;
- if (index >= 0) return index;
- index += len;
- if (index >= 0) return index;
- return 0;
-}
+ var type = typeof subject;
+ switch (type) {
+ case 'number':
+ this.length = subject > 0 ? Math.floor(subject) : 0;
+ break;
-function toHex(n) {
- if (n < 16) return '0' + n.toString(16);
- return n.toString(16);
-}
+ case 'string':
+ this.length = Buffer.byteLength(subject, encoding = encoding || 'utf8');
+ break;
+ case 'object':
+ this.length = +subject.length > 0 ? Math.floor(+subject.length) : 0;
+ break;
-SlowBuffer.prototype.toString = function(encoding, start, end) {
- encoding = String(encoding || 'utf8').toLowerCase();
- start = +start || 0;
- if (typeof end !== 'number') end = this.length;
+ // undef first arg returns unallocated buffer, also assumes length passed.
+ // this is a stop-gap for now while look for better architecture.
+ // for internal use only.
+ case 'undefined':
+ this.length = encoding;
+ return;
- // Fastpath empty strings
- if (+end == start) {
- return '';
+ default:
+ throw new TypeError('must start with number, buffer, array or string');
}
- switch (encoding) {
- case 'hex':
- return this.hexSlice(start, end);
-
- case 'utf8':
- case 'utf-8':
- return this.utf8Slice(start, end);
+ if (this.length > kMaxLength)
+ throw new RangeError('length > kMaxLength');
- case 'ascii':
- return this.asciiSlice(start, end);
+ alloc(this, this.length);
- case 'binary':
- return this.binarySlice(start, end);
+ if (type !== 'number') {
+ if (type === 'string') {
+ // FIXME: the number of bytes hasn't changed, so why change the length?
+ this.length = this.write(subject, 0, encoding);
+ } else {
+ if (subject instanceof Buffer)
+ this.copy(subject, 0, 0, this.length);
+ else if (typeof subject.length === 'number' || Array.isArray(subject))
+ for (var i = 0; i < this.length; i++)
+ this[i] = subject[i];
+ }
+ }
+}
- case 'base64':
- return this.base64Slice(start, end);
- case 'ucs2':
- case 'ucs-2':
- case 'utf16le':
- case 'utf-16le':
- return this.ucs2Slice(start, end);
+// Static methods
- default:
- throw new TypeError('Unknown encoding: ' + encoding);
- }
+Buffer.isBuffer = function isBuffer(b) {
+ return b instanceof Buffer;
};
-SlowBuffer.prototype.write = function(string, offset, length, encoding) {
- // Support both (string, offset, length, encoding)
- // and the legacy (string, encoding, offset, length)
- if (isFinite(offset)) {
- if (!isFinite(length)) {
- encoding = length;
- length = undefined;
- }
- } else { // legacy
- var swap = encoding;
- encoding = offset;
- offset = length;
- length = swap;
- }
-
- offset = +offset || 0;
- var remaining = this.length - offset;
- if (!length) {
- length = remaining;
- } else {
- length = +length;
- if (length > remaining) {
- length = remaining;
- }
- }
- encoding = String(encoding || 'utf8').toLowerCase();
-
- switch (encoding) {
+Buffer.isEncoding = function(encoding) {
+ switch ((encoding + '').toLowerCase()) {
case 'hex':
- return this.hexWrite(string, offset, length);
-
case 'utf8':
case 'utf-8':
- return this.utf8Write(string, offset, length);
-
case 'ascii':
- return this.asciiWrite(string, offset, length);
-
case 'binary':
- return this.binaryWrite(string, offset, length);
-
case 'base64':
- return this.base64Write(string, offset, length);
-
case 'ucs2':
case 'ucs-2':
case 'utf16le':
case 'utf-16le':
- return this.ucs2Write(string, offset, length);
+ case 'raw':
+ return true;
default:
- throw new TypeError('Unknown encoding: ' + encoding);
+ return false;
}
};
-// slice(start, end)
-SlowBuffer.prototype.slice = function(start, end) {
- var len = this.length;
- start = clamp(start, len, 0);
- end = clamp(end, len, len);
- return new Buffer(this, end - start, start);
-};
-
-
-var zeroBuffer = new SlowBuffer(0);
-
-// Buffer
-function Buffer(subject, encoding, offset) {
- if (!(this instanceof Buffer)) {
- return new Buffer(subject, encoding, offset);
- }
-
- var type;
-
- // Are we slicing?
- if (typeof offset === 'number') {
- if (!Buffer.isBuffer(subject)) {
- throw new TypeError('First argument must be a Buffer when slicing');
- }
+Buffer.concat = function(list, length) {
+ if (!Array.isArray(list))
+ throw new TypeError('Usage: Buffer.concat(list[, length])');
- this.length = +encoding > 0 ? Math.ceil(encoding) : 0;
- this.parent = subject.parent ? subject.parent : subject;
- this.offset = offset;
+ if (typeof length === 'undefined') {
+ length = 0;
+ for (var i = 0; i < list.length; i++)
+ length += list[i].length;
} else {
- // Find the length
- switch (type = typeof subject) {
- case 'number':
- this.length = +subject > 0 ? Math.ceil(subject) : 0;
- break;
-
- case 'string':
- this.length = Buffer.byteLength(subject, encoding);
- break;
-
- case 'object': // Assume object is array-ish
- this.length = +subject.length > 0 ? Math.ceil(subject.length) : 0;
- break;
-
- default:
- throw new TypeError('First argument needs to be a number, ' +
- 'array or string.');
- }
+ length = ~~length;
+ }
- if (this.length > Buffer.poolSize) {
- // Big buffer, just alloc one.
- this.parent = new SlowBuffer(this.length);
- this.offset = 0;
+ if (length < 0) length = 0;
- } else if (this.length > 0) {
- // Small buffer.
- if (!pool || pool.length - pool.used < this.length) allocPool();
- this.parent = pool;
- this.offset = pool.used;
- pool.used += this.length;
- if (pool.used & 7) pool.used = (pool.used + 8) & ~7;
+ if (list.length === 0)
+ return new Buffer(0);
+ else if (list.length === 1)
+ return list[0];
- } else {
- // Zero-length buffer
- this.parent = zeroBuffer;
- this.offset = 0;
- }
+ if (length < 0)
+ throw new RangeError('length is not a positive number');
- // optimize by branching logic for new allocations
- if (typeof subject !== 'number') {
- if (type === 'string') {
- // We are a string
- this.length = this.write(subject, 0, encoding);
- // if subject is buffer then use built-in copy method
- } else if (Buffer.isBuffer(subject)) {
- if (subject.parent)
- subject.parent.copy(this.parent,
- this.offset,
- subject.offset,
- this.length + subject.offset);
- else
- subject.copy(this.parent, this.offset, 0, this.length);
- } else if (isArrayIsh(subject)) {
- for (var i = 0; i < this.length; i++)
- this.parent[i + this.offset] = subject[i];
- }
- }
+ var buffer = new Buffer(length);
+ var pos = 0;
+ for (var i = 0; i < list.length; i++) {
+ var buf = list[i];
+ buf.copy(buffer, pos);
+ pos += buf.length;
}
- SlowBuffer.makeFastBuffer(this.parent, this, this.offset, this.length);
-}
+ return buffer;
+};
-function isArrayIsh(subject) {
- return Array.isArray(subject) ||
- subject && typeof subject === 'object' &&
- typeof subject.length === 'number';
-}
-exports.SlowBuffer = SlowBuffer;
-exports.Buffer = Buffer;
+// toString(encoding, start=0, end=buffer.length)
+Buffer.prototype.toString = function(encoding, start, end) {
+ encoding = !!encoding ? (encoding + '').toLowerCase() : 'utf8';
+ start = ~~start;
+ end = typeof end === 'undefined' ? this.length : ~~end;
-Buffer.isEncoding = function(encoding) {
- switch (encoding && encoding.toLowerCase()) {
+ if (start < 0) start = 0;
+ if (end > this.length) end = this.length;
+ if (end <= start) return '';
+
+ switch (encoding) {
case 'hex':
+ return this.hexSlice(start, end);
+
case 'utf8':
case 'utf-8':
+ return this.utf8Slice(start, end);
+
case 'ascii':
+ return this.asciiSlice(start, end);
+
case 'binary':
+ return this.binarySlice(start, end);
+
case 'base64':
+ return this.base64Slice(start, end);
+
case 'ucs2':
case 'ucs-2':
case 'utf16le':
case 'utf-16le':
- case 'raw':
- return true;
+ return this.ucs2Slice(start, end);
default:
- return false;
+ throw new TypeError('Unknown encoding: ' + encoding);
}
};
-
-Buffer.poolSize = 8 * 1024;
-var pool;
-
-function allocPool() {
- pool = new SlowBuffer(Buffer.poolSize);
- pool.used = 0;
-}
-
-
-// Static methods
-Buffer.isBuffer = function isBuffer(b) {
- return b instanceof Buffer;
-};
-
-
// Inspect
Buffer.prototype.inspect = function inspect() {
- var out = [],
- len = this.length,
- name = this.constructor.name;
-
- for (var i = 0; i < len; i++) {
- out[i] = toHex(this[i]);
- if (i == exports.INSPECT_MAX_BYTES) {
- out[i + 1] = '...';
- break;
- }
- }
-
- return '<' + name + ' ' + out.join(' ') + '>';
+ var str = '';
+ if (this.length > 0)
+ str = this.hexSlice(0, this.length).match(/.{2}/g).join(' ');
+ return '<' + this.constructor.name + ' ' + str + '>';
};
+// TODO(trevnorris): DEPRECATE
Buffer.prototype.get = function get(offset) {
+ offset = ~~offset;
if (offset < 0 || offset >= this.length)
- throw new RangeError('offset is out of bounds');
- return this.parent[this.offset + offset];
+ throw new RangeError('index out of range');
+ return this[offset];
};
+// TODO(trevnorris): DEPRECATE
Buffer.prototype.set = function set(offset, v) {
+ offset = ~~offset;
if (offset < 0 || offset >= this.length)
- throw new RangeError('offset is out of bounds');
- return this.parent[this.offset + offset] = v;
+ throw new RangeError('index out of range');
+ return this[offset] = v;
};
-// write(string, offset = 0, length = buffer.length-offset, encoding = 'utf8')
+// TODO(trevnorris): fix these checks to follow new standard
+// write(string, offset = 0, length = buffer.length, encoding = 'utf8')
Buffer.prototype.write = function(string, offset, length, encoding) {
// Support both (string, offset, length, encoding)
// and the legacy (string, encoding, offset, length)
encoding = length;
length = undefined;
}
+ // TODO(trevnorris): DEPRECATE
} else { // legacy
var swap = encoding;
encoding = offset;
length = remaining;
}
}
- encoding = String(encoding || 'utf8').toLowerCase();
+
+ if (typeof encoding === 'undefined')
+ encoding = 'utf8';
+ else
+ encoding = (encoding + '').toLowerCase();
if (string.length > 0 && (length < 0 || offset < 0))
throw new RangeError('attempt to write beyond buffer bounds');
var ret;
switch (encoding) {
case 'hex':
- ret = this.parent.hexWrite(string, this.offset + offset, length);
+ ret = this.hexWrite(string, offset, length);
break;
case 'utf8':
case 'utf-8':
- ret = this.parent.utf8Write(string, this.offset + offset, length);
+ ret = this.utf8Write(string, offset, length);
break;
case 'ascii':
- ret = this.parent.asciiWrite(string, this.offset + offset, length);
+ ret = this.asciiWrite(string, offset, length);
break;
case 'binary':
- ret = this.parent.binaryWrite(string, this.offset + offset, length);
+ ret = this.binaryWrite(string, offset, length);
break;
case 'base64':
// Warning: maxLength not taken into account in base64Write
- ret = this.parent.base64Write(string, this.offset + offset, length);
+ ret = this.base64Write(string, offset, length);
break;
case 'ucs2':
case 'ucs-2':
case 'utf16le':
case 'utf-16le':
- ret = this.parent.ucs2Write(string, this.offset + offset, length);
+ ret = this.ucs2Write(string, offset, length);
break;
default:
};
-// toString(encoding, start=0, end=buffer.length)
-Buffer.prototype.toString = function(encoding, start, end) {
- encoding = String(encoding || 'utf8').toLowerCase();
-
- if (typeof start !== 'number' || start < 0) {
- start = 0;
- } else if (start > this.length) {
- start = this.length;
- }
-
- if (typeof end !== 'number' || end > this.length) {
- end = this.length;
- } else if (end < 0) {
- end = 0;
- }
-
- start = start + this.offset;
- end = end + this.offset;
-
- switch (encoding) {
- case 'hex':
- return this.parent.hexSlice(start, end);
-
- case 'utf8':
- case 'utf-8':
- return this.parent.utf8Slice(start, end);
-
- case 'ascii':
- return this.parent.asciiSlice(start, end);
-
- case 'binary':
- return this.parent.binarySlice(start, end);
-
- case 'base64':
- return this.parent.base64Slice(start, end);
-
- case 'ucs2':
- case 'ucs-2':
- case 'utf16le':
- case 'utf-16le':
- return this.parent.ucs2Slice(start, end);
-
- default:
- throw new TypeError('Unknown encoding: ' + encoding);
- }
-};
-
-
-// byteLength
-Buffer.byteLength = SlowBuffer.byteLength;
-
-
-// fill(value, start=0, end=buffer.length)
-Buffer.prototype.fill = function fill(value, start, end) {
- value || (value = 0);
- start || (start = 0);
- end || (end = this.length);
-
- if (typeof value === 'string') {
- value = value.charCodeAt(0);
- }
- if (typeof value !== 'number' || isNaN(value)) {
- throw new TypeError('value is not a number');
- }
-
- if (end < start) throw new RangeError('end < start');
-
- // Fill 0 bytes; we're done
- if (end === start) return 0;
- if (this.length == 0) return 0;
-
- if (start < 0 || start >= this.length) {
- throw new RangeError('start out of bounds');
- }
-
- if (end < 0 || end > this.length) {
- throw new RangeError('end out of bounds');
- }
-
- this.parent.fill(value,
- start + this.offset,
- end + this.offset);
- return this;
-};
-
-
-Buffer.concat = function(list, length) {
- if (!Array.isArray(list)) {
- throw new TypeError('Usage: Buffer.concat(list, [length])');
- }
-
- if (list.length === 0) {
- return new Buffer(0);
- } else if (list.length === 1) {
- return list[0];
+// TODO(trevnorris): currently works like Array.prototype.slice(), which
+// doesn't follow the new standard for throwing on out of range indexes.
+Buffer.prototype.slice = function(start, end) {
+ var len = this.length;
+ start = ~~start;
+ end = typeof end === 'undefined' ? len : ~~end;
+
+ if (start < 0) {
+ start += len;
+ if (start < 0)
+ start = 0;
+ } else if (start > len) {
+ start = len;
}
- if (typeof length !== 'number') {
- length = 0;
- for (var i = 0; i < list.length; i++) {
- var buf = list[i];
- length += buf.length;
- }
+ if (end < 0) {
+ end += len;
+ if (end < 0)
+ end = 0;
+ } else if (end > len) {
+ end = len;
}
- var buffer = new Buffer(length);
- var pos = 0;
- for (var i = 0; i < list.length; i++) {
- var buf = list[i];
- buf.copy(buffer, pos);
- pos += buf.length;
- }
- return buffer;
-};
-
-
-
-
-// copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length)
-Buffer.prototype.copy = function(target, target_start, start, end) {
- // set undefined/NaN or out of bounds values equal to their default
- if (!(target_start >= 0)) target_start = 0;
- if (!(start >= 0)) start = 0;
- if (!(end < this.length)) end = this.length;
-
- // Copy 0 bytes; we're done
- if (end === start ||
- target.length === 0 ||
- this.length === 0 ||
- start > this.length)
- return 0;
-
if (end < start)
- throw new RangeError('sourceEnd < sourceStart');
-
- if (target_start >= target.length)
- throw new RangeError('targetStart out of bounds');
-
- if (target.length - target_start < end - start)
- end = target.length - target_start + start;
-
- return this.parent.copy(target.parent || target,
- target_start + (target.offset || 0),
- start + this.offset,
- end + this.offset);
-};
-
-
-// slice(start, end)
-Buffer.prototype.slice = function(start, end) {
- var len = this.length;
- start = clamp(start, len, 0);
- end = clamp(end, len, len);
- return new Buffer(this.parent, end - start, start + this.offset);
-};
-
-
-// Legacy methods for backwards compatibility.
-
-Buffer.prototype.utf8Slice = function(start, end) {
- return this.toString('utf8', start, end);
-};
+ end = start;
-Buffer.prototype.binarySlice = function(start, end) {
- return this.toString('binary', start, end);
-};
+ var buf = new Buffer();
+ buf.parent = sliceOnto(this, buf, start, end);
+ buf.length = end - start;
-Buffer.prototype.asciiSlice = function(start, end) {
- return this.toString('ascii', start, end);
+ return buf;
};
-Buffer.prototype.utf8Write = function(string, offset) {
- return this.write(string, offset, 'utf8');
-};
-
-Buffer.prototype.binaryWrite = function(string, offset) {
- return this.write(string, offset, 'binary');
-};
-Buffer.prototype.asciiWrite = function(string, offset) {
- return this.write(string, offset, 'ascii');
-};
-
-
-/*
- * 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');
+ if (offset < 0 || offset + ext > length)
+ throw new RangeError('index out of range');
}
Buffer.prototype.readUInt8 = function(offset, noAssert) {
+ offset = ~~offset;
if (!noAssert)
checkOffset(offset, 1, this.length);
return this[offset];
val = buffer[offset];
val |= buffer[offset + 1] << 8;
}
-
return val;
}
Buffer.prototype.readUInt16LE = function(offset, noAssert) {
+ offset = ~~offset;
if (!noAssert)
checkOffset(offset, 2, this.length);
return readUInt16(this, offset, false, noAssert);
Buffer.prototype.readUInt16BE = function(offset, noAssert) {
+ offset = ~~offset;
if (!noAssert)
checkOffset(offset, 2, this.length);
return readUInt16(this, offset, true, noAssert);
function readUInt32(buffer, offset, isBigEndian, noAssert) {
var val = 0;
-
if (isBigEndian) {
val = buffer[offset + 1] << 16;
val |= buffer[offset + 2] << 8;
val |= buffer[offset];
val = val + (buffer[offset + 3] << 24 >>> 0);
}
-
return val;
}
Buffer.prototype.readUInt32LE = function(offset, noAssert) {
+ offset = ~~offset;
if (!noAssert)
checkOffset(offset, 4, this.length);
return readUInt32(this, offset, false, noAssert);
Buffer.prototype.readUInt32BE = function(offset, noAssert) {
+ offset = ~~offset;
if (!noAssert)
checkOffset(offset, 4, this.length);
return readUInt32(this, offset, true, noAssert);
*/
Buffer.prototype.readInt8 = function(offset, noAssert) {
+ offset = ~~offset;
if (!noAssert)
checkOffset(offset, 1, this.length);
if (!(this[offset] & 0x80))
function readInt16(buffer, offset, isBigEndian) {
var val = readUInt16(buffer, offset, isBigEndian);
-
if (!(val & 0x8000))
return val;
return (0xffff - val + 1) * -1;
Buffer.prototype.readInt16LE = function(offset, noAssert) {
+ offset = ~~offset;
if (!noAssert)
checkOffset(offset, 2, this.length);
return readInt16(this, offset, false);
Buffer.prototype.readInt16BE = function(offset, noAssert) {
+ offset = ~~offset;
if (!noAssert)
checkOffset(offset, 2, this.length);
return readInt16(this, offset, true);
function readInt32(buffer, offset, isBigEndian) {
var val = readUInt32(buffer, offset, isBigEndian);
-
if (!(val & 0x80000000))
return (val);
return (0xffffffff - val + 1) * -1;
Buffer.prototype.readInt32LE = function(offset, noAssert) {
+ offset = ~~offset;
if (!noAssert)
checkOffset(offset, 4, this.length);
return readInt32(this, offset, false);
Buffer.prototype.readInt32BE = function(offset, noAssert) {
+ offset = ~~offset;
if (!noAssert)
checkOffset(offset, 4, this.length);
return readInt32(this, offset, true);
};
-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);
- return this.parent.readDoubleBE(this.offset + offset, !!noAssert);
-};
-
function checkInt(buffer, value, offset, ext, max, min) {
- if ((value % 1) !== 0 || value > max || value < min)
+ if (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');
+ if (offset < 0 || offset + ext > buffer.length || buffer.length + offset < 0)
+ throw RangeError('index out of range');
}
Buffer.prototype.writeUInt8 = function(value, offset, noAssert) {
+ value = +value;
+ offset = ~~offset;
if (!noAssert)
checkInt(this, value, offset, 1, 0xff, 0);
this[offset] = value;
Buffer.prototype.writeUInt16LE = function(value, offset, noAssert) {
+ value = +value;
+ offset = ~~offset;
if (!noAssert)
checkInt(this, value, offset, 2, 0xffff, 0);
writeUInt16(this, value, offset, false);
Buffer.prototype.writeUInt16BE = function(value, offset, noAssert) {
+ value = +value;
+ offset = ~~offset;
if (!noAssert)
checkInt(this, value, offset, 2, 0xffff, 0);
writeUInt16(this, value, offset, true);
Buffer.prototype.writeUInt32LE = function(value, offset, noAssert) {
+ value = +value;
+ offset = ~~offset;
if (!noAssert)
checkInt(this, value, offset, 4, 0xffffffff, 0);
writeUInt32(this, value, offset, false);
Buffer.prototype.writeUInt32BE = function(value, offset, noAssert) {
+ value = +value;
+ offset = ~~offset;
if (!noAssert)
checkInt(this, value, offset, 4, 0xffffffff, 0);
writeUInt32(this, value, offset, true);
*/
Buffer.prototype.writeInt8 = function(value, offset, noAssert) {
+ value = +value;
+ offset = ~~offset;
if (!noAssert)
checkInt(this, value, offset, 1, 0x7f, -0x80);
if (value < 0) value = 0xff + value + 1;
Buffer.prototype.writeInt16LE = function(value, offset, noAssert) {
+ value = +value;
+ offset = ~~offset;
if (!noAssert)
checkInt(this, value, offset, 2, 0x7fff, -0x8000);
if (value < 0) value = 0xffff + value + 1;
Buffer.prototype.writeInt16BE = function(value, offset, noAssert) {
+ value = +value;
+ offset = ~~offset;
if (!noAssert)
checkInt(this, value, offset, 2, 0x7fff, -0x8000);
if (value < 0) value = 0xffff + value + 1;
Buffer.prototype.writeInt32LE = function(value, offset, noAssert) {
+ value = +value;
+ offset = ~~offset;
if (!noAssert)
checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000);
if (value < 0) value = 0xffffffff + value + 1;
Buffer.prototype.writeInt32BE = function(value, offset, noAssert) {
+ value = +value;
+ offset = ~~offset;
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);
- this.parent.writeDoubleBE(value, this.offset + offset, !!noAssert);
-};
global.GLOBAL = global;
global.root = global;
global.Buffer = NativeModule.require('buffer').Buffer;
- process.binding('buffer').setFastBufferConstructor(global.Buffer);
process.domain = null;
process._exiting = false;
};
// USE OR OTHER DEALINGS IN THE SOFTWARE.
-#include "node_buffer.h"
-
#include "node.h"
+#include "node_internals.h"
+#include "node_buffer.h"
+#include "smalloc.h"
#include "string_bytes.h"
#include "v8.h"
#include "v8-profiler.h"
#include <assert.h>
-#include <string.h> // memcpy
+#include <string.h>
#include <limits.h>
-#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
-#define BUFFER_CLASS_ID (0xBABE)
+#define CHECK_NOT_OOB(r) \
+ do { if (!(r)) return ThrowRangeError("out of range index"); } while (0)
-namespace node {
+#define ARGS_THIS(argT) \
+ Local<Object> obj = argT; \
+ size_t obj_length = obj->GetIndexedPropertiesExternalArrayDataLength(); \
+ char* obj_data = static_cast<char*>( \
+ obj->GetIndexedPropertiesExternalArrayData());
-using namespace v8;
-
-#define SLICE_ARGS(start_arg, end_arg) \
- if (!start_arg->IsInt32() || !end_arg->IsInt32()) { \
- return ThrowException(Exception::TypeError( \
- String::New("Bad argument."))); \
- } \
- int32_t start = start_arg->Int32Value(); \
- int32_t end = end_arg->Int32Value(); \
- if (start < 0 || end < 0) { \
- return ThrowException(Exception::TypeError( \
- String::New("Bad argument."))); \
- } \
- if (!(start <= end)) { \
- return ThrowException(Exception::Error( \
- String::New("Must have start <= end"))); \
- } \
- if ((size_t)end > parent->length_) { \
- return ThrowException(Exception::Error( \
- String::New("end cannot be longer than parent.length"))); \
- }
+#define SLICE_START_END(start_arg, end_arg, end_max) \
+ size_t start; \
+ size_t end; \
+ CHECK_NOT_OOB(ParseArrayIndex(start_arg, 0, &start)); \
+ CHECK_NOT_OOB(ParseArrayIndex(end_arg, end_max, &end)); \
+ if (end < start) end = start; \
+ CHECK_NOT_OOB(end <= end_max); \
+ size_t length = end - start;
+namespace node {
-static Persistent<String> length_symbol;
-static Persistent<String> write_sym;
-static Persistent<Function> fast_buffer_constructor;
-Persistent<FunctionTemplate> Buffer::constructor_template;
+namespace Buffer {
-Handle<Object> Buffer::New(Handle<String> string) {
- HandleScope scope(node_isolate);
+using v8::Arguments;
+using v8::Function;
+using v8::FunctionTemplate;
+using v8::Handle;
+using v8::HandleScope;
+using v8::Local;
+using v8::Number;
+using v8::Object;
+using v8::Persistent;
+using v8::String;
+using v8::Uint32;
+using v8::Undefined;
+using v8::Value;
- // get Buffer from global scope.
- Local<Object> global = v8::Context::GetCurrent()->Global();
- Local<Value> bv = global->Get(String::NewSymbol("Buffer"));
- assert(bv->IsFunction());
- Local<Function> b = Local<Function>::Cast(bv);
- Local<Value> argv[1] = { Local<Value>::New(node_isolate, string) };
- Local<Object> instance = b->NewInstance(1, argv);
+Persistent<Function> p_buffer_fn;
- return scope.Close(instance);
+
+bool HasInstance(Handle<Value> val) {
+ return val->IsObject() && HasInstance(val.As<Object>());
}
-Buffer* Buffer::New(size_t length) {
- HandleScope scope(node_isolate);
+bool HasInstance(Handle<Object> obj) {
+ if (!obj->HasIndexedPropertiesInExternalArrayData())
+ return false;
+ v8::ExternalArrayType type = obj->GetIndexedPropertiesExternalArrayDataType();
+ return type == v8::kExternalUnsignedByteArray;
+}
- Local<Value> arg = Integer::NewFromUnsigned(length, node_isolate);
- Local<Object> b = constructor_template->GetFunction()->NewInstance(1, &arg);
- if (b.IsEmpty()) return NULL;
- return ObjectWrap::Unwrap<Buffer>(b);
+char* Data(Handle<Value> val) {
+ assert(val->IsObject());
+ return Data(val.As<Object>());
}
-Buffer* Buffer::New(const char* data, size_t length) {
- HandleScope scope(node_isolate);
+char* Data(Handle<Object> obj) {
+ assert(obj->HasIndexedPropertiesInExternalArrayData());
+ return static_cast<char*>(obj->GetIndexedPropertiesExternalArrayData());
+}
- Local<Value> arg = Integer::NewFromUnsigned(0, node_isolate);
- Local<Object> obj = constructor_template->GetFunction()->NewInstance(1, &arg);
- Buffer *buffer = ObjectWrap::Unwrap<Buffer>(obj);
- buffer->Replace(const_cast<char*>(data), length, NULL, NULL);
+size_t Length(Handle<Value> val) {
+ assert(val->IsObject());
+ return Length(val.As<Object>());
+}
+
- return buffer;
+size_t Length(Handle<Object> obj) {
+ assert(obj->HasIndexedPropertiesInExternalArrayData());
+ return obj->GetIndexedPropertiesExternalArrayDataLength();
}
-Buffer* Buffer::New(char *data, size_t length,
- free_callback callback, void *hint) {
+// TODO(trevnorris): would be more efficient to use StringBytes to calculate the
+// length and write out the data beforehand then do the same as New().
+Local<Object> New(Handle<String> string) {
HandleScope scope(node_isolate);
- Local<Value> arg = Integer::NewFromUnsigned(0, node_isolate);
- Local<Object> obj = constructor_template->GetFunction()->NewInstance(1, &arg);
+ Handle<Value> argv[1] = { string };
+ Local<Object> obj = p_buffer_fn->NewInstance(1, argv);
- Buffer *buffer = ObjectWrap::Unwrap<Buffer>(obj);
- buffer->Replace(data, length, callback, hint);
-
- return buffer;
+ return scope.Close(obj);
}
-Handle<Value> Buffer::New(const Arguments& args) {
- if (!args.IsConstructCall()) {
- return FromConstructorTemplate(constructor_template, args);
- }
-
+// TODO(trevnorris): these have a flaw by needing to call the Buffer inst then
+// Alloc. continue to look for a better architecture.
+Local<Object> New(size_t length) {
HandleScope scope(node_isolate);
- if (!args[0]->IsUint32()) return ThrowTypeError("Bad argument");
+ assert(length <= kMaxLength);
- size_t length = args[0]->Uint32Value();
- if (length > Buffer::kMaxLength) {
- return ThrowRangeError("length > kMaxLength");
- }
- new Buffer(args.This(), length);
+ Handle<Value> argv[2];
+ // this is safe b/c Undefined and length fits in an SMI, so there's no risk
+ // of GC reclaiming the values prematurely.
+ argv[0] = Undefined(node_isolate);
+ argv[1] = Uint32::New(length, node_isolate);
+ Local<Object> obj = p_buffer_fn->NewInstance(2, argv);
- return args.This();
+ smalloc::Alloc(obj, new char[length], length);
+
+ return scope.Close(obj);
}
-Buffer::Buffer(Handle<Object> wrapper, size_t length) : ObjectWrap() {
- Wrap(wrapper);
+// TODO(trevnorris): for backwards compatibility this is left to copy the data,
+// but for consistency w/ the other should use data. And a copy version renamed
+// to something else.
+Local<Object> New(const char* data, size_t length) {
+ HandleScope scope(node_isolate);
- length_ = 0;
- callback_ = NULL;
- handle_.SetWrapperClassId(node_isolate, BUFFER_CLASS_ID);
+ assert(length <= kMaxLength);
- Replace(NULL, length, NULL, NULL);
-}
+ Handle<Value> argv[2];
+ // this is safe b/c Undefined and length fits in an SMI, so there's no risk
+ // of GC reclaiming the values prematurely.
+ argv[0] = Undefined(node_isolate);
+ argv[1] = Uint32::New(length, node_isolate);
+ Local<Object> obj = p_buffer_fn->NewInstance(2, argv);
+
+ char* new_data = new char[length];
+ memcpy(new_data, data, length);
+ smalloc::Alloc(obj, new_data, length);
-Buffer::~Buffer() {
- Replace(NULL, 0, NULL, NULL);
+ return scope.Close(obj);
}
-// if replace doesn't have a callback, data must be copied
-// const_cast in Buffer::New requires this
-void Buffer::Replace(char *data, size_t length,
- free_callback callback, void *hint) {
+Local<Object> New(char* data,
+ size_t length,
+ smalloc::FreeCallback callback,
+ void* hint) {
HandleScope scope(node_isolate);
- if (callback_) {
- callback_(data_, callback_hint_);
- } else if (length_) {
- delete [] data_;
- node_isolate->AdjustAmountOfExternalAllocatedMemory(
- -static_cast<intptr_t>(sizeof(Buffer) + length_));
- }
+ assert(length <= kMaxLength);
- length_ = length;
- callback_ = callback;
- callback_hint_ = hint;
-
- if (callback_) {
- data_ = data;
- } else if (length_) {
- data_ = new char[length_];
- if (data)
- memcpy(data_, data, length_);
- node_isolate->AdjustAmountOfExternalAllocatedMemory(sizeof(Buffer) +
- length_);
- } else {
- data_ = NULL;
- }
+ Handle<Value> argv[2];
+ // this is safe b/c Undefined and length fits in an SMI, so there's no risk
+ // of GC reclaiming the values prematurely.
+ argv[0] = Undefined(node_isolate);
+ argv[1] = Uint32::New(length, node_isolate);
+ Local<Object> obj = p_buffer_fn->NewInstance(2, argv);
+
+ smalloc::Alloc(obj, data, length, callback, hint);
- handle_->SetIndexedPropertiesToExternalArrayData(data_,
- kExternalUnsignedByteArray,
- length_);
- handle_->Set(length_symbol, Integer::NewFromUnsigned(length_, node_isolate));
+ return scope.Close(obj);
}
-template <encoding encoding>
-Handle<Value> Buffer::StringSlice(const Arguments& args) {
+Local<Object> Use(char* data, uint32_t length) {
HandleScope scope(node_isolate);
- Buffer *parent = ObjectWrap::Unwrap<Buffer>(args.This());
- SLICE_ARGS(args[0], args[1])
- const char* src = parent->data_ + start;
- size_t slen = (end - start);
- return scope.Close(StringBytes::Encode(src, slen, encoding));
-}
+ assert(length <= kMaxLength);
+ Handle<Value> argv[2];
+ // this is safe b/c Undefined and length fits in an SMI, so there's no risk
+ // of GC reclaiming the values prematurely.
+ argv[0] = Undefined(node_isolate);
+ argv[1] = Uint32::New(length, node_isolate);
+ Local<Object> obj = p_buffer_fn->NewInstance(2, argv);
-Handle<Value> Buffer::BinarySlice(const Arguments& args) {
- return Buffer::StringSlice<BINARY>(args);
+ smalloc::Alloc(obj, data, length);
+
+ return scope.Close(obj);
}
-Handle<Value> Buffer::AsciiSlice(const Arguments& args) {
- return Buffer::StringSlice<ASCII>(args);
-}
+template <encoding encoding>
+Handle<Value> StringSlice(const Arguments& args) {
+ HandleScope scope(node_isolate);
+ ARGS_THIS(args.This())
+ SLICE_START_END(args[0], args[1], obj_length)
-Handle<Value> Buffer::Utf8Slice(const Arguments& args) {
- return Buffer::StringSlice<UTF8>(args);
+ return scope.Close(StringBytes::Encode(obj_data + start, length, encoding));
}
-Handle<Value> Buffer::Ucs2Slice(const Arguments& args) {
- return Buffer::StringSlice<UCS2>(args);
+Handle<Value> BinarySlice(const Arguments& args) {
+ return StringSlice<BINARY>(args);
}
-
-Handle<Value> Buffer::HexSlice(const Arguments& args) {
- return Buffer::StringSlice<HEX>(args);
+Handle<Value> AsciiSlice(const Arguments& args) {
+ return StringSlice<ASCII>(args);
}
-Handle<Value> Buffer::Base64Slice(const Arguments& args) {
- return Buffer::StringSlice<BASE64>(args);
+Handle<Value> Utf8Slice(const Arguments& args) {
+ return StringSlice<UTF8>(args);
}
-// buffer.fill(value, start, end);
-Handle<Value> Buffer::Fill(const Arguments &args) {
- HandleScope scope(node_isolate);
+Handle<Value> Ucs2Slice(const Arguments& args) {
+ return StringSlice<UCS2>(args);
+}
- if (!args[0]->IsInt32()) {
- return ThrowException(Exception::Error(String::New(
- "value is not a number")));
- }
- int value = (char)args[0]->Int32Value();
- Buffer *parent = ObjectWrap::Unwrap<Buffer>(args.This());
- SLICE_ARGS(args[1], args[2])
- memset( (void*)(parent->data_ + start),
- value,
- end - start);
+Handle<Value> HexSlice(const Arguments& args) {
+ return StringSlice<HEX>(args);
+}
- return Undefined(node_isolate);
+
+Handle<Value> Base64Slice(const Arguments& args) {
+ return StringSlice<BASE64>(args);
}
-// var bytesCopied = buffer.copy(target, targetStart, sourceStart, sourceEnd);
-Handle<Value> Buffer::Copy(const Arguments &args) {
+// bytesCopied = buffer.copy(target[, targetStart][, sourceStart][, sourceEnd]);
+Handle<Value> Copy(const Arguments &args) {
HandleScope scope(node_isolate);
- Buffer *source = ObjectWrap::Unwrap<Buffer>(args.This());
+ Local<Object> target = args[0]->ToObject();
- if (!Buffer::HasInstance(args[0])) {
- return ThrowTypeError("First arg should be a Buffer");
- }
+ if (!HasInstance(target))
+ return ThrowTypeError("first arg should be a Buffer");
- Local<Value> target = args[0];
- char* target_data = Buffer::Data(target);
- size_t target_length = Buffer::Length(target);
- size_t target_start = args[1]->IsUndefined() ? 0 : args[1]->Uint32Value();
- size_t source_start = args[2]->IsUndefined() ? 0 : args[2]->Uint32Value();
- size_t source_end = args[3]->IsUndefined() ? source->length_
- : args[3]->Uint32Value();
+ ARGS_THIS(args.This())
+ size_t target_length = target->GetIndexedPropertiesExternalArrayDataLength();
+ char* target_data = static_cast<char*>(
+ target->GetIndexedPropertiesExternalArrayData());
+ size_t target_start;
+ size_t source_start;
+ size_t source_end;
- if (source_end < source_start) {
- return ThrowRangeError("sourceEnd < sourceStart");
- }
+ CHECK_NOT_OOB(ParseArrayIndex(args[1], 0, &target_start));
+ CHECK_NOT_OOB(ParseArrayIndex(args[2], 0, &source_start));
+ CHECK_NOT_OOB(ParseArrayIndex(args[3], obj_length, &source_end));
// Copy 0 bytes; we're done
- if (source_end == source_start) {
- return scope.Close(Integer::New(0, node_isolate));
- }
-
- if (target_start >= target_length) {
- return ThrowRangeError("targetStart out of bounds");
- }
+ if (target_start >= target_length || source_start >= source_end)
+ return scope.Close(Uint32::New(0, node_isolate));
- if (source_start >= source->length_) {
- return ThrowRangeError("sourceStart out of bounds");
- }
+ if (source_start > obj_length)
+ return ThrowRangeError("out of range index");
- if (source_end > source->length_) {
- return ThrowRangeError("sourceEnd out of bounds");
- }
+ if (source_end - source_start > target_length - target_start)
+ source_end = source_start + target_length - target_start;
size_t to_copy = MIN(MIN(source_end - source_start,
target_length - target_start),
- source->length_ - source_start);
+ obj_length - source_start);
- // need to use slightly slower memmove is the ranges might overlap
memmove((void *)(target_data + target_start),
- (const void*)(source->data_ + source_start),
+ (const void*)(obj_data + source_start),
to_copy);
- return scope.Close(Integer::New(to_copy, node_isolate));
+ return scope.Close(Uint32::New(to_copy, node_isolate));
}
-Handle<Value> Buffer::Base64Write(const Arguments& args) {
- return Buffer::StringWrite<BASE64>(args);
-}
+// buffer.fill(value[, start][, end]);
+Handle<Value> Fill(const Arguments &args) {
+ HandleScope scope(node_isolate);
-Handle<Value> Buffer::BinaryWrite(const Arguments& args) {
- return Buffer::StringWrite<BINARY>(args);
-}
+ ARGS_THIS(args.This())
+ int value;
-Handle<Value> Buffer::Utf8Write(const Arguments& args) {
- return Buffer::StringWrite<UTF8>(args);
-}
+ if (args[0]->IsString()) {
+ String::AsciiValue at(args[0]);
+ value = (*at)[0];
+ } else {
+ value = (char)args[0]->Int32Value();
+ }
-Handle<Value> Buffer::Ucs2Write(const Arguments& args) {
- return Buffer::StringWrite<UCS2>(args);
-}
+ SLICE_START_END(args[1], args[2], obj_length)
-Handle<Value> Buffer::HexWrite(const Arguments& args) {
- return Buffer::StringWrite<HEX>(args);
-}
+ memset((void*)(obj_data + start), value, length);
-Handle<Value> Buffer::AsciiWrite(const Arguments& args) {
- return Buffer::StringWrite<ASCII>(args);
+ return args.This();
}
+
template <encoding encoding>
-Handle<Value> Buffer::StringWrite(const Arguments& args) {
+Handle<Value> StringWrite(const Arguments& args) {
HandleScope scope(node_isolate);
- Buffer* buffer = ObjectWrap::Unwrap<Buffer>(args.This());
+ ARGS_THIS(args.This())
- if (!args[0]->IsString()) {
+ if (!args[0]->IsString())
return ThrowTypeError("Argument must be a string");
- }
-
- Local<String> str = args[0].As<String>();
- int length = str->Length();
+ Local<String> str = args[0]->ToString();
- if (length == 0) {
- return scope.Close(Integer::New(0));
- }
-
- if (encoding == HEX && length % 2 != 0)
+ if (encoding == HEX && str->Length() % 2 != 0)
return ThrowTypeError("Invalid hex string");
+ size_t offset;
+ size_t max_length;
- size_t offset = args[1]->Int32Value();
- size_t max_length = args[2]->IsUndefined() ? buffer->length_ - offset
- : args[2]->Uint32Value();
- max_length = MIN(buffer->length_ - offset, max_length);
+ CHECK_NOT_OOB(ParseArrayIndex(args[1], 0, &offset));
+ CHECK_NOT_OOB(ParseArrayIndex(args[2], obj_length - offset, &max_length));
- if (max_length == 0) {
- // shortcut: nothing to write anyway
- Local<Integer> val = Integer::New(0);
- return scope.Close(val);
- }
+ max_length = MIN(obj_length - offset, max_length);
+
+ if (max_length == 0)
+ return scope.Close(Uint32::New(0, node_isolate));
if (encoding == UCS2)
max_length = max_length / 2;
- if (offset >= buffer->length_) {
- return ThrowTypeError("Offset is out of bounds");
- }
+ if (offset >= obj_length)
+ return ThrowRangeError("Offset is out of bounds");
- char* start = buffer->data_ + offset;
- size_t written = StringBytes::Write(start,
+ size_t written = StringBytes::Write(obj_data + offset,
max_length,
str,
encoding,
NULL);
- return scope.Close(Integer::New(written, node_isolate));
+ return scope.Close(Uint32::New(written, node_isolate));
+}
+
+
+Handle<Value> Base64Write(const Arguments& args) {
+ return StringWrite<BASE64>(args);
+}
+
+
+Handle<Value> BinaryWrite(const Arguments& args) {
+ return StringWrite<BINARY>(args);
+}
+
+
+Handle<Value> Utf8Write(const Arguments& args) {
+ return StringWrite<UTF8>(args);
+}
+
+
+Handle<Value> Ucs2Write(const Arguments& args) {
+ return StringWrite<UCS2>(args);
+}
+
+
+Handle<Value> HexWrite(const Arguments& args) {
+ return StringWrite<HEX>(args);
+}
+
+
+Handle<Value> AsciiWrite(const Arguments& args) {
+ return StringWrite<ASCII>(args);
}
template <typename T, enum Endianness endianness>
Handle<Value> ReadFloatGeneric(const Arguments& args) {
- size_t offset = args[0]->Uint32Value();
bool doAssert = !args[1]->BooleanValue();
+ size_t offset;
+
+ CHECK_NOT_OOB(ParseArrayIndex(args[0], 0, &offset));
if (doAssert) {
- if (!args[0]->IsUint32())
- return ThrowTypeError("offset is not uint");
- size_t len = static_cast<size_t>(
- args.This()->GetIndexedPropertiesExternalArrayDataLength());
+ size_t len = Length(args.This());
if (offset + sizeof(T) > len || offset + sizeof(T) < offset)
return ThrowRangeError("Trying to read beyond buffer length");
}
memcpy(na.bytes, ptr, sizeof(na.bytes));
if (endianness != GetEndianness()) Swizzle(na.bytes, sizeof(na.bytes));
- // TODO: when Number::New is updated to accept an Isolate, make the change
return Number::New(na.val);
}
-Handle<Value> Buffer::ReadFloatLE(const Arguments& args) {
+Handle<Value> ReadFloatLE(const Arguments& args) {
return ReadFloatGeneric<float, kLittleEndian>(args);
}
-Handle<Value> Buffer::ReadFloatBE(const Arguments& args) {
+Handle<Value> ReadFloatBE(const Arguments& args) {
return ReadFloatGeneric<float, kBigEndian>(args);
}
-Handle<Value> Buffer::ReadDoubleLE(const Arguments& args) {
+Handle<Value> ReadDoubleLE(const Arguments& args) {
return ReadFloatGeneric<double, kLittleEndian>(args);
}
-Handle<Value> Buffer::ReadDoubleBE(const Arguments& args) {
+Handle<Value> ReadDoubleBE(const Arguments& args) {
return ReadFloatGeneric<double, kBigEndian>(args);
}
Handle<Value> WriteFloatGeneric(const Arguments& args) {
bool doAssert = !args[2]->BooleanValue();
- if (doAssert) {
- if (!args[0]->IsNumber())
- return ThrowTypeError("value not a number");
- if (!args[1]->IsUint32())
- return ThrowTypeError("offset is not uint");
- }
-
T val = static_cast<T>(args[0]->NumberValue());
- size_t offset = args[1]->Uint32Value();
+ size_t offset;
+
+ CHECK_NOT_OOB(ParseArrayIndex(args[1], 0, &offset));
if (doAssert) {
- size_t len = static_cast<size_t>(
- args.This()->GetIndexedPropertiesExternalArrayDataLength());
+ size_t len = Length(args.This());
if (offset + sizeof(T) > len || offset + sizeof(T) < offset)
return ThrowRangeError("Trying to write beyond buffer length");
}
}
-Handle<Value> Buffer::WriteFloatLE(const Arguments& args) {
+Handle<Value> WriteFloatLE(const Arguments& args) {
return WriteFloatGeneric<float, kLittleEndian>(args);
}
-Handle<Value> Buffer::WriteFloatBE(const Arguments& args) {
+Handle<Value> WriteFloatBE(const Arguments& args) {
return WriteFloatGeneric<float, kBigEndian>(args);
}
-Handle<Value> Buffer::WriteDoubleLE(const Arguments& args) {
+Handle<Value> WriteDoubleLE(const Arguments& args) {
return WriteFloatGeneric<double, kLittleEndian>(args);
}
-Handle<Value> Buffer::WriteDoubleBE(const Arguments& args) {
+Handle<Value> WriteDoubleBE(const Arguments& args) {
return WriteFloatGeneric<double, kBigEndian>(args);
}
-// var nbytes = Buffer.byteLength("string", "utf8")
-Handle<Value> Buffer::ByteLength(const Arguments &args) {
+Handle<Value> ByteLength(const Arguments &args) {
HandleScope scope(node_isolate);
- if (!args[0]->IsString()) {
+ if (!args[0]->IsString())
return ThrowTypeError("Argument must be a string");
- }
Local<String> s = args[0]->ToString();
enum encoding e = ParseEncoding(args[1], UTF8);
- return scope.Close(Integer::New(StringBytes::Size(s, e), node_isolate));
+ return scope.Close(Uint32::New(StringBytes::Size(s, e), node_isolate));
}
-Handle<Value> Buffer::MakeFastBuffer(const Arguments &args) {
+// pass Buffer object to load prototype methods
+Handle<Value> SetupBufferJS(const Arguments& args) {
HandleScope scope(node_isolate);
- if (!Buffer::HasInstance(args[0])) {
- return ThrowTypeError("First argument must be a Buffer");
- }
-
- Buffer *buffer = ObjectWrap::Unwrap<Buffer>(args[0]->ToObject());
- Local<Object> fast_buffer = args[1]->ToObject();
- uint32_t offset = args[2]->Uint32Value();
- uint32_t length = args[3]->Uint32Value();
-
- if (offset > buffer->length_) {
- return ThrowRangeError("offset out of range");
- }
-
- if (offset + length > buffer->length_) {
- return ThrowRangeError("length out of range");
- }
-
- // Check for wraparound. Safe because offset and length are unsigned.
- if (offset + length < offset) {
- return ThrowRangeError("offset or length out of range");
- }
-
- fast_buffer->SetIndexedPropertiesToExternalArrayData(buffer->data_ + offset,
- kExternalUnsignedByteArray,
- length);
-
- return Undefined(node_isolate);
-}
-
-
-bool Buffer::HasInstance(Handle<Value> val) {
- if (!val->IsObject()) return false;
- Local<Object> obj = val->ToObject();
-
- ExternalArrayType type = obj->GetIndexedPropertiesExternalArrayDataType();
- if (type != kExternalUnsignedByteArray)
- return false;
-
- // Also check for SlowBuffers that are empty.
- if (constructor_template->HasInstance(obj))
- return true;
-
- assert(!fast_buffer_constructor.IsEmpty());
- return obj->GetConstructor()->StrictEquals(fast_buffer_constructor);
-}
-
-
-Handle<Value> SetFastBufferConstructor(const Arguments& args) {
assert(args[0]->IsFunction());
- fast_buffer_constructor = Persistent<Function>::New(node_isolate,
- args[0].As<Function>());
- return Undefined(node_isolate);
-}
-
-
-class RetainedBufferInfo: public RetainedObjectInfo {
-public:
- RetainedBufferInfo(Buffer* buffer);
- virtual void Dispose();
- virtual bool IsEquivalent(RetainedObjectInfo* other);
- virtual intptr_t GetHash();
- virtual const char* GetLabel();
- virtual intptr_t GetSizeInBytes();
-private:
- Buffer* buffer_;
- static const char label[];
-};
-
-const char RetainedBufferInfo::label[] = "Buffer";
+ Local<Function> bv = args[0].As<Function>();
+ p_buffer_fn = Persistent<Function>::New(node_isolate, bv);
+ Local<Value> proto_v = bv->Get(String::New("prototype"));
+
+ assert(proto_v->IsObject());
+
+ Local<Object> proto = proto_v.As<Object>();
+
+ bv->Set(String::New("byteLength"),
+ FunctionTemplate::New(ByteLength)->GetFunction());
+
+ proto->Set(String::New("asciiSlice"),
+ FunctionTemplate::New(AsciiSlice)->GetFunction());
+ proto->Set(String::New("base64Slice"),
+ FunctionTemplate::New(Base64Slice)->GetFunction());
+ proto->Set(String::New("binarySlice"),
+ FunctionTemplate::New(BinarySlice)->GetFunction());
+ proto->Set(String::New("hexSlice"),
+ FunctionTemplate::New(HexSlice)->GetFunction());
+ proto->Set(String::New("ucs2Slice"),
+ FunctionTemplate::New(Ucs2Slice)->GetFunction());
+ proto->Set(String::New("utf8Slice"),
+ FunctionTemplate::New(Utf8Slice)->GetFunction());
+
+ proto->Set(String::New("asciiWrite"),
+ FunctionTemplate::New(AsciiWrite)->GetFunction());
+ proto->Set(String::New("base64Write"),
+ FunctionTemplate::New(Base64Write)->GetFunction());
+ proto->Set(String::New("binaryWrite"),
+ FunctionTemplate::New(BinaryWrite)->GetFunction());
+ proto->Set(String::New("hexWrite"),
+ FunctionTemplate::New(HexWrite)->GetFunction());
+ proto->Set(String::New("ucs2Write"),
+ FunctionTemplate::New(Ucs2Write)->GetFunction());
+ proto->Set(String::New("utf8Write"),
+ FunctionTemplate::New(Utf8Write)->GetFunction());
+
+ proto->Set(String::New("readDoubleBE"),
+ FunctionTemplate::New(ReadDoubleBE)->GetFunction());
+ proto->Set(String::New("readDoubleLE"),
+ FunctionTemplate::New(ReadDoubleLE)->GetFunction());
+ proto->Set(String::New("readFloatBE"),
+ FunctionTemplate::New(ReadFloatBE)->GetFunction());
+ proto->Set(String::New("readFloatLE"),
+ FunctionTemplate::New(ReadFloatLE)->GetFunction());
+
+ proto->Set(String::New("writeDoubleBE"),
+ FunctionTemplate::New(WriteDoubleBE)->GetFunction());
+ proto->Set(String::New("writeDoubleLE"),
+ FunctionTemplate::New(WriteDoubleLE)->GetFunction());
+ proto->Set(String::New("writeFloatBE"),
+ FunctionTemplate::New(WriteFloatBE)->GetFunction());
+ proto->Set(String::New("writeFloatLE"),
+ FunctionTemplate::New(WriteFloatLE)->GetFunction());
+
+ proto->Set(String::New("copy"),
+ FunctionTemplate::New(Copy)->GetFunction());
+ proto->Set(String::New("fill"),
+ FunctionTemplate::New(Fill)->GetFunction());
+
+ // for backwards compatibility
+ proto->Set(String::New("offset"), Uint32::New(0, node_isolate), v8::ReadOnly);
-RetainedBufferInfo::RetainedBufferInfo(Buffer* buffer): buffer_(buffer) {
-}
-
-
-void RetainedBufferInfo::Dispose() {
- buffer_ = NULL;
- delete this;
-}
-
-
-bool RetainedBufferInfo::IsEquivalent(RetainedObjectInfo* other) {
- return label == other->GetLabel() &&
- buffer_ == static_cast<RetainedBufferInfo*>(other)->buffer_;
-}
-
-
-intptr_t RetainedBufferInfo::GetHash() {
- return reinterpret_cast<intptr_t>(buffer_);
-}
-
-
-const char* RetainedBufferInfo::GetLabel() {
- return label;
-}
-
-
-intptr_t RetainedBufferInfo::GetSizeInBytes() {
- return Buffer::Length(buffer_);
-}
-
-
-RetainedObjectInfo* WrapperInfo(uint16_t class_id, Handle<Value> wrapper) {
- assert(class_id == BUFFER_CLASS_ID);
- assert(Buffer::HasInstance(wrapper));
- Buffer* buffer = Buffer::Unwrap<Buffer>(wrapper.As<Object>());
- return new RetainedBufferInfo(buffer);
+ return Undefined(node_isolate);
}
-void Buffer::Initialize(Handle<Object> target) {
+void Initialize(Handle<Object> target) {
HandleScope scope(node_isolate);
- length_symbol = NODE_PSYMBOL("length");
-
- Local<FunctionTemplate> t = FunctionTemplate::New(Buffer::New);
- constructor_template = Persistent<FunctionTemplate>::New(node_isolate, t);
- constructor_template->InstanceTemplate()->SetInternalFieldCount(1);
- constructor_template->SetClassName(String::NewSymbol("SlowBuffer"));
-
- NODE_SET_PROTOTYPE_METHOD(constructor_template, "binarySlice", Buffer::BinarySlice);
- NODE_SET_PROTOTYPE_METHOD(constructor_template, "asciiSlice", Buffer::AsciiSlice);
- NODE_SET_PROTOTYPE_METHOD(constructor_template, "base64Slice", Buffer::Base64Slice);
- NODE_SET_PROTOTYPE_METHOD(constructor_template, "ucs2Slice", Buffer::Ucs2Slice);
- NODE_SET_PROTOTYPE_METHOD(constructor_template, "hexSlice", Buffer::HexSlice);
- NODE_SET_PROTOTYPE_METHOD(constructor_template, "utf8Slice", Buffer::Utf8Slice);
- // TODO NODE_SET_PROTOTYPE_METHOD(t, "utf16Slice", Utf16Slice);
-
- NODE_SET_PROTOTYPE_METHOD(constructor_template, "utf8Write", Buffer::Utf8Write);
- NODE_SET_PROTOTYPE_METHOD(constructor_template, "asciiWrite", Buffer::AsciiWrite);
- NODE_SET_PROTOTYPE_METHOD(constructor_template, "binaryWrite", Buffer::BinaryWrite);
- NODE_SET_PROTOTYPE_METHOD(constructor_template, "base64Write", Buffer::Base64Write);
- NODE_SET_PROTOTYPE_METHOD(constructor_template, "ucs2Write", Buffer::Ucs2Write);
- NODE_SET_PROTOTYPE_METHOD(constructor_template, "hexWrite", Buffer::HexWrite);
- NODE_SET_PROTOTYPE_METHOD(constructor_template, "readFloatLE", Buffer::ReadFloatLE);
- NODE_SET_PROTOTYPE_METHOD(constructor_template, "readFloatBE", Buffer::ReadFloatBE);
- NODE_SET_PROTOTYPE_METHOD(constructor_template, "readDoubleLE", Buffer::ReadDoubleLE);
- NODE_SET_PROTOTYPE_METHOD(constructor_template, "readDoubleBE", Buffer::ReadDoubleBE);
- NODE_SET_PROTOTYPE_METHOD(constructor_template, "writeFloatLE", Buffer::WriteFloatLE);
- NODE_SET_PROTOTYPE_METHOD(constructor_template, "writeFloatBE", Buffer::WriteFloatBE);
- NODE_SET_PROTOTYPE_METHOD(constructor_template, "writeDoubleLE", Buffer::WriteDoubleLE);
- NODE_SET_PROTOTYPE_METHOD(constructor_template, "writeDoubleBE", Buffer::WriteDoubleBE);
- NODE_SET_PROTOTYPE_METHOD(constructor_template, "fill", Buffer::Fill);
- NODE_SET_PROTOTYPE_METHOD(constructor_template, "copy", Buffer::Copy);
-
- NODE_SET_METHOD(constructor_template->GetFunction(),
- "byteLength",
- Buffer::ByteLength);
- NODE_SET_METHOD(constructor_template->GetFunction(),
- "makeFastBuffer",
- Buffer::MakeFastBuffer);
-
- target->Set(String::NewSymbol("SlowBuffer"), constructor_template->GetFunction());
- target->Set(String::NewSymbol("setFastBufferConstructor"),
- FunctionTemplate::New(SetFastBufferConstructor)->GetFunction());
-
- v8::HeapProfiler* heap_profiler = node_isolate->GetHeapProfiler();
- heap_profiler->SetWrapperClassInfoProvider(BUFFER_CLASS_ID, WrapperInfo);
+ target->Set(String::New("setupBufferJS"),
+ FunctionTemplate::New(SetupBufferJS)->GetFunction());
}
+} // namespace Buffer
+
} // namespace node
NODE_MODULE(node_buffer, node::Buffer::Initialize)
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
+#include "smalloc.h"
+#include "v8.h"
+
#ifndef NODE_BUFFER_H_
#define NODE_BUFFER_H_
-#include "node.h"
-#include "node_object_wrap.h"
-#include "v8.h"
-#include <assert.h>
-
namespace node {
-/* A buffer is a chunk of memory stored outside the V8 heap, mirrored by an
- * object in javascript. The object is not totally opaque, one can access
- * individual bytes with [] and slice it into substrings or sub-buffers
- * without copying memory.
- */
-
-/*
- The C++ API for Buffer changed radically between v0.2 and v0.3, in fact
- it was the reason for bumping the version. In v0.2 JavaScript Buffers and
- C++ Buffers were in one-to-one correspondence via ObjectWrap. We found
- that it was faster to expose the C++ Buffers to JavaScript as a
- "SlowBuffer" which is used as a private backend to pure JavaScript
- "Buffer" objects - a 'Buffer' in v0.3 might look like this:
-
- { _parent: s,
- _offset: 520,
- length: 5 }
-
- Migrating code C++ Buffer code from v0.2 to v0.3 is difficult. Here are
- some tips:
- - buffer->data() calls should become Buffer::Data(buffer) calls.
- - buffer->length() calls should become Buffer::Length(buffer) calls.
- - There should not be any ObjectWrap::Unwrap<Buffer>() calls. You should
- not be storing pointers to Buffer objects at all - as they are
- now considered internal structures. Instead consider making a
- JavaScript reference to the buffer.
-
- See the source code node-png as an example of a module which successfully
- compiles on both v0.2 and v0.3 while making heavy use of the C++ Buffer
- API.
-
- */
-
-
-class NODE_EXTERN Buffer: public ObjectWrap {
- public:
- // mirrors deps/v8/src/objects.h
- static const unsigned int kMaxLength = 0x3fffffff;
-
- static v8::Persistent<v8::FunctionTemplate> constructor_template;
-
- static bool HasInstance(v8::Handle<v8::Value> val);
-
- static inline char* Data(v8::Handle<v8::Value> val) {
- assert(val->IsObject());
- void* data = val.As<v8::Object>()->GetIndexedPropertiesExternalArrayData();
- return static_cast<char*>(data);
- }
-
- static inline char* Data(Buffer *b) {
- return Buffer::Data(b->handle_);
- }
-
- static inline size_t Length(v8::Handle<v8::Value> val) {
- assert(val->IsObject());
- int len = val.As<v8::Object>()
- ->GetIndexedPropertiesExternalArrayDataLength();
- return static_cast<size_t>(len);
- }
-
- static inline size_t Length(Buffer *b) {
- return Buffer::Length(b->handle_);
- }
-
-
- ~Buffer();
-
- typedef void (*free_callback)(char *data, void *hint);
-
- // C++ API for constructing fast buffer
- static v8::Handle<v8::Object> New(v8::Handle<v8::String> string);
-
- static void Initialize(v8::Handle<v8::Object> target);
-
- // public constructor
- static Buffer* New(size_t length);
- // public constructor - data is copied
- static Buffer* New(const char *data, size_t len);
- // public constructor
- static Buffer* New(char *data, size_t length,
- free_callback callback, void *hint);
-
- private:
- static v8::Handle<v8::Value> New(const v8::Arguments &args);
-
- template <encoding encoding>
- static v8::Handle<v8::Value> StringSlice(const v8::Arguments &args);
- static v8::Handle<v8::Value> BinarySlice(const v8::Arguments &args);
- static v8::Handle<v8::Value> AsciiSlice(const v8::Arguments &args);
- static v8::Handle<v8::Value> Base64Slice(const v8::Arguments &args);
- static v8::Handle<v8::Value> Utf8Slice(const v8::Arguments &args);
- static v8::Handle<v8::Value> Ucs2Slice(const v8::Arguments &args);
- static v8::Handle<v8::Value> HexSlice(const v8::Arguments &args);
-
- template <encoding encoding>
- static v8::Handle<v8::Value> StringWrite(const v8::Arguments &args);
- static v8::Handle<v8::Value> BinaryWrite(const v8::Arguments &args);
- static v8::Handle<v8::Value> Base64Write(const v8::Arguments &args);
- static v8::Handle<v8::Value> AsciiWrite(const v8::Arguments &args);
- static v8::Handle<v8::Value> Utf8Write(const v8::Arguments &args);
- static v8::Handle<v8::Value> Ucs2Write(const v8::Arguments &args);
- static v8::Handle<v8::Value> HexWrite(const v8::Arguments &args);
- static v8::Handle<v8::Value> ReadFloatLE(const v8::Arguments &args);
- static v8::Handle<v8::Value> ReadFloatBE(const v8::Arguments &args);
- static v8::Handle<v8::Value> ReadDoubleLE(const v8::Arguments &args);
- static v8::Handle<v8::Value> ReadDoubleBE(const v8::Arguments &args);
- static v8::Handle<v8::Value> WriteFloatLE(const v8::Arguments &args);
- static v8::Handle<v8::Value> WriteFloatBE(const v8::Arguments &args);
- static v8::Handle<v8::Value> WriteDoubleLE(const v8::Arguments &args);
- static v8::Handle<v8::Value> WriteDoubleBE(const v8::Arguments &args);
- static v8::Handle<v8::Value> ByteLength(const v8::Arguments &args);
- static v8::Handle<v8::Value> MakeFastBuffer(const v8::Arguments &args);
- static v8::Handle<v8::Value> Fill(const v8::Arguments &args);
- static v8::Handle<v8::Value> Copy(const v8::Arguments &args);
-
- Buffer(v8::Handle<v8::Object> wrapper, size_t length);
- void Replace(char *data, size_t length, free_callback callback, void *hint);
-
- size_t length_;
- char* data_;
- free_callback callback_;
- void* callback_hint_;
-};
-
-
-} // namespace node buffer
+namespace Buffer {
+
+static const unsigned int kMaxLength = smalloc::kMaxLength;
+
+bool HasInstance(v8::Handle<v8::Value> val);
+bool HasInstance(v8::Handle<v8::Object> val);
+char* Data(v8::Handle<v8::Value> val);
+char* Data(v8::Handle<v8::Object> val);
+size_t Length(v8::Handle<v8::Value> val);
+size_t Length(v8::Handle<v8::Object> val);
+
+// public constructor
+v8::Local<v8::Object> New(size_t length);
+// public constructor from string
+v8::Local<v8::Object> New(v8::Handle<v8::String> string);
+// public constructor - data is copied
+// TODO(trevnorris): should be something like Copy()
+v8::Local<v8::Object> New(const char* data, size_t len);
+// public constructor - data is used, callback is passed data on object gc
+v8::Local<v8::Object> New(char* data,
+ size_t length,
+ smalloc::FreeCallback callback,
+ void* hint);
+
+// public constructor - data is used.
+// TODO(trevnorris): should be New() for consistency
+v8::Local<v8::Object> Use(char* data, uint32_t len);
+
+} // namespace Buffer
+
+} // namespace node
#endif // NODE_BUFFER_H_
}
-void SessionDataFree(char* data, void* hint) {
- delete[] data;
-}
-
-
int SecureContext::NewSessionCallback(SSL* s, SSL_SESSION* sess) {
HandleScope scope(node_isolate);
Handle<Value> argv[2] = {
Buffer::New(reinterpret_cast<char*>(sess->session_id),
- sess->session_id_length)->handle_,
- Buffer::New(serialized, size, SessionDataFree, NULL)->handle_
+ sess->session_id_length),
+ Buffer::Use(serialized, size)
};
if (onnewsession_sym.IsEmpty()) {
hello = Object::New();
hello->Set(sessionid_sym,
Buffer::New(reinterpret_cast<char*>(session_id),
- session_size)->handle_);
+ session_size));
argv[0] = hello;
MakeCallback(conn_->handle_, onclienthello_sym, 1, argv);
return ThrowCryptoTypeError(ERR_get_error());
}
- Buffer* buf = Buffer::New(reinterpret_cast<char*>(out), out_len);
+ Local<Object> buf = Buffer::New(reinterpret_cast<char*>(out), out_len);
if (out) delete[] out;
- return scope.Close(buf->handle_);
+ return scope.Close(buf);
}
if (!r) return ThrowCryptoTypeError(ERR_get_error());
}
- Buffer* buf = Buffer::New(reinterpret_cast<char*>(out_value), out_len);
-
- return scope.Close(buf->handle_);
+ return scope.Close(Buffer::New(reinterpret_cast<char*>(out_value), out_len));
}
}
-void RandomBytesFree(char* data, void* hint) {
- delete[] data;
-}
-
-
template <bool pseudoRandom>
void RandomBytesWork(uv_work_t* work_req) {
RandomBytesRequest* req = container_of(work_req,
argv[1] = Local<Value>::New(node_isolate, Null(node_isolate));
}
else {
- // avoids the malloc + memcpy
- Buffer* buffer = Buffer::New(req->data_, req->size_, RandomBytesFree, NULL);
argv[0] = Local<Value>::New(node_isolate, Null(node_isolate));
- argv[1] = Local<Object>::New(node_isolate, buffer->handle_);
+ argv[1] = Buffer::Use(req->data_, req->size_);
}
}
# define ROUND_UP(a, b) ((a) % (b) ? ((a) + (b)) - ((a) % (b)) : (a))
#endif
+#if defined(__GNUC__) && __GNUC__ >= 4
+# define MUST_USE_RESULT __attribute__((warn_unused_result))
+#else
+# define MUST_USE_RESULT
+#endif
+
// this would have been a template function were it not for the fact that g++
// sometimes fails to resolve it...
#define THROW_ERROR(fun) \
return GetEndianness() == kBigEndian;
}
+// parse index for external array data
+inline MUST_USE_RESULT bool ParseArrayIndex(v8::Handle<v8::Value> arg,
+ size_t def,
+ size_t* ret) {
+ if (arg->IsUndefined()) {
+ *ret = def;
+ return true;
+ }
+
+ int32_t tmp_i = arg->Int32Value();
+
+ if (tmp_i < 0)
+ return false;
+
+ *ret = static_cast<size_t>(tmp_i);
+ return true;
+}
+
} // namespace node
#endif // SRC_NODE_INTERNALS_H_
static Local<Object> NewSlab(unsigned int size) {
HandleScope scope(node_isolate);
- Local<Value> arg = Integer::NewFromUnsigned(ROUND_UP(size, 16), node_isolate);
- Local<Object> buf = Buffer::constructor_template
- ->GetFunction()
- ->NewInstance(1, &arg);
+ Local<Object> buf = Buffer::New(ROUND_UP(size, 16));
return scope.Close(buf);
}
Local<String> val;
switch (encoding) {
case BUFFER:
- return scope.Close(Buffer::New(buf, buflen)->handle_);
+ return scope.Close(Buffer::New(buf, buflen));
case ASCII:
if (contains_non_ascii(buf, buflen)) {
return 0;
// Serialize session
- Local<Object> buff = Local<Object>::New(Buffer::New(size)->handle_);
+ Local<Object> buff = Buffer::New(size);
unsigned char* serialized = reinterpret_cast<unsigned char*>(
Buffer::Data(buff));
memset(serialized, 0, size);
i2d_SSL_SESSION(sess, &serialized);
- Local<Object> session = Local<Object>::New(
- Buffer::New(reinterpret_cast<char*>(sess->session_id),
- sess->session_id_length)->handle_);
+ Local<Object> session = Buffer::New(reinterpret_cast<char*>(sess->session_id),
+ sess->session_id_length);
Handle<Value> argv[2] = { session, buff };
MakeCallback(c->handle_, onnewsession_sym, ARRAY_SIZE(argv), argv);
do {
read = SSL_read(ssl_, out, sizeof(out));
if (read > 0) {
- Local<Value> buff = Local<Value>::New(Buffer::New(out, read)->handle_);
+ Local<Value> buff = Buffer::New(out, read);
Handle<Value> argv[3] = {
buff,
Integer::New(0, node_isolate),
hello_obj = Object::New();
hello_obj->Set(sessionid_sym,
Buffer::New(reinterpret_cast<char*>(session_id),
- session_size)->handle_);
+ session_size));
argv[0] = hello_obj;
MakeCallback(handle_, onclienthello_sym, 1, argv);
+++ /dev/null
-// Copyright Joyent, Inc. and other Node contributors.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a
-// copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to permit
-// persons to whom the Software is furnished to do so, subject to the
-// following conditions:
-//
-// The above copyright notice and this permission notice shall be included
-// in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
-// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
-// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
-// USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-var common = require('../common');
-var assert = require('assert');
-
-// This is not a great test. It depends on a Node internal, namely the slab
-// size. Maybe we should expose that in some way. Then again, maybe not...
-for (var n = 1; n <= 8192; ++n) {
- Buffer(n);
- Buffer(0).write('', 'base64');
-}
var common = require('../common');
var assert = require('assert');
-var SlowBuffer = require('buffer').SlowBuffer;
var Buffer = require('buffer').Buffer;
// counter to ensure unique value is always copied
var cntr = 0;
-// Regression test for segfault introduced in commit e501ce4.
-['base64','binary','ucs2','utf8','ascii'].forEach(function(encoding) {
- var buf = new SlowBuffer(0);
- buf.write('', encoding);
-});
-
var b = Buffer(1024); // safe constructor
console.log('b.length == %d', b.length);
}
-// copy from fast to slow buffer
-var sb = new SlowBuffer(b.length);
-var copied = b.copy(sb);
-console.log('copied %d bytes from b into sb');
-for (var i = 0; i < sb.length; i++) {
- assert.strictEqual(sb[i], b[i]);
-}
-
var caught_error = null;
// try to copy from before the beginning of b
caught_error = err;
}
-// copy from b to c with negative sourceStart
-b.fill(++cntr);
-c.fill(++cntr);
-var copied = b.copy(c, 0, -1);
-assert.strictEqual(c.length, copied);
-console.log('copied %d bytes from b into c w/ negative sourceStart', copied);
-for (var i = 0; i < c.length; i++) {
- assert.strictEqual(b[i], c[i]);
-}
+// copy throws at negative sourceStart
+assert.throws(function() {
+ Buffer(5).copy(Buffer(5), 0, -1);
+}, RangeError);
// check sourceEnd resets to targetEnd if former is greater than the latter
b.fill(++cntr);
assert.strictEqual(b[i], c[i]);
}
-// copy from fast buffer to slow buffer without parameters
-var sb = new SlowBuffer(b.length);
-sb.fill(++cntr, 0, sb.length);
-b.fill(++cntr);
-var copied = b.copy(sb);
-console.log('copied %d bytes from fast buffer to slow buffer', copied);
-for (var i = 0 ; i < b.length; i++) {
- assert.strictEqual(b[i], sb[i]);
-}
-
// throw with negative sourceEnd
console.log('test copy at negative sourceEnd');
assert.throws(function() {
b.copy(c, 0, 0, -1);
}, RangeError);
-// throw when sourceStart is greater than sourceEnd
-assert.throws(function() {
- b.copy(c, 0, 100, 10);
-}, RangeError);
+// when sourceStart is greater than sourceEnd, zero copied
+assert.equal(b.copy(c, 0, 100, 10), 0);
-// throw attempting to copy after end of c
-assert.throws(function() {
- b.copy(c, 512, 0, 10);
-}, RangeError);
+// when targetStart > targetLength, zero copied
+assert.equal(b.copy(c, 512, 0, 10), 0);
var caught_error;
new Buffer(0);
// try to write a 0-length string beyond the end of b
-b.write('', 1024);
-b.write('', 2048);
+assert.throws(function() {
+ b.write('', 2048);
+}, RangeError);
+
+// throw when writing to negative offset
+assert.throws(function() {
+ b.write('a', -1);
+}, RangeError);
// throw when writing past bounds from the pool
assert.throws(function() {
assert.equal(b2, b4);
-// Test slice on SlowBuffer GH-843
-var SlowBuffer = process.binding('buffer').SlowBuffer;
-
-function buildSlowBuffer(data) {
+function buildBuffer(data) {
if (Array.isArray(data)) {
- var buffer = new SlowBuffer(data.length);
+ var buffer = new Buffer(data.length);
data.forEach(function(v, k) {
buffer[k] = v;
});
return null;
}
-var x = buildSlowBuffer([0x81, 0xa3, 0x66, 0x6f, 0x6f, 0xa3, 0x62, 0x61, 0x72]);
+var x = buildBuffer([0x81, 0xa3, 0x66, 0x6f, 0x6f, 0xa3, 0x62, 0x61, 0x72]);
console.log(x.inspect());
-assert.equal('<SlowBuffer 81 a3 66 6f 6f a3 62 61 72>', x.inspect());
+assert.equal('<Buffer 81 a3 66 6f 6f a3 62 61 72>', x.inspect());
var z = x.slice(4);
console.log(z.inspect());
for (; i < b.length; i++) assert.equal(0, b[i]);
['ucs2', 'ucs-2', 'utf16le', 'utf-16le'].forEach(function(encoding) {
- var b = new SlowBuffer(10);
+ var b = new Buffer(10);
b.write('あいうえお', encoding);
assert.equal(b.toString(encoding), 'あいうえお');
});
assert.equal(0xbe, b[2]);
assert.equal(0xef, b[3]);
-// testing invalid encoding on SlowBuffer.toString
+// testing invalid encoding on Buffer.toString
caught_error = null;
try {
var copied = b.toString('invalid');
}
assert.strictEqual('Unknown encoding: invalid', caught_error.message);
-// testing invalid encoding on SlowBuffer.write
+// testing invalid encoding on Buffer.write
caught_error = null;
try {
var copied = b.write('some string', 0, 5, 'invalid');
assert.strictEqual('Unknown encoding: invalid', caught_error.message);
-// This should not segfault the program.
-assert.throws(function() {
- new Buffer('"pong"', 0, 6, 8031, '127.0.0.1');
-});
-
// #1210 Test UTF-8 string includes null character
var buf = new Buffer('\0');
assert.equal(buf.length, 1);
Buffer(3.3).toString(); // throws bad argument error in commit 43cb4ec
assert.equal(Buffer(-1).length, 0);
assert.equal(Buffer(NaN).length, 0);
-assert.equal(Buffer(3.3).length, 4);
-assert.equal(Buffer({length: 3.3}).length, 4);
+assert.equal(Buffer(3.3).length, 3);
+assert.equal(Buffer({length: 3.3}).length, 3);
assert.equal(Buffer({length: 'BAM'}).length, 0);
// Make sure that strings are not coerced to numbers.
}, RangeError);
assert.throws(function() {
new Buffer(0xFFFFFFFFF);
-}, TypeError);
+}, RangeError);
// attempt to overflow buffers, similar to previous bug in array buffers
assert.throws(function() {
var buf = new Buffer(8);
buf.readFloatLE(0xffffffff);
-}, /Trying to access beyond buffer length/);
+}, RangeError);
assert.throws(function() {
var buf = new Buffer(8);
buf.writeFloatLE(0.0, 0xffffffff);
-}, /Trying to access beyond buffer length/);
+}, RangeError);
assert.throws(function() {
- var buf = new SlowBuffer(8);
+ var buf = new Buffer(8);
buf.readFloatLE(0xffffffff);
-}, /Trying to read beyond buffer length/);
+}, RangeError);
assert.throws(function() {
- var buf = new SlowBuffer(8);
+ var buf = new Buffer(8);
buf.writeFloatLE(0.0, 0xffffffff);
-}, /Trying to write beyond buffer length/);
+}, RangeError);
// ensure negative values can't get past offset
assert.throws(function() {
var buf = new Buffer(8);
buf.readFloatLE(-1);
-}, /offset is not uint/);
+}, RangeError);
assert.throws(function() {
var buf = new Buffer(8);
buf.writeFloatLE(0.0, -1);
-}, /offset is not uint/);
+}, RangeError);
assert.throws(function() {
- var buf = new SlowBuffer(8);
+ var buf = new Buffer(8);
buf.readFloatLE(-1);
-}, /offset is not uint/);
+}, RangeError);
assert.throws(function() {
- var buf = new SlowBuffer(8);
+ var buf = new Buffer(8);
buf.writeFloatLE(0.0, -1);
-}, /offset is not uint/);
+}, RangeError);
// offset checks
var buf = new Buffer(0);
-assert.throws(function() { buf.readUInt8(0); }, /beyond buffer length/);
-assert.throws(function() { buf.readInt8(0); }, /beyond buffer length/);
+assert.throws(function() { buf.readUInt8(0); }, RangeError);
+assert.throws(function() { buf.readInt8(0); }, RangeError);
[16, 32].forEach(function(bits) {
var buf = new Buffer(bits / 8 - 1);
- assert.throws(
- function() { buf['readUInt' + bits + 'BE'](0); },
- /beyond buffer length/,
- 'readUInt' + bits + 'BE'
- );
-
- assert.throws(
- function() { buf['readUInt' + bits + 'LE'](0); },
- /beyond buffer length/,
- 'readUInt' + bits + 'LE'
- );
-
- assert.throws(
- function() { buf['readInt' + bits + 'BE'](0); },
- /beyond buffer length/,
- 'readInt' + bits + 'BE()'
- );
-
- assert.throws(
- function() { buf['readInt' + bits + 'LE'](0); },
- /beyond buffer length/,
- 'readInt' + bits + 'LE()'
- );
-});
+ assert.throws(function() { buf['readUInt' + bits + 'BE'](0); },
+ RangeError,
+ 'readUInt' + bits + 'BE');
-// SlowBuffer sanity checks.
-assert.throws(function() {
- var len = 0xfffff;
- var sbuf = new SlowBuffer(len);
- var buf = new Buffer(sbuf, len, 0);
- SlowBuffer.makeFastBuffer(sbuf, buf, -len, len); // Should throw.
- for (var i = 0; i < len; ++i) buf[i] = 0x42; // Try to force segfault.
-}, RangeError);
+ assert.throws(function() { buf['readUInt' + bits + 'LE'](0); },
+ RangeError,
+ 'readUInt' + bits + 'LE');
-assert.throws(function() {
- var len = 0xfffff;
- var sbuf = new SlowBuffer(len);
- var buf = new Buffer(sbuf, len, -len); // Should throw.
- for (var i = 0; i < len; ++i) buf[i] = 0x42; // Try to force segfault.
-}, RangeError);
+ assert.throws(function() { buf['readInt' + bits + 'BE'](0); },
+ RangeError,
+ 'readInt' + bits + 'BE()');
-assert.throws(function() {
- var sbuf = new SlowBuffer(1);
- var buf = new Buffer(sbuf, 1, 0);
- buf.length = 0xffffffff;
- buf.slice(0xffffff0, 0xffffffe); // Should throw.
-}, Error);
+ assert.throws(function() { buf['readInt' + bits + 'LE'](0); },
+ RangeError,
+ 'readInt' + bits + 'LE()');
+});
+// test Buffer slice
(function() {
var buf = new Buffer('0123456789');
assert.equal(buf.slice(-10, 10), '0123456789');
assert.throws(function() {
Buffer('', 'buffer');
}, TypeError);
-
-assert.doesNotThrow(function () {
- var slow = new SlowBuffer(1);
- assert(slow.write('', Buffer.poolSize * 10) === 0);
- var fast = new Buffer(1);
- assert(fast.write('', Buffer.poolSize * 10) === 0);
-});
/*
* Tests to verify we're reading in doubles correctly
*/
-var SlowBuffer = process.binding('buffer').SlowBuffer;
var common = require('../common');
var ASSERT = require('assert');
test(Buffer);
-test(SlowBuffer);
/*
* Tests to verify we're reading in floats correctly
*/
-var SlowBuffer = process.binding('buffer').SlowBuffer;
var common = require('../common');
var ASSERT = require('assert');
test(Buffer);
-test(SlowBuffer);
/*
* Tests to verify we're reading in signed integers correctly
*/
-var SlowBuffer = process.binding('buffer').SlowBuffer;
var common = require('../common');
var ASSERT = require('assert');
test8(Buffer);
-test8(SlowBuffer);
test16(Buffer);
-test16(SlowBuffer);
test32(Buffer);
-test32(SlowBuffer);
* A battery of tests to help us read a series of uints
*/
-var SlowBuffer = process.binding('buffer').SlowBuffer;
var common = require('../common');
var ASSERT = require('assert');
test8(Buffer);
-test8(SlowBuffer);
test16(Buffer);
-test16(SlowBuffer);
test32(Buffer);
-test32(SlowBuffer);
/*
* Tests to verify we're writing doubles correctly
*/
-var SlowBuffer = process.binding('buffer').SlowBuffer;
var common = require('../common');
var ASSERT = require('assert');
test(Buffer);
-test(SlowBuffer);
/*
* Tests to verify we're writing floats correctly
*/
-var SlowBuffer = process.binding('buffer').SlowBuffer;
var common = require('../common');
var ASSERT = require('assert');
test(Buffer);
-test(SlowBuffer);
/*
* Tests to verify we're writing signed integers correctly
*/
-var SlowBuffer = process.binding('buffer').SlowBuffer;
var common = require('../common');
var ASSERT = require('assert');
test8(Buffer);
-test8(SlowBuffer);
test16(Buffer);
-test16(SlowBuffer);
test32(Buffer);
-test32(SlowBuffer);
/*
* A battery of tests to help us read a series of uints
*/
-var SlowBuffer = process.binding('buffer').SlowBuffer;
var common = require('../common');
var ASSERT = require('assert');
test8(Buffer);
-test8(SlowBuffer);
test16(Buffer);
-test16(SlowBuffer);
test32(Buffer);
-test32(SlowBuffer);