From: Feross Aboukhadijeh Date: Mon, 18 Nov 2013 09:44:50 +0000 (-0800) Subject: Buffer backed by Uint8Array for insane performance! X-Git-Url: https://zoso.dev/?a=commitdiff_plain;h=0a484d08f3f0ee5ec41b3cddfcbe859904f586a9;p=buffer.git Buffer backed by Uint8Array for insane performance! --- diff --git a/buffer_ieee754.js b/buffer_ieee754.js deleted file mode 100644 index fb295c0..0000000 --- a/buffer_ieee754.js +++ /dev/null @@ -1,84 +0,0 @@ -exports.readIEEE754 = function(buffer, offset, isBE, mLen, nBytes) { - var e, m, - eLen = nBytes * 8 - mLen - 1, - eMax = (1 << eLen) - 1, - eBias = eMax >> 1, - nBits = -7, - i = isBE ? 0 : (nBytes - 1), - d = isBE ? 1 : -1, - s = buffer[offset + i]; - - i += d; - - e = s & ((1 << (-nBits)) - 1); - s >>= (-nBits); - nBits += eLen; - for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8); - - m = e & ((1 << (-nBits)) - 1); - e >>= (-nBits); - nBits += mLen; - for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8); - - if (e === 0) { - e = 1 - eBias; - } else if (e === eMax) { - return m ? NaN : ((s ? -1 : 1) * Infinity); - } else { - m = m + Math.pow(2, mLen); - e = e - eBias; - } - return (s ? -1 : 1) * m * Math.pow(2, e - mLen); -}; - -exports.writeIEEE754 = function(buffer, value, offset, isBE, mLen, nBytes) { - var e, m, c, - eLen = nBytes * 8 - mLen - 1, - eMax = (1 << eLen) - 1, - eBias = eMax >> 1, - rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0), - i = isBE ? (nBytes - 1) : 0, - d = isBE ? -1 : 1, - s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0; - - value = Math.abs(value); - - if (isNaN(value) || value === Infinity) { - m = isNaN(value) ? 1 : 0; - e = eMax; - } else { - e = Math.floor(Math.log(value) / Math.LN2); - if (value * (c = Math.pow(2, -e)) < 1) { - e--; - c *= 2; - } - if (e + eBias >= 1) { - value += rt / c; - } else { - value += rt * Math.pow(2, 1 - eBias); - } - if (value * c >= 2) { - e++; - c /= 2; - } - - if (e + eBias >= eMax) { - m = 0; - e = eMax; - } else if (e + eBias >= 1) { - m = (value * c - 1) * Math.pow(2, mLen); - e = e + eBias; - } else { - m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen); - e = 0; - } - } - - for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8); - - e = (e << mLen) | m; - eLen += mLen; - for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8); - - buffer[offset + i - d] |= s * 128; -}; diff --git a/index.js b/index.js index 89c5d27..f46a91a 100644 --- a/index.js +++ b/index.js @@ -1,1124 +1,995 @@ -var assert; -exports.Buffer = Buffer; -exports.SlowBuffer = Buffer; -Buffer.poolSize = 8192; -exports.INSPECT_MAX_BYTES = 50; +var assert +exports.Buffer = Buffer +exports.SlowBuffer = Buffer +exports.INSPECT_MAX_BYTES = 50 +Buffer.poolSize = 8192 -function stringtrim(str) { - if (str.trim) return str.trim(); - return str.replace(/^\s+|\s+$/g, ''); -} +// TODO: throw the correct exception type on errors (look at node source) -function Buffer(subject, encoding, offset) { - if(!assert) assert= require('assert'); - if (!(this instanceof Buffer)) { - return new Buffer(subject, encoding, offset); - } - this.parent = this; - this.offset = 0; +function Buffer (subject, encoding) { + if (!assert) assert = require('assert') // Work-around: node's base64 implementation // allows for non-padded strings while base64-js // does not.. if (encoding == "base64" && typeof subject == "string") { - subject = stringtrim(subject); - while (subject.length % 4 != 0) { - subject = subject + "="; + subject = stringtrim(subject) + while (subject.length % 4 !== 0) { + subject = subject + "=" } } - var type; + // Find the length + var type = typeof subject + var length + if (type === 'number') + length = coerce(subject) + else if (type === 'string') + length = Buffer.byteLength(subject, encoding) + else if (type === 'object') + length = coerce(subject.length); // Assume object is an array + else + throw new Error('First argument needs to be a number, array or string.') - // Are we slicing? - if (typeof offset === 'number') { - this.length = coerce(encoding); - // slicing works, with limitations (no parent tracking/update) - // check https://github.com/toots/buffer-browserify/issues/19 - for (var i = 0; i < this.length; i++) { - this[i] = subject.get(i+offset); - } - } else { - // Find the length - switch (type = typeof subject) { - case 'number': - this.length = coerce(subject); - break; - - case 'string': - this.length = Buffer.byteLength(subject, encoding); - break; - - case 'object': // Assume object is an array - this.length = coerce(subject.length); - break; - - default: - throw new Error('First argument needs to be a number, ' + - 'array or string.'); - } + var buf = augment(new Uint8Array(length)) + if (isArrayIsh(subject)) { // Treat array-ish objects as a byte array. - if (isArrayIsh(subject)) { - for (var i = 0; i < this.length; i++) { - if (subject instanceof Buffer) { - this[i] = subject.readUInt8(i); - } - else { - this[i] = subject[i]; - } - } - } else if (type == 'string') { - // We are a string - this.length = this.write(subject, 0, encoding); - } else if (type === 'number') { - for (var i = 0; i < this.length; i++) { - this[i] = 0; - } + for (var i = 0; i < length; i++) { + if (Buffer.isBuffer(subject)) + buf[i] = subject.readUInt8(i) + else + buf[i] = subject[i] } + } else if (type == 'string') { + buf.write(subject, 0, encoding) } -} -Buffer.prototype.get = function get(i) { - if (i < 0 || i >= this.length) throw new Error('oob'); - return this[i]; -}; + return buf +} -Buffer.prototype.set = function set(i, v) { - if (i < 0 || i >= this.length) throw new Error('oob'); - return this[i] = v; -}; +// STATIC METHODS +// ============== -Buffer.byteLength = function (str, encoding) { - switch (encoding || "utf8") { +Buffer.isEncoding = function(encoding) { + switch ((encoding + '').toLowerCase()) { case 'hex': - return str.length / 2; - case 'utf8': case 'utf-8': - return utf8ToBytes(str).length; - case 'ascii': case 'binary': - return str.length; - case 'base64': - return base64ToBytes(str).length; + case 'ucs2': + case 'ucs-2': + case 'utf16le': + case 'utf-16le': + case 'raw': + return true default: - throw new Error('Unknown encoding'); + return false } -}; - -Buffer.prototype.utf8Write = function (string, offset, length) { - var bytes, pos; - return Buffer._charsWritten = blitBuffer(utf8ToBytes(string), this, offset, length); -}; - -Buffer.prototype.asciiWrite = function (string, offset, length) { - var bytes, pos; - return Buffer._charsWritten = blitBuffer(asciiToBytes(string), this, offset, length); -}; - -Buffer.prototype.binaryWrite = Buffer.prototype.asciiWrite; - -Buffer.prototype.base64Write = function (string, offset, length) { - var bytes, pos; - return Buffer._charsWritten = blitBuffer(base64ToBytes(string), this, offset, length); -}; - -Buffer.prototype.base64Slice = function (start, end) { - var bytes = Array.prototype.slice.apply(this, arguments) - return require("base64-js").fromByteArray(bytes); -}; - -Buffer.prototype.utf8Slice = function () { - var bytes = Array.prototype.slice.apply(this, arguments); - var res = ""; - var tmp = ""; - var i = 0; - while (i < bytes.length) { - if (bytes[i] <= 0x7F) { - res += decodeUtf8Char(tmp) + String.fromCharCode(bytes[i]); - tmp = ""; - } else - tmp += "%" + bytes[i].toString(16); - - i++; - } - - return res + decodeUtf8Char(tmp); } -Buffer.prototype.asciiSlice = function () { - var bytes = Array.prototype.slice.apply(this, arguments); - var ret = ""; - for (var i = 0; i < bytes.length; i++) - ret += String.fromCharCode(bytes[i]); - return ret; +Buffer.isBuffer = function isBuffer (b) { + return b instanceof Uint8Array && b._isBuffer } -Buffer.prototype.binarySlice = Buffer.prototype.asciiSlice; - -Buffer.prototype.inspect = function() { - var out = [], - len = this.length; - for (var i = 0; i < len; i++) { - out[i] = toHex(this[i]); - if (i == exports.INSPECT_MAX_BYTES) { - out[i + 1] = '...'; - break; - } - } - return ''; -}; - - -Buffer.prototype.hexSlice = function(start, end) { - var len = this.length; - - if (!start || start < 0) start = 0; - if (!end || end < 0 || end > len) end = len; - - var out = ''; - for (var i = start; i < end; i++) { - out += toHex(this[i]); - } - return out; -}; - - -Buffer.prototype.toString = function(encoding, start, end) { - encoding = String(encoding || 'utf8').toLowerCase(); - start = +start || 0; - if (typeof end == 'undefined') end = this.length; - - // Fastpath empty strings - if (+end == start) { - return ''; - } - - switch (encoding) { +Buffer.byteLength = function (str, encoding) { + switch (encoding || "utf8") { case 'hex': - return this.hexSlice(start, end); + return str.length / 2 case 'utf8': case 'utf-8': - return this.utf8Slice(start, end); + return utf8ToBytes(str).length case 'ascii': - return this.asciiSlice(start, end); - case 'binary': - return this.binarySlice(start, end); + return str.length case 'base64': - return this.base64Slice(start, end); - - case 'ucs2': - case 'ucs-2': - return this.ucs2Slice(start, end); + return base64ToBytes(str).length default: - throw new Error('Unknown encoding'); + throw new Error('Unknown encoding') + } +} + +Buffer.concat = function (list, totalLength) { + if (!Array.isArray(list)) { + throw new Error('Usage: Buffer.concat(list, [totalLength])\n' + + 'list should be an Array.') } -}; + var i + var buf -Buffer.prototype.hexWrite = function(string, offset, length) { - offset = +offset || 0; - var remaining = this.length - offset; + if (list.length === 0) { + return new Buffer(0) + } else if (list.length === 1) { + return list[0] + } + + if (typeof totalLength !== 'number') { + totalLength = 0 + for (i = 0; i < list.length; i++) { + buf = list[i] + totalLength += buf.length + } + } + + var buffer = new Buffer(totalLength) + var pos = 0 + for (i = 0; i < list.length; i++) { + buf = list[i] + buf.copy(buffer, pos) + pos += buf.length + } + return buffer +} + +// INSTANCE METHODS +// ================ + +function _hexWrite (buf, string, offset, length) { + offset = Number(offset) || 0 + var remaining = buf.length - offset if (!length) { - length = remaining; + length = remaining } else { - length = +length; + length = Number(length) if (length > remaining) { - length = remaining; + length = remaining } } // must be an even number of digits - var strLen = string.length; - if (strLen % 2) { - throw new Error('Invalid hex string'); + var strLen = string.length + if (strLen % 2 !== 0) { + throw new Error('Invalid hex string') } if (length > strLen / 2) { - length = strLen / 2; + length = strLen / 2 } for (var i = 0; i < length; i++) { - var byte = parseInt(string.substr(i * 2, 2), 16); - if (isNaN(byte)) throw new Error('Invalid hex string'); - this[offset + i] = byte; + var byte = parseInt(string.substr(i * 2, 2), 16) + if (isNaN(byte)) throw new Error('Invalid hex string') + buf[offset + i] = byte } - Buffer._charsWritten = i * 2; - return i; -}; + Buffer._charsWritten = i * 2 + return i +} + +function _utf8Write (buf, string, offset, length) { + var bytes, pos + return Buffer._charsWritten = blitBuffer(utf8ToBytes(string), buf, offset, length) +} +function _asciiWrite (buf, string, offset, length) { + var bytes, pos + return Buffer._charsWritten = blitBuffer(asciiToBytes(string), buf, offset, length) +} + +function _binaryWrite (buf, string, offset, length) { + return _asciiWrite(buf, string, offset, length) +} -Buffer.prototype.write = function(string, offset, length, encoding) { +function _base64Write (buf, string, offset, length) { + var bytes, pos + return Buffer._charsWritten = blitBuffer(base64ToBytes(string), buf, offset, length) +} + +function BufferWrite (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; + encoding = length + length = undefined } } else { // legacy - var swap = encoding; - encoding = offset; - offset = length; - length = swap; + var swap = encoding + encoding = offset + offset = length + length = swap } - offset = +offset || 0; - var remaining = this.length - offset; + offset = Number(offset) || 0 + var remaining = this.length - offset if (!length) { - length = remaining; + length = remaining } else { - length = +length; + length = Number(length) if (length > remaining) { - length = remaining; + length = remaining } } - encoding = String(encoding || 'utf8').toLowerCase(); + encoding = String(encoding || 'utf8').toLowerCase() switch (encoding) { case 'hex': - return this.hexWrite(string, offset, length); + return _hexWrite(this, string, offset, length) case 'utf8': case 'utf-8': - return this.utf8Write(string, offset, length); + return _utf8Write(this, string, offset, length) case 'ascii': - return this.asciiWrite(string, offset, length); + return _asciiWrite(this, string, offset, length) case 'binary': - return this.binaryWrite(string, offset, length); + return _binaryWrite(this, string, offset, length) case 'base64': - return this.base64Write(string, offset, length); - - case 'ucs2': - case 'ucs-2': - return this.ucs2Write(string, offset, length); + return _base64Write(this, string, offset, length) default: - throw new Error('Unknown encoding'); + throw new Error('Unknown encoding') } -}; - -// slice(start, end) -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; } -Buffer.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); -}; - -// copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length) -Buffer.prototype.copy = function(target, target_start, start, end) { - var source = this; - start || (start = 0); - if (end === undefined || isNaN(end)) { - end = this.length; - } - target_start || (target_start = 0); +function BufferToString (encoding, start, end) { + encoding = String(encoding || 'utf8').toLowerCase() + start = Number(start) || 0 + end = Number(end) || this.length - if (end < start) throw new Error('sourceEnd < sourceStart'); + // Fastpath empty strings + if (end === start) + return '' - // Copy 0 bytes; we're done - if (end === start) return 0; - if (target.length == 0 || source.length == 0) return 0; + switch (encoding) { + case 'hex': + return _hexSlice(this, start, end) - if (target_start < 0 || target_start >= target.length) { - throw new Error('targetStart out of bounds'); - } + case 'utf8': + case 'utf-8': + return _utf8Slice(this, start, end) - if (start < 0 || start >= source.length) { - throw new Error('sourceStart out of bounds'); - } + case 'ascii': + return _asciiSlice(this, start, end) - if (end < 0 || end > source.length) { - throw new Error('sourceEnd out of bounds'); - } + case 'binary': + return _binarySlice(this, start, end) - // Are we oob? - if (end > this.length) { - end = this.length; - } + case 'base64': + return _base64Slice(this, start, end) - if (target.length - target_start < end - start) { - end = target.length - target_start + start; + default: + throw new Error('Unknown encoding') } +} - var temp = []; - for (var i=start; i= target.length) + throw new Error('targetStart out of bounds') + if (start < 0 || start >= source.length) + throw new Error('sourceStart out of bounds') + if (end < 0 || end > source.length) + throw new Error('sourceEnd out of bounds') - if (end < start) throw new Error('end < start'); + // Are we oob? + if (end > this.length) + end = this.length + if (target.length - target_start < end - start) + end = target.length - target_start + start + + // copy! + for (var i = 0; i < end - start; i++) + target[i + target_start] = this[i + start] +} - // Fill 0 bytes; we're done - if (end === start) return 0; - if (this.length == 0) return 0; +function _base64Slice (buf, start, end) { + var bytes = buf.slice(start, end) + return require('base64-js').fromByteArray(bytes) +} - if (start < 0 || start >= this.length) { - throw new Error('start out of bounds'); - } +function _utf8Slice (buf, start, end) { + var bytes = buf.slice(start, end) + var res = '' + var tmp = '' + var i = 0 + while (i < bytes.length) { + if (bytes[i] <= 0x7F) { + res += decodeUtf8Char(tmp) + String.fromCharCode(bytes[i]) + tmp = '' + } else { + tmp += '%' + bytes[i].toString(16) + } - if (end < 0 || end > this.length) { - throw new Error('end out of bounds'); + i++ } - for (var i = start; i < end; i++) { - this[i] = value; - } + return res + decodeUtf8Char(tmp) } -// Static methods -Buffer.isBuffer = function isBuffer(b) { - return b instanceof Buffer; -}; +function _asciiSlice (buf, start, end) { + var bytes = buf.slice(start, end) + var ret = '' + for (var i = 0; i < bytes.length; i++) + ret += String.fromCharCode(bytes[i]) + return ret +} -Buffer.concat = function (list, totalLength) { - if (!isArray(list)) { - throw new Error("Usage: Buffer.concat(list, [totalLength])\n \ - list should be an Array."); - } +function _binarySlice (buf, start, end) { + return _asciiSlice(buf, start, end) +} - if (list.length === 0) { - return new Buffer(0); - } else if (list.length === 1) { - return list[0]; - } +function _hexSlice (buf, start, end) { + var len = buf.length - if (typeof totalLength !== 'number') { - totalLength = 0; - for (var i = 0; i < list.length; i++) { - var buf = list[i]; - totalLength += buf.length; - } - } + if (!start || start < 0) start = 0 + if (!end || end < 0 || end > len) end = len - var buffer = new Buffer(totalLength); - var pos = 0; - for (var i = 0; i < list.length; i++) { - var buf = list[i]; - buf.copy(buffer, pos); - pos += buf.length; + var out = '' + for (var i = start; i < end; i++) { + out += toHex(buf[i]) } - return buffer; -}; + return out +} -Buffer.isEncoding = function(encoding) { - switch ((encoding + '').toLowerCase()) { - case 'hex': - case 'utf8': - case 'utf-8': - case 'ascii': - case 'binary': - case 'base64': - case 'ucs2': - case 'ucs-2': - case 'utf16le': - case 'utf-16le': - case 'raw': - return true; +// TODO: add test that modifying the new buffer slice will modify memory in the +// original buffer! Use code from: +// http://nodejs.org/api/buffer.html#buffer_buf_slice_start_end +function BufferSlice (start, end) { + var len = this.length + start = clamp(start, len, 0) + end = clamp(end, len, len) + return augment(this.subarray(start, end)) // Uint8Array built-in method +} - default: - return false; +function BufferReadUInt8 (offset, noAssert) { + var buf = this + if (!noAssert) { + assert.ok(offset !== undefined && offset !== null, 'missing offset') + assert.ok(offset < buf.length, 'Trying to read beyond buffer length') } -}; -// helpers + if (offset >= buf.length) + return -function coerce(length) { - // Coerce length to a number (possibly NaN), round up - // in case it's fractional (e.g. 123.456) then do a - // double negate to coerce a NaN to 0. Easy, right? - length = ~~Math.ceil(+length); - return length < 0 ? 0 : length; + return buf[offset] } -function isArray(subject) { - return (Array.isArray || - function(subject){ - return {}.toString.apply(subject) == '[object Array]' - }) - (subject) +function _readUInt16 (buf, offset, littleEndian, noAssert) { + if (!noAssert) { + assert.ok(typeof (littleEndian) === 'boolean', + 'missing or invalid endian') + assert.ok(offset !== undefined && offset !== null, 'missing offset') + assert.ok(offset + 1 < buf.length, 'Trying to read beyond buffer length') + } + + var len = buf.length + if (offset >= len) { + return + } else if (offset + 1 === len) { + var dv = new DataView(new ArrayBuffer(2)) + dv.setUint8(0, buf[len - 1]) + return dv.getUint16(0, littleEndian) + } else { + return buf._dataview.getUint16(offset, littleEndian) + } } -function isArrayIsh(subject) { - return isArray(subject) || Buffer.isBuffer(subject) || - subject && typeof subject === 'object' && - typeof subject.length === 'number'; +function BufferReadUInt16LE (offset, noAssert) { + return _readUInt16(this, offset, true, noAssert) } -function toHex(n) { - if (n < 16) return '0' + n.toString(16); - return n.toString(16); +function BufferReadUInt16BE (offset, noAssert) { + return _readUInt16(this, offset, false, noAssert) } -function utf8ToBytes(str) { - var byteArray = []; - for (var i = 0; i < str.length; i++) - if (str.charCodeAt(i) <= 0x7F) - byteArray.push(str.charCodeAt(i)); - else { - var h = encodeURIComponent(str.charAt(i)).substr(1).split('%'); - for (var j = 0; j < h.length; j++) - byteArray.push(parseInt(h[j], 16)); +function _readUInt32 (buf, offset, littleEndian, noAssert) { + if (!noAssert) { + assert.ok(typeof (littleEndian) === 'boolean', + 'missing or invalid endian') + assert.ok(offset !== undefined && offset !== null, 'missing offset') + assert.ok(offset + 3 < buf.length, 'Trying to read beyond buffer length') + } + + var len = buf.length + if (offset >= len) { + return + } else if (offset + 3 >= len) { + var dv = new DataView(new ArrayBuffer(4)) + for (var i = 0; i + offset < len; i++) { + dv.setUint8(i, buf[i + offset]) } - - return byteArray; -} - -function asciiToBytes(str) { - var byteArray = [] - for (var i = 0; i < str.length; i++ ) - // Node's code seems to be doing this and not & 0x7F.. - byteArray.push( str.charCodeAt(i) & 0xFF ); - - return byteArray; -} - -function base64ToBytes(str) { - return require("base64-js").toByteArray(str); -} - -function blitBuffer(src, dst, offset, length) { - var pos, i = 0; - while (i < length) { - if ((i+offset >= dst.length) || (i >= src.length)) - break; - - dst[i + offset] = src[i]; - i++; + return dv.getUint32(0, littleEndian) + } else { + return buf._dataview.getUint32(offset, littleEndian) } - return i; } -function decodeUtf8Char(str) { - try { - return decodeURIComponent(str); - } catch (err) { - return String.fromCharCode(0xFFFD); // UTF 8 invalid char - } +function BufferReadUInt32LE (offset, noAssert) { + return _readUInt32(this, offset, true, noAssert) } -// read/write bit-twiddling - -Buffer.prototype.readUInt8 = function(offset, noAssert) { - var buffer = this; +function BufferReadUInt32BE (offset, noAssert) { + return _readUInt32(this, offset, false, noAssert) +} +function BufferReadInt8 (offset, noAssert) { + var buf = this if (!noAssert) { assert.ok(offset !== undefined && offset !== null, - 'missing offset'); - - assert.ok(offset < buffer.length, - 'Trying to read beyond buffer length'); + 'missing offset') + assert.ok(offset < buf.length, 'Trying to read beyond buffer length') } - if (offset >= buffer.length) return; - - return buffer[offset]; -}; - -function readUInt16(buffer, offset, isBigEndian, noAssert) { - var val = 0; + if (offset >= buf.length) + return + return buf._dataview.getInt8(offset) +} +function _readInt16 (buf, offset, littleEndian, noAssert) { if (!noAssert) { - assert.ok(typeof (isBigEndian) === 'boolean', - 'missing or invalid endian'); - + assert.ok(typeof (littleEndian) === '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'); + 'missing offset') + assert.ok(offset + 1 < buf.length, 'Trying to read beyond buffer length') } - if (offset >= buffer.length) return 0; - - if (isBigEndian) { - val = buffer[offset] << 8; - if (offset + 1 < buffer.length) { - val |= buffer[offset + 1]; - } + var len = buf.length + if (offset >= len) { + return + } else if (offset + 1 === len) { + var dv = new DataView(new ArrayBuffer(2)) + dv.setUint8(0, buf[len - 1]) + return dv.getInt16(0, littleEndian) } else { - val = buffer[offset]; - if (offset + 1 < buffer.length) { - val |= buffer[offset + 1] << 8; - } + return buf._dataview.getInt16(offset, littleEndian) } - - return val; } -Buffer.prototype.readUInt16LE = function(offset, noAssert) { - return readUInt16(this, offset, false, noAssert); -}; - -Buffer.prototype.readUInt16BE = function(offset, noAssert) { - return readUInt16(this, offset, true, noAssert); -}; +function BufferReadInt16LE (offset, noAssert) { + return _readInt16(this, offset, true, noAssert) +} -function readUInt32(buffer, offset, isBigEndian, noAssert) { - var val = 0; +function BufferReadInt16BE (offset, noAssert) { + return _readInt16(this, offset, false, noAssert) +} +function _readInt32 (buf, offset, littleEndian, noAssert) { 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 (offset >= buffer.length) return 0; - - if (isBigEndian) { - if (offset + 1 < buffer.length) - val = buffer[offset + 1] << 16; - if (offset + 2 < buffer.length) - val |= buffer[offset + 2] << 8; - if (offset + 3 < buffer.length) - val |= buffer[offset + 3]; - val = val + (buffer[offset] << 24 >>> 0); + assert.ok(typeof (littleEndian) === 'boolean', + 'missing or invalid endian') + assert.ok(offset !== undefined && offset !== null, 'missing offset') + assert.ok(offset + 3 < buf.length, 'Trying to read beyond buffer length') + } + + var len = buf.length + if (offset >= len) { + return + } else if (offset + 3 >= len) { + var dv = new DataView(new ArrayBuffer(4)) + for (var i = 0; i + offset < len; i++) { + dv.setUint8(i, buf[i + offset]) + } + return dv.getInt32(0, littleEndian) } else { - if (offset + 2 < buffer.length) - val = buffer[offset + 2] << 16; - if (offset + 1 < buffer.length) - val |= buffer[offset + 1] << 8; - val |= buffer[offset]; - if (offset + 3 < buffer.length) - val = val + (buffer[offset + 3] << 24 >>> 0); + return buf._dataview.getInt32(offset, littleEndian) } - - return val; } -Buffer.prototype.readUInt32LE = function(offset, noAssert) { - return readUInt32(this, offset, false, noAssert); -}; - -Buffer.prototype.readUInt32BE = function(offset, noAssert) { - return readUInt32(this, offset, true, noAssert); -}; - +function BufferReadInt32LE (offset, noAssert) { + return _readInt32(this, offset, true, noAssert) +} -/* - * Signed integer types, yay team! A reminder on how two's complement actually - * works. The first bit is the signed bit, i.e. tells us whether or not the - * number should be positive or negative. If the two's complement value is - * positive, then we're done, as it's equivalent to the unsigned representation. - * - * Now if the number is positive, you're pretty much done, you can just leverage - * the unsigned translations and return those. Unfortunately, negative numbers - * aren't quite that straightforward. - * - * At first glance, one might be inclined to use the traditional formula to - * translate binary numbers between the positive and negative values in two's - * complement. (Though it doesn't quite work for the most negative value) - * Mainly: - * - invert all the bits - * - add one to the result - * - * Of course, this doesn't quite work in Javascript. Take for example the value - * of -128. This could be represented in 16 bits (big-endian) as 0xff80. But of - * course, Javascript will do the following: - * - * > ~0xff80 - * -65409 - * - * Whoh there, Javascript, that's not quite right. But wait, according to - * Javascript that's perfectly correct. When Javascript ends up seeing the - * constant 0xff80, it has no notion that it is actually a signed number. It - * assumes that we've input the unsigned value 0xff80. Thus, when it does the - * binary negation, it casts it into a signed value, (positive 0xff80). Then - * when you perform binary negation on that, it turns it into a negative number. - * - * Instead, we're going to have to use the following general formula, that works - * in a rather Javascript friendly way. I'm glad we don't support this kind of - * weird numbering scheme in the kernel. - * - * (BIT-MAX - (unsigned)val + 1) * -1 - * - * The astute observer, may think that this doesn't make sense for 8-bit numbers - * (really it isn't necessary for them). However, when you get 16-bit numbers, - * you do. Let's go back to our prior example and see how this will look: - * - * (0xffff - 0xff80 + 1) * -1 - * (0x007f + 1) * -1 - * (0x0080) * -1 - */ -Buffer.prototype.readInt8 = function(offset, noAssert) { - var buffer = this; - var neg; +function BufferReadInt32BE (offset, noAssert) { + return _readInt32(this, offset, false, noAssert) +} +function _readFloat (buf, offset, littleEndian, noAssert) { if (!noAssert) { - assert.ok(offset !== undefined && offset !== null, - 'missing offset'); - - assert.ok(offset < buffer.length, - 'Trying to read beyond buffer length'); + assert.ok(typeof (littleEndian) === 'boolean', + 'missing or invalid endian') + assert.ok(offset + 3 < buf.length, 'Trying to read beyond buffer length') } - if (offset >= buffer.length) return; - - neg = buffer[offset] & 0x80; - if (!neg) { - return (buffer[offset]); - } + return buf._dataview.getFloat32(offset, littleEndian) +} - return ((0xff - buffer[offset] + 1) * -1); -}; +function BufferReadFloatLE (offset, noAssert) { + return _readFloat(this, offset, true, noAssert) +} -function readInt16(buffer, offset, isBigEndian, noAssert) { - var neg, val; +function BufferReadFloatBE (offset, noAssert) { + return _readFloat(this, offset, false, noAssert) +} +function _readDouble (buf, offset, littleEndian, noAssert) { 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'); - } - - val = readUInt16(buffer, offset, isBigEndian, noAssert); - neg = val & 0x8000; - if (!neg) { - return val; + assert.ok(typeof (littleEndian) === 'boolean', + 'missing or invalid endian') + assert.ok(offset + 7 < buf.length, 'Trying to read beyond buffer length') } - return (0xffff - val + 1) * -1; + return buf._dataview.getFloat64(offset, littleEndian) } -Buffer.prototype.readInt16LE = function(offset, noAssert) { - return readInt16(this, offset, false, noAssert); -}; - -Buffer.prototype.readInt16BE = function(offset, noAssert) { - return readInt16(this, offset, true, noAssert); -}; +function BufferReadDoubleLE (offset, noAssert) { + return _readDouble(this, offset, true, noAssert) +} -function readInt32(buffer, offset, isBigEndian, noAssert) { - var neg, val; +function BufferReadDoubleBE (offset, noAssert) { + return _readDouble(this, offset, false, noAssert) +} +function BufferWriteUInt8 (value, offset, noAssert) { + var buf = this 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'); + assert.ok(value !== undefined && value !== null, 'missing value') + assert.ok(offset !== undefined && offset !== null, 'missing offset') + assert.ok(offset < buf.length, 'trying to write beyond buffer length') + verifuint(value, 0xff) } - val = readUInt32(buffer, offset, isBigEndian, noAssert); - neg = val & 0x80000000; - if (!neg) { - return (val); - } + if (offset >= buf.length) return - return (0xffffffff - val + 1) * -1; + buf[offset] = value } -Buffer.prototype.readInt32LE = function(offset, noAssert) { - return readInt32(this, offset, false, noAssert); -}; - -Buffer.prototype.readInt32BE = function(offset, noAssert) { - return readInt32(this, offset, true, noAssert); -}; - -function readFloat(buffer, offset, isBigEndian, noAssert) { +function _writeUInt16 (buf, value, offset, littleEndian, noAssert) { if (!noAssert) { - assert.ok(typeof (isBigEndian) === 'boolean', - 'missing or invalid endian'); - - assert.ok(offset + 3 < buffer.length, - 'Trying to read beyond buffer length'); + assert.ok(value !== undefined && value !== null, 'missing value') + assert.ok(typeof (littleEndian) === 'boolean', + 'missing or invalid endian') + assert.ok(offset !== undefined && offset !== null, 'missing offset') + assert.ok(offset + 1 < buf.length, 'trying to write beyond buffer length') + verifuint(value, 0xffff) + } + + var len = buf.length + if (offset >= len) { + return + } else if (offset + 1 === len) { + var dv = new DataView(new ArrayBuffer(2)) + dv.setUint16(0, value, littleEndian) + buf[offset] = dv.getUint8(0) + } else { + buf._dataview.setUint16(offset, value, littleEndian) } - - return require('./buffer_ieee754').readIEEE754(buffer, offset, isBigEndian, - 23, 4); } -Buffer.prototype.readFloatLE = function(offset, noAssert) { - return readFloat(this, offset, false, noAssert); -}; +function BufferWriteUInt16LE (value, offset, noAssert) { + _writeUInt16(this, value, offset, true, noAssert) +} -Buffer.prototype.readFloatBE = function(offset, noAssert) { - return readFloat(this, offset, true, noAssert); -}; +function BufferWriteUInt16BE (value, offset, noAssert) { + _writeUInt16(this, value, offset, false, noAssert) +} -function readDouble(buffer, offset, isBigEndian, noAssert) { +function _writeUInt32 (buf, value, offset, littleEndian, noAssert) { if (!noAssert) { - assert.ok(typeof (isBigEndian) === 'boolean', - 'missing or invalid endian'); - - assert.ok(offset + 7 < buffer.length, - 'Trying to read beyond buffer length'); + assert.ok(value !== undefined && value !== null, 'missing value') + assert.ok(typeof (littleEndian) === 'boolean', + 'missing or invalid endian') + assert.ok(offset !== undefined && offset !== null, 'missing offset') + assert.ok(offset + 3 < buf.length, 'trying to write beyond buffer length') + verifuint(value, 0xffffffff) + } + + var len = buf.length + if (offset >= len) { + return + } else if (offset + 3 >= len) { + var dv = new DataView(new ArrayBuffer(4)) + dv.setUint32(0, value, littleEndian) + for (var i = 0; i + offset < len; i++) { + buf[i + offset] = dv.getUint8(i) + } + } else { + buf._dataview.setUint32(offset, value, littleEndian) } - - return require('./buffer_ieee754').readIEEE754(buffer, offset, isBigEndian, - 52, 8); } -Buffer.prototype.readDoubleLE = function(offset, noAssert) { - return readDouble(this, offset, false, noAssert); -}; - -Buffer.prototype.readDoubleBE = function(offset, noAssert) { - return readDouble(this, offset, true, noAssert); -}; - +function BufferWriteUInt32LE (value, offset, noAssert) { + _writeUInt32(this, value, offset, true, 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'); +function BufferWriteUInt32BE (value, offset, noAssert) { + _writeUInt32(this, value, offset, false, noAssert) +} - assert.ok(value >= 0, - 'specified a negative value for writing an unsigned value'); +function BufferWriteInt8 (value, offset, noAssert) { + var buf = this + if (!noAssert) { + assert.ok(value !== undefined && value !== null, 'missing value') + assert.ok(offset !== undefined && offset !== null, 'missing offset') + assert.ok(offset < buf.length, 'Trying to write beyond buffer length') + verifsint(value, 0x7f, -0x80) + } - assert.ok(value <= max, 'value is larger than maximum value for type'); + if (offset >= buf.length) return - assert.ok(Math.floor(value) === value, 'value has a fractional component'); + buf._dataview.setInt8(offset, value) } -Buffer.prototype.writeUInt8 = function(value, offset, noAssert) { - var buffer = this; - +function _writeInt16 (buf, value, offset, littleEndian, noAssert) { if (!noAssert) { - assert.ok(value !== undefined && value !== null, - 'missing value'); + assert.ok(value !== undefined && value !== null, 'missing value') + assert.ok(typeof (littleEndian) === 'boolean', + 'missing or invalid endian') + assert.ok(offset !== undefined && offset !== null, 'missing offset') + assert.ok(offset + 1 < buf.length, 'Trying to write beyond buffer length') + verifsint(value, 0x7fff, -0x8000) + } + + var len = buf.length + if (offset >= len) { + return + } else if (offset + 1 === len) { + var dv = new DataView(new ArrayBuffer(2)) + dv.setInt16(0, value, littleEndian) + buf[offset] = dv.getUint8(0) + } else { + buf._dataview.setInt16(offset, value, littleEndian) + } +} - assert.ok(offset !== undefined && offset !== null, - 'missing offset'); +function BufferWriteInt16LE (value, offset, noAssert) { + _writeInt16(this, value, offset, true, noAssert) +} - assert.ok(offset < buffer.length, - 'trying to write beyond buffer length'); +function BufferWriteInt16BE (value, offset, noAssert) { + _writeInt16(this, value, offset, false, noAssert) +} - verifuint(value, 0xff); +function _writeInt32 (buf, value, offset, littleEndian, noAssert) { + if (!noAssert) { + assert.ok(value !== undefined && value !== null, 'missing value') + assert.ok(typeof (littleEndian) === 'boolean', + 'missing or invalid endian') + assert.ok(offset !== undefined && offset !== null, 'missing offset') + assert.ok(offset + 3 < buf.length, 'Trying to write beyond buffer length') + verifsint(value, 0x7fffffff, -0x80000000) + } + + var len = buf.length + if (offset >= len) { + return + } else if (offset + 3 >= len) { + var dv = new DataView(new ArrayBuffer(4)) + dv.setInt32(0, value, littleEndian) + for (var i = 0; i + offset < len; i++) { + buf[i + offset] = dv.getUint8(i) + } + } else { + buf._dataview.setInt32(offset, value, littleEndian) } +} - if (offset < buffer.length) { - buffer[offset] = value; - } -}; +function BufferWriteInt32LE (value, offset, noAssert) { + _writeInt32(this, value, offset, true, noAssert) +} -function writeUInt16(buffer, value, offset, isBigEndian, noAssert) { - if (!noAssert) { - assert.ok(value !== undefined && value !== null, - 'missing value'); +function BufferWriteInt32BE (value, offset, noAssert) { + _writeInt32(this, value, offset, false, noAssert) +} - assert.ok(typeof (isBigEndian) === 'boolean', - 'missing or invalid endian'); +function _writeFloat (buf, value, offset, littleEndian, noAssert) { + if (!noAssert) { + assert.ok(value !== undefined && value !== null, 'missing value') + assert.ok(typeof (littleEndian) === 'boolean', + 'missing or invalid endian') + assert.ok(offset !== undefined && offset !== null, 'missing offset') + assert.ok(offset + 3 < buf.length, 'Trying to write beyond buffer length') + verifIEEE754(value, 3.4028234663852886e+38, -3.4028234663852886e+38) + } + + var len = buf.length + if (offset >= len) { + return + } else if (offset + 3 >= len) { + var dv = new DataView(new ArrayBuffer(4)) + dv.setFloat32(0, value, littleEndian) + for (var i = 0; i + offset < len; i++) { + buf[i + offset] = dv.getUint8(i) + } + } else { + buf._dataview.setFloat32(offset, value, littleEndian) + } +} - assert.ok(offset !== undefined && offset !== null, - 'missing offset'); +function BufferWriteFloatLE (value, offset, noAssert) { + _writeFloat(this, value, offset, true, noAssert) +} - assert.ok(offset + 1 < buffer.length, - 'trying to write beyond buffer length'); +function BufferWriteFloatBE (value, offset, noAssert) { + _writeFloat(this, value, offset, false, noAssert) +} - verifuint(value, 0xffff); +function _writeDouble (buf, value, offset, littleEndian, noAssert) { + if (!noAssert) { + assert.ok(value !== undefined && value !== null, 'missing value') + assert.ok(typeof (littleEndian) === 'boolean', + 'missing or invalid endian') + assert.ok(offset !== undefined && offset !== null, 'missing offset') + assert.ok(offset + 7 < buf.length, + 'Trying to write beyond buffer length') + verifIEEE754(value, 1.7976931348623157E+308, -1.7976931348623157E+308) + } + + var len = buf.length + if (offset >= len) { + return + } else if (offset + 7 >= len) { + var dv = new DataView(new ArrayBuffer(8)) + dv.setFloat64(0, value, littleEndian) + for (var i = 0; i + offset < len; i++) { + buf[i + offset] = dv.getUint8(i) + } + } else { + buf._dataview.setFloat64(offset, value, littleEndian) } +} - for (var i = 0; i < Math.min(buffer.length - offset, 2); i++) { - buffer[offset + i] = - (value & (0xff << (8 * (isBigEndian ? 1 - i : i)))) >>> - (isBigEndian ? 1 - i : i) * 8; - } +function BufferWriteDoubleLE (value, offset, noAssert) { + _writeDouble(this, value, offset, true, noAssert) +} +function BufferWriteDoubleBE (value, offset, noAssert) { + _writeDouble(this, value, offset, false, noAssert) } -Buffer.prototype.writeUInt16LE = function(value, offset, noAssert) { - writeUInt16(this, value, offset, false, noAssert); -}; +// fill(value, start=0, end=buffer.length) +function BufferFill (value, start, end) { + if (!value) value = 0 + if (!start) start = 0 + if (!end) end = this.length -Buffer.prototype.writeUInt16BE = function(value, offset, noAssert) { - writeUInt16(this, value, offset, true, noAssert); -}; + if (typeof value === 'string') { + value = value.charCodeAt(0) + } -function writeUInt32(buffer, value, offset, isBigEndian, noAssert) { - if (!noAssert) { - assert.ok(value !== undefined && value !== null, - 'missing value'); + if (typeof value !== 'number' || isNaN(value)) { + throw new Error('value is not a number') + } - assert.ok(typeof (isBigEndian) === 'boolean', - 'missing or invalid endian'); + if (end < start) throw new Error('end < start') - assert.ok(offset !== undefined && offset !== null, - 'missing offset'); + // Fill 0 bytes; we're done + if (end === start) return + if (this.length === 0) return - assert.ok(offset + 3 < buffer.length, - 'trying to write beyond buffer length'); + if (start < 0 || start >= this.length) { + throw new Error('start out of bounds') + } - verifuint(value, 0xffffffff); + if (end < 0 || end > this.length) { + throw new Error('end out of bounds') } - for (var i = 0; i < Math.min(buffer.length - offset, 4); i++) { - buffer[offset + i] = - (value >>> (isBigEndian ? 3 - i : i) * 8) & 0xff; + for (var i = start; i < end; i++) { + this[i] = value } } -Buffer.prototype.writeUInt32LE = function(value, offset, noAssert) { - writeUInt32(this, value, offset, false, noAssert); -}; - -Buffer.prototype.writeUInt32BE = function(value, offset, noAssert) { - writeUInt32(this, value, offset, true, noAssert); -}; - - -/* - * We now move onto our friends in the signed number category. Unlike unsigned - * numbers, we're going to have to worry a bit more about how we put values into - * arrays. Since we are only worrying about signed 32-bit values, we're in - * slightly better shape. Unfortunately, we really can't do our favorite binary - * & in this system. It really seems to do the wrong thing. For example: - * - * > -32 & 0xff - * 224 - * - * What's happening above is really: 0xe0 & 0xff = 0xe0. However, the results of - * this aren't treated as a signed number. Ultimately a bad thing. - * - * What we're going to want to do is basically create the unsigned equivalent of - * our representation and pass that off to the wuint* functions. To do that - * we're going to do the following: - * - * - if the value is positive - * we can pass it directly off to the equivalent wuint - * - if the value is negative - * we do the following computation: - * mb + val + 1, where - * mb is the maximum unsigned value in that byte size - * val is the Javascript negative integer - * - * - * As a concrete value, take -128. In signed 16 bits this would be 0xff80. If - * you do out the computations: - * - * 0xffff - 128 + 1 - * 0xffff - 127 - * 0xff80 - * - * You can then encode this value as the signed version. This is really rather - * hacky, but it should work and get the job done which is our goal here. - */ +function BufferInspect () { + var out = [] + var len = this.length + for (var i = 0; i < len; i++) { + out[i] = toHex(this[i]) + if (i == exports.INSPECT_MAX_BYTES) { + out[i + 1] = '...' + break + } + } + return '' +} -/* - * 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'); +// Creates a new `ArrayBuffer` with the copied memory of the buffer instance. +// Added in Node 0.12. +function BufferToArrayBuffer () { + return (new Buffer(this)).buffer +} - assert.ok(value <= max, 'value larger than maximum allowed value'); - assert.ok(value >= min, 'value smaller than minimum allowed value'); +// HELPER FUNCTIONS +// ================ - assert.ok(Math.floor(value) === value, 'value has a fractional component'); +function stringtrim (str) { + if (str.trim) return str.trim() + return str.replace(/^\s+|\s+$/g, '') } -function verifIEEE754(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'); +function augment (arr) { + if (arr._isBuffer) return arr // do not augment an Uint8Array twice - assert.ok(value >= min, 'value smaller than minimum allowed value'); -} + // Augment the Uint8Array *instance* (not the class!) with Buffer methods + arr.write = BufferWrite -Buffer.prototype.writeInt8 = function(value, offset, noAssert) { - var buffer = this; + arr.toString = BufferToString + arr.toLocaleString = BufferToString + arr.toJSON = BufferToJSON - if (!noAssert) { - assert.ok(value !== undefined && value !== null, - 'missing value'); + arr.copy = BufferCopy + arr.slice = BufferSlice - assert.ok(offset !== undefined && offset !== null, - 'missing offset'); + arr.readUInt8 = BufferReadUInt8 + arr.readUInt16LE = BufferReadUInt16LE + arr.readUInt16BE = BufferReadUInt16BE + arr.readUInt32LE = BufferReadUInt32LE + arr.readUInt32BE = BufferReadUInt32BE - assert.ok(offset < buffer.length, - 'Trying to write beyond buffer length'); + arr.readInt8 = BufferReadInt8 + arr.readInt16LE = BufferReadInt16LE + arr.readInt16BE = BufferReadInt16BE + arr.readInt32LE = BufferReadInt32LE + arr.readInt32BE = BufferReadInt32BE - verifsint(value, 0x7f, -0x80); - } + arr.readFloatLE = BufferReadFloatLE + arr.readFloatBE = BufferReadFloatBE + arr.readDoubleLE = BufferReadDoubleLE + arr.readDoubleBE = BufferReadDoubleBE - if (value >= 0) { - buffer.writeUInt8(value, offset, noAssert); - } else { - buffer.writeUInt8(0xff + value + 1, offset, noAssert); - } -}; + arr.writeUInt8 = BufferWriteUInt8 + arr.writeUInt16LE = BufferWriteUInt16LE + arr.writeUInt16BE = BufferWriteUInt16BE + arr.writeUInt32LE = BufferWriteUInt32LE + arr.writeUInt32BE = BufferWriteUInt32BE -function writeInt16(buffer, value, offset, isBigEndian, noAssert) { - if (!noAssert) { - assert.ok(value !== undefined && value !== null, - 'missing value'); + arr.writeInt8 = BufferWriteInt8 + arr.writeInt16LE = BufferWriteInt16LE + arr.writeInt16BE = BufferWriteInt16BE + arr.writeInt32LE = BufferWriteInt32LE + arr.writeInt32BE = BufferWriteInt32BE - assert.ok(typeof (isBigEndian) === 'boolean', - 'missing or invalid endian'); + arr.writeFloatLE = BufferWriteFloatLE + arr.writeFloatBE = BufferWriteFloatBE + arr.writeDoubleLE = BufferWriteDoubleLE + arr.writeDoubleBE = BufferWriteDoubleBE - assert.ok(offset !== undefined && offset !== null, - 'missing offset'); + arr.fill = BufferFill + arr.inspect = BufferInspect + arr.toArrayBuffer = BufferToArrayBuffer // Node 0.12 - assert.ok(offset + 1 < buffer.length, - 'Trying to write beyond buffer length'); + // Private + arr._isBuffer = true - verifsint(value, 0x7fff, -0x8000); - } + if (arr.byteLength !== 0) + arr._dataview = new DataView(arr.buffer, arr.byteOffset, arr.byteLength) - if (value >= 0) { - writeUInt16(buffer, value, offset, isBigEndian, noAssert); - } else { - writeUInt16(buffer, 0xffff + value + 1, offset, isBigEndian, noAssert); - } + return arr } -Buffer.prototype.writeInt16LE = function(value, offset, noAssert) { - writeInt16(this, value, offset, false, noAssert); -}; +// slice(start, end) +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 +} -Buffer.prototype.writeInt16BE = function(value, offset, noAssert) { - writeInt16(this, value, offset, true, noAssert); -}; +function coerce (length) { + // Coerce length to a number (possibly NaN), round up + // in case it's fractional (e.g. 123.456) then do a + // double negate to coerce a NaN to 0. Easy, right? + length = ~~Math.ceil(+length) + return length < 0 ? 0 : length +} -function writeInt32(buffer, value, offset, isBigEndian, noAssert) { - if (!noAssert) { - assert.ok(value !== undefined && value !== null, - 'missing value'); +function isArrayIsh (subject) { + return Array.isArray(subject) || Buffer.isBuffer(subject) || + subject && typeof subject === 'object' && + typeof subject.length === 'number' +} - assert.ok(typeof (isBigEndian) === 'boolean', - 'missing or invalid endian'); +function toHex (n) { + if (n < 16) return '0' + n.toString(16) + return n.toString(16) +} - assert.ok(offset !== undefined && offset !== null, - 'missing offset'); +function utf8ToBytes (str) { + var byteArray = [] + for (var i = 0; i < str.length; i++) + if (str.charCodeAt(i) <= 0x7F) + byteArray.push(str.charCodeAt(i)) + else { + var h = encodeURIComponent(str.charAt(i)).substr(1).split('%') + for (var j = 0; j < h.length; j++) + byteArray.push(parseInt(h[j], 16)) + } - assert.ok(offset + 3 < buffer.length, - 'Trying to write beyond buffer length'); + return byteArray +} - verifsint(value, 0x7fffffff, -0x80000000); +function asciiToBytes (str) { + var byteArray = [] + for (var i = 0; i < str.length; i++) { + // Node's code seems to be doing this and not & 0x7F.. + byteArray.push(str.charCodeAt(i) & 0xFF) } - if (value >= 0) { - writeUInt32(buffer, value, offset, isBigEndian, noAssert); - } else { - writeUInt32(buffer, 0xffffffff + value + 1, offset, isBigEndian, noAssert); - } + return byteArray } -Buffer.prototype.writeInt32LE = function(value, offset, noAssert) { - writeInt32(this, value, offset, false, noAssert); -}; - -Buffer.prototype.writeInt32BE = function(value, offset, noAssert) { - writeInt32(this, value, offset, true, noAssert); -}; - -function writeFloat(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'); +function base64ToBytes (str) { + return require('base64-js').toByteArray(str) +} - assert.ok(offset + 3 < buffer.length, - 'Trying to write beyond buffer length'); +function blitBuffer (src, dst, offset, length) { + var pos, i = 0 + while (i < length) { + if ((i + offset >= dst.length) || (i >= src.length)) + break - verifIEEE754(value, 3.4028234663852886e+38, -3.4028234663852886e+38); + dst[i + offset] = src[i] + i++ } + return i +} - require('./buffer_ieee754').writeIEEE754(buffer, value, offset, isBigEndian, - 23, 4); +function decodeUtf8Char (str) { + try { + return decodeURIComponent(str) + } catch (err) { + return String.fromCharCode(0xFFFD); // UTF 8 invalid char + } } -Buffer.prototype.writeFloatLE = function(value, offset, noAssert) { - writeFloat(this, value, offset, false, 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') -Buffer.prototype.writeFloatBE = function(value, offset, noAssert) { - writeFloat(this, value, offset, true, noAssert); -}; + assert.ok(value >= 0, + 'specified a negative value for writing an unsigned value') -function writeDouble(buffer, value, offset, isBigEndian, noAssert) { - if (!noAssert) { - assert.ok(value !== undefined && value !== null, - 'missing value'); + assert.ok(value <= max, 'value is larger than maximum value for type') - assert.ok(typeof (isBigEndian) === 'boolean', - 'missing or invalid endian'); + assert.ok(Math.floor(value) === value, 'value has a fractional component') +} - assert.ok(offset !== undefined && offset !== null, - 'missing offset'); +/* + * 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(offset + 7 < buffer.length, - 'Trying to write beyond buffer length'); + assert.ok(value <= max, 'value larger than maximum allowed value') - verifIEEE754(value, 1.7976931348623157E+308, -1.7976931348623157E+308); - } + assert.ok(value >= min, 'value smaller than minimum allowed value') - require('./buffer_ieee754').writeIEEE754(buffer, value, offset, isBigEndian, - 52, 8); + assert.ok(Math.floor(value) === value, 'value has a fractional component') } -Buffer.prototype.writeDoubleLE = function(value, offset, noAssert) { - writeDouble(this, value, offset, false, noAssert); -}; +function verifIEEE754(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') -Buffer.prototype.writeDoubleBE = function(value, offset, noAssert) { - writeDouble(this, value, offset, true, noAssert); -}; + assert.ok(value >= min, 'value smaller than minimum allowed value') +} diff --git a/package.json b/package.json index f8e696a..9bae618 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,7 @@ "email" : "toots@rastageeks.org" }, "scripts" : { - "test" : "tap test/*.js" + "test" : "tape test/*.js" }, "license" : "MIT/X11", "engine" : { "node" : ">=0.6" } diff --git a/test/basic.js b/test/basic.js new file mode 100644 index 0000000..f53e7fc --- /dev/null +++ b/test/basic.js @@ -0,0 +1,64 @@ +var B = require('../index.js').Buffer +var test = require('tape') + +test('new buffer from array', function (t) { + t.plan(1) + t.equal( + new B([1, 2, 3]).toString(), + new Buffer([1, 2, 3]).toString() + ) + t.end() +}) + +test('new buffer from string', function (t) { + t.plan(1) + t.equal( + new B('hey', 'utf8').toString(), + new Buffer('hey', 'utf8').toString() + ) + t.end() +}) + +function arraybufferToString (arraybuffer) { + return String.fromCharCode.apply(null, new Uint16Array(arraybuffer)) +} + +test('buffer toArrayBuffer()', function (t) { + t.plan(1) + var data = [1, 2, 3, 4, 5, 6, 7, 8] + t.equal( + arraybufferToString(new B(data).slice(4).toArrayBuffer()), + arraybufferToString(new Uint8Array(new Uint8Array(data).subarray(4)).buffer) + ) + t.end() +}) + +test('buffer toJSON()', function (t) { + t.plan(1) + var data = [1, 2, 3, 4] + t.deepEqual( + new B(data).toJSON(), + new Buffer(data).toJSON() + ) + t.end() +}) + +test('buffer copy example', function (t) { + t.plan(1) + + buf1 = new B(26) + buf2 = new B(26) + + for (var i = 0 ; i < 26 ; i++) { + buf1[i] = i + 97; // 97 is ASCII a + buf2[i] = 33; // ASCII ! + } + + buf1.copy(buf2, 8, 16, 20) + + t.equal( + buf2.toString('ascii', 0, 25), + '!!!!!!!!qrst!!!!!!!!!!!!!' + ) + t.end() +}) diff --git a/test/buffer.js b/test/buffer.js index 34ca567..0d8ff7b 100644 --- a/test/buffer.js +++ b/test/buffer.js @@ -257,5 +257,5 @@ test('buffer.slice out of range', function (t) { test('base64 strings without padding', function (t) { t.plan(1); t.equal((new B('YW9ldQ', 'base64').toString()), 'aoeu'); - t.end(); + t.end(); });