UNPKG

bytebuffer

Version:

The swiss army knife for binary data in JavaScript.

1,201 lines (1,127 loc) 141 kB
/* Copyright 2013-2014 Daniel Wirtz <dcode@dcode.io> Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ /** * @license ByteBuffer.js (c) 2013-2014 Daniel Wirtz <dcode@dcode.io> * This version of ByteBuffer.js uses a node Buffer (NB) as its backing buffer and is compatible with node.js only. * Released under the Apache License, Version 2.0 * see: https://github.com/dcodeIO/ByteBuffer.js for details */ module.exports = (function() { "use strict"; var buffer = require("buffer"), Buffer = buffer['Buffer'], SlowBuffer = buffer['SlowBuffer'], Long = require("long"), memcpy = null; try { memcpy = require("memcpy"); } catch (e) {} /** * Constructs a new ByteBuffer. * @class The swiss army knife for binary data in JavaScript. * @exports ByteBuffer * @constructor * @param {number=} capacity Initial capacity. Defaults to {@link ByteBuffer.DEFAULT_CAPACITY}. * @param {boolean=} littleEndian Whether to use little or big endian byte order. Defaults to * {@link ByteBuffer.DEFAULT_ENDIAN}. * @param {boolean=} noAssert Whether to skip assertions of offsets and values. Defaults to * {@link ByteBuffer.DEFAULT_NOASSERT}. * @expose */ var ByteBuffer = function(capacity, littleEndian, noAssert) { if (typeof capacity === 'undefined') capacity = ByteBuffer.DEFAULT_CAPACITY; if (typeof littleEndian === 'undefined') littleEndian = ByteBuffer.DEFAULT_ENDIAN; if (typeof noAssert === 'undefined') noAssert = ByteBuffer.DEFAULT_NOASSERT; if (!noAssert) { capacity = capacity | 0; if (capacity < 0) throw new RangeError("Illegal capacity: 0 <= "+capacity); if (typeof littleEndian !== 'boolean') throw new TypeError("Illegal littleEndian: Not a boolean"); if (typeof noAssert !== 'boolean') throw new TypeError("Illegal noAssert: Not a boolean"); } /** * Backing buffer. * @type {!Buffer} * @expose */ this.buffer = capacity === 0 ? EMPTY_BUFFER : new Buffer(capacity); /** * Absolute read/write offset. * @type {number} * @expose * @see ByteBuffer#flip * @see ByteBuffer#clear */ this.offset = 0; /** * Marked offset. * @type {number} * @expose * @see ByteBuffer#mark * @see ByteBuffer#reset */ this.markedOffset = -1; /** * Absolute limit of the contained data. Set to the backing buffer's capacity upon allocation. * @type {number} * @expose * @see ByteBuffer#flip * @see ByteBuffer#clear */ this.limit = capacity; /** * Whether to use little endian byte order, defaults to `false` for big endian. * @type {boolean} * @expose */ this.littleEndian = typeof littleEndian !== 'undefined' ? !!littleEndian : false; /** * Whether to skip assertions of offsets and values, defaults to `false`. * @type {boolean} * @expose */ this.noAssert = !!noAssert; }; /** * ByteBuffer version. * @type {string} * @const * @expose */ ByteBuffer.VERSION = "3.2.3"; /** * Little endian constant that can be used instead of its boolean value. Evaluates to `true`. * @type {boolean} * @const * @expose */ ByteBuffer.LITTLE_ENDIAN = true; /** * Big endian constant that can be used instead of its boolean value. Evaluates to `false`. * @type {boolean} * @const * @expose */ ByteBuffer.BIG_ENDIAN = false; /** * Default initial capacity of `16`. * @type {number} * @expose */ ByteBuffer.DEFAULT_CAPACITY = 16; /** * Default endianess of `false` for big endian. * @type {boolean} * @expose */ ByteBuffer.DEFAULT_ENDIAN = ByteBuffer.BIG_ENDIAN; /** * Default no assertions flag of `false`. * @type {boolean} * @expose */ ByteBuffer.DEFAULT_NOASSERT = false; /** * A `Long` class for representing a 64-bit two's-complement integer value. * @type {!Long} * @const * @see https://npmjs.org/package/long * @expose */ ByteBuffer.Long = Long; // helpers /** * @type {!Buffer} * @inner */ var EMPTY_BUFFER = new Buffer(0); /** * Allocates a new ByteBuffer backed by a buffer of the specified capacity. * @param {number=} capacity Initial capacity. Defaults to {@link ByteBuffer.DEFAULT_CAPACITY}. * @param {boolean=} littleEndian Whether to use little or big endian byte order. Defaults to * {@link ByteBuffer.DEFAULT_ENDIAN}. * @param {boolean=} noAssert Whether to skip assertions of offsets and values. Defaults to * {@link ByteBuffer.DEFAULT_NOASSERT}. * @returns {!ByteBuffer} * @expose */ ByteBuffer.allocate = function(capacity, littleEndian, noAssert) { return new ByteBuffer(capacity, littleEndian, noAssert); }; /** * Concatenates multiple ByteBuffers into one. * @param {!Array.<!ByteBuffer|!Buffer|!ArrayBuffer|!Uint8Array|string>} buffers Buffers to concatenate * @param {(string|boolean)=} encoding String encoding if `buffers` contains a string ("base64", "hex", "binary", * defaults to "utf8") * @param {boolean=} littleEndian Whether to use little or big endian byte order for the resulting ByteBuffer. Defaults * to {@link ByteBuffer.DEFAULT_ENDIAN}. * @param {boolean=} noAssert Whether to skip assertions of offsets and values for the resulting ByteBuffer. Defaults to * {@link ByteBuffer.DEFAULT_NOASSERT}. * @returns {!ByteBuffer} Concatenated ByteBuffer * @expose */ ByteBuffer.concat = function(buffers, encoding, littleEndian, noAssert) { if (typeof encoding === 'boolean' || typeof encoding !== 'string') { noAssert = littleEndian; littleEndian = encoding; encoding = undefined; } var capacity = 0; for (var i=0, k=buffers.length, length; i<k; ++i) { if (!ByteBuffer.isByteBuffer(buffers[i])) buffers[i] = ByteBuffer.wrap(buffers[i], encoding); length = buffers[i].limit - buffers[i].offset; if (length > 0) capacity += length; } if (capacity === 0) return new ByteBuffer(0, littleEndian, noAssert); var bb = new ByteBuffer(capacity, littleEndian, noAssert), bi; i=0; while (i<k) { bi = buffers[i++]; length = bi.limit - bi.offset; if (length <= 0) continue; bi.buffer.copy(bb.buffer, bb.offset, bi.offset, bi.limit); bb.offset += length; } bb.limit = bb.offset; bb.offset = 0; return bb; }; /** * Tests if the specified type is a ByteBuffer. * @param {*} bb ByteBuffer to test * @returns {boolean} `true` if it is a ByteBuffer, otherwise `false` * @expose */ ByteBuffer.isByteBuffer = function(bb) { return bb && bb instanceof ByteBuffer; }; /** * Gets the backing buffer type. * @returns {Function} `Buffer` for NB builds, `ArrayBuffer` for AB builds (classes) * @expose */ ByteBuffer.type = function() { return Buffer; }; /** * Wraps a buffer or a string. Sets the allocated ByteBuffer's {@link ByteBuffer#offset} to `0` and its * {@link ByteBuffer#limit} to the length of the wrapped data. * @param {!ByteBuffer|!Buffer|!ArrayBuffer|!Uint8Array|string|!Array.<number>} buffer Anything that can be wrapped * @param {(string|boolean)=} encoding String encoding if `buffer` is a string ("base64", "hex", "binary", defaults to * "utf8") * @param {boolean=} littleEndian Whether to use little or big endian byte order. Defaults to * {@link ByteBuffer.DEFAULT_ENDIAN}. * @param {boolean=} noAssert Whether to skip assertions of offsets and values. Defaults to * {@link ByteBuffer.DEFAULT_NOASSERT}. * @returns {!ByteBuffer} A ByteBuffer wrapping `buffer` * @expose */ ByteBuffer.wrap = function(buffer, encoding, littleEndian, noAssert) { if (typeof encoding !== 'string') { noAssert = littleEndian; littleEndian = encoding; encoding = undefined; } if (typeof buffer === 'string') { if (typeof encoding === 'undefined') encoding = "utf8"; switch (encoding) { case "base64": return ByteBuffer.fromBase64(buffer, littleEndian); case "hex": return ByteBuffer.fromHex(buffer, littleEndian); case "binary": return ByteBuffer.fromBinary(buffer, littleEndian); case "utf8": return ByteBuffer.fromUTF8(buffer, littleEndian); case "debug": return ByteBuffer.fromDebug(buffer, littleEndian); default: throw new TypeError("Unsupported encoding: "+encoding); } } if (buffer === null || typeof buffer !== 'object') throw new TypeError("Illegal buffer: null or non-object"); var bb; if (ByteBuffer.isByteBuffer(buffer)) { bb = ByteBuffer.prototype.clone.call(buffer); bb.markedOffset = -1; return bb; } var i = 0, k = 0, b; if (buffer instanceof Uint8Array) { // Extract bytes from Uint8Array b = new Buffer(buffer.length); if (memcpy) { // Fast memcpy(b, 0, buffer.buffer, buffer.byteOffset, buffer.byteOffset + buffer.length); } else { // Slow for (i=0, k=buffer.length; i<k; ++i) b[i] = buffer[i]; } buffer = b; } else if (buffer instanceof ArrayBuffer) { // Convert ArrayBuffer to Buffer b = new Buffer(buffer.byteLength); if (memcpy) { // Fast memcpy(b, 0, buffer, 0, buffer.byteLength); } else { // Slow buffer = new Uint8Array(buffer); for (i=0, k=buffer.length; i<k; ++i) { b[i] = buffer[i]; } } buffer = b; } else if (!(buffer instanceof Buffer)) { // Create from octets if it is an error, otherwise fail if (Object.prototype.toString.call(buffer) !== "[object Array]") throw new TypeError("Illegal buffer"); buffer = new Buffer(buffer); } bb = new ByteBuffer(0, littleEndian, noAssert); if (buffer.length > 0) { // Avoid references to more than one EMPTY_BUFFER bb.buffer = buffer; bb.limit = buffer.length; } return bb; }; // types/ints/int8 /** * Writes an 8bit signed integer. * @param {number} value Value to write * @param {number=} offset Offset to write to. Will use and advance {@link ByteBuffer#offset} by `1` if omitted. * @returns {!ByteBuffer} this * @expose */ ByteBuffer.prototype.writeInt8 = function(value, offset) { var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; if (!this.noAssert) { if (typeof value !== 'number' || value % 1 !== 0) throw new TypeError("Illegal value: "+value+" (not an integer)"); value |= 0; if (typeof offset !== 'number' || offset % 1 !== 0) throw new TypeError("Illegal offset: "+offset+" (not an integer)"); offset >>>= 0; if (offset < 0 || offset + 0 > this.buffer.length) throw new RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.length); } offset += 1; var capacity0 = this.buffer.length; if (offset > capacity0) this.resize((capacity0 *= 2) > offset ? capacity0 : offset); offset -= 1; this.buffer[offset] = value; if (relative) this.offset += 1; return this; }; /** * Writes an 8bit signed integer. This is an alias of {@link ByteBuffer#writeInt8}. * @function * @param {number} value Value to write * @param {number=} offset Offset to write to. Will use and advance {@link ByteBuffer#offset} by `1` if omitted. * @returns {!ByteBuffer} this * @expose */ ByteBuffer.prototype.writeByte = ByteBuffer.prototype.writeInt8; /** * Reads an 8bit signed integer. * @param {number=} offset Offset to read from. Will use and advance {@link ByteBuffer#offset} by `1` if omitted. * @returns {number} Value read * @expose */ ByteBuffer.prototype.readInt8 = function(offset) { var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; if (!this.noAssert) { if (typeof offset !== 'number' || offset % 1 !== 0) throw new TypeError("Illegal offset: "+offset+" (not an integer)"); offset >>>= 0; if (offset < 0 || offset + 1 > this.buffer.length) throw new RangeError("Illegal offset: 0 <= "+offset+" (+"+1+") <= "+this.buffer.length); } var value = this.buffer[offset]; if ((value & 0x80) === 0x80) value = -(0xFF - value + 1); // Cast to signed if (relative) this.offset += 1; return value; }; /** * Reads an 8bit signed integer. This is an alias of {@link ByteBuffer#readInt8}. * @function * @param {number=} offset Offset to read from. Will use and advance {@link ByteBuffer#offset} by `1` if omitted. * @returns {number} Value read * @expose */ ByteBuffer.prototype.readByte = ByteBuffer.prototype.readInt8; /** * Writes an 8bit unsigned integer. * @param {number} value Value to write * @param {number=} offset Offset to write to. Will use and advance {@link ByteBuffer#offset} by `1` if omitted. * @returns {!ByteBuffer} this * @expose */ ByteBuffer.prototype.writeUint8 = function(value, offset) { var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; if (!this.noAssert) { if (typeof value !== 'number' || value % 1 !== 0) throw new TypeError("Illegal value: "+value+" (not an integer)"); value >>>= 0; if (typeof offset !== 'number' || offset % 1 !== 0) throw new TypeError("Illegal offset: "+offset+" (not an integer)"); offset >>>= 0; if (offset < 0 || offset + 0 > this.buffer.length) throw new RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.length); } offset += 1; var capacity1 = this.buffer.length; if (offset > capacity1) this.resize((capacity1 *= 2) > offset ? capacity1 : offset); offset -= 1; this.buffer[offset] = value; if (relative) this.offset += 1; return this; }; /** * Reads an 8bit unsigned integer. * @param {number=} offset Offset to read from. Will use and advance {@link ByteBuffer#offset} by `1` if omitted. * @returns {number} Value read * @expose */ ByteBuffer.prototype.readUint8 = function(offset) { var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; if (!this.noAssert) { if (typeof offset !== 'number' || offset % 1 !== 0) throw new TypeError("Illegal offset: "+offset+" (not an integer)"); offset >>>= 0; if (offset < 0 || offset + 1 > this.buffer.length) throw new RangeError("Illegal offset: 0 <= "+offset+" (+"+1+") <= "+this.buffer.length); } var value = this.buffer[offset]; if (relative) this.offset += 1; return value; }; // types/ints/int16 /** * Writes a 16bit signed integer. * @param {number} value Value to write * @param {number=} offset Offset to write to. Will use and advance {@link ByteBuffer#offset} by `2` if omitted. * @throws {TypeError} If `offset` or `value` is not a valid number * @throws {RangeError} If `offset` is out of bounds * @expose */ ByteBuffer.prototype.writeInt16 = function(value, offset) { var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; if (!this.noAssert) { if (typeof value !== 'number' || value % 1 !== 0) throw new TypeError("Illegal value: "+value+" (not an integer)"); value |= 0; if (typeof offset !== 'number' || offset % 1 !== 0) throw new TypeError("Illegal offset: "+offset+" (not an integer)"); offset >>>= 0; if (offset < 0 || offset + 0 > this.buffer.length) throw new RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.length); } offset += 2; var capacity2 = this.buffer.length; if (offset > capacity2) this.resize((capacity2 *= 2) > offset ? capacity2 : offset); offset -= 2; if (this.littleEndian) { this.buffer[offset+1] = (value & 0xFF00) >>> 8; this.buffer[offset ] = value & 0x00FF; } else { this.buffer[offset] = (value & 0xFF00) >>> 8; this.buffer[offset+1] = value & 0x00FF; } if (relative) this.offset += 2; return this; }; /** * Writes a 16bit signed integer. This is an alias of {@link ByteBuffer#writeInt16}. * @function * @param {number} value Value to write * @param {number=} offset Offset to write to. Will use and advance {@link ByteBuffer#offset} by `2` if omitted. * @throws {TypeError} If `offset` or `value` is not a valid number * @throws {RangeError} If `offset` is out of bounds * @expose */ ByteBuffer.prototype.writeShort = ByteBuffer.prototype.writeInt16; /** * Reads a 16bit signed integer. * @param {number=} offset Offset to read from. Will use and advance {@link ByteBuffer#offset} by `2` if omitted. * @returns {number} Value read * @throws {TypeError} If `offset` is not a valid number * @throws {RangeError} If `offset` is out of bounds * @expose */ ByteBuffer.prototype.readInt16 = function(offset) { var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; if (!this.noAssert) { if (typeof offset !== 'number' || offset % 1 !== 0) throw new TypeError("Illegal offset: "+offset+" (not an integer)"); offset >>>= 0; if (offset < 0 || offset + 2 > this.buffer.length) throw new RangeError("Illegal offset: 0 <= "+offset+" (+"+2+") <= "+this.buffer.length); } var value = 0; if (this.littleEndian) { value = this.buffer[offset ]; value |= this.buffer[offset+1] << 8; } else { value = this.buffer[offset ] << 8; value |= this.buffer[offset+1]; } if ((value & 0x8000) === 0x8000) value = -(0xFFFF - value + 1); // Cast to signed if (relative) this.offset += 2; return value; }; /** * Reads a 16bit signed integer. This is an alias of {@link ByteBuffer#readInt16}. * @function * @param {number=} offset Offset to read from. Will use and advance {@link ByteBuffer#offset} by `2` if omitted. * @returns {number} Value read * @throws {TypeError} If `offset` is not a valid number * @throws {RangeError} If `offset` is out of bounds * @expose */ ByteBuffer.prototype.readShort = ByteBuffer.prototype.readInt16; /** * Writes a 16bit unsigned integer. * @param {number} value Value to write * @param {number=} offset Offset to write to. Will use and advance {@link ByteBuffer#offset} by `2` if omitted. * @throws {TypeError} If `offset` or `value` is not a valid number * @throws {RangeError} If `offset` is out of bounds * @expose */ ByteBuffer.prototype.writeUint16 = function(value, offset) { var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; if (!this.noAssert) { if (typeof value !== 'number' || value % 1 !== 0) throw new TypeError("Illegal value: "+value+" (not an integer)"); value >>>= 0; if (typeof offset !== 'number' || offset % 1 !== 0) throw new TypeError("Illegal offset: "+offset+" (not an integer)"); offset >>>= 0; if (offset < 0 || offset + 0 > this.buffer.length) throw new RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.length); } offset += 2; var capacity3 = this.buffer.length; if (offset > capacity3) this.resize((capacity3 *= 2) > offset ? capacity3 : offset); offset -= 2; if (this.littleEndian) { this.buffer[offset+1] = (value & 0xFF00) >>> 8; this.buffer[offset ] = value & 0x00FF; } else { this.buffer[offset] = (value & 0xFF00) >>> 8; this.buffer[offset+1] = value & 0x00FF; } if (relative) this.offset += 2; return this; }; /** * Reads a 16bit unsigned integer. * @param {number=} offset Offset to read from. Will use and advance {@link ByteBuffer#offset} by `2` if omitted. * @returns {number} Value read * @throws {TypeError} If `offset` is not a valid number * @throws {RangeError} If `offset` is out of bounds * @expose */ ByteBuffer.prototype.readUint16 = function(offset) { var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; if (!this.noAssert) { if (typeof offset !== 'number' || offset % 1 !== 0) throw new TypeError("Illegal offset: "+offset+" (not an integer)"); offset >>>= 0; if (offset < 0 || offset + 2 > this.buffer.length) throw new RangeError("Illegal offset: 0 <= "+offset+" (+"+2+") <= "+this.buffer.length); } var value = 0; if (this.littleEndian) { value = this.buffer[offset ]; value |= this.buffer[offset+1] << 8; } else { value = this.buffer[offset ] << 8; value |= this.buffer[offset+1]; } if (relative) this.offset += 2; return value; }; // types/ints/int32 /** * Writes a 32bit signed integer. * @param {number} value Value to write * @param {number=} offset Offset to write to. Will use and increase {@link ByteBuffer#offset} by `4` if omitted. * @expose */ ByteBuffer.prototype.writeInt32 = function(value, offset) { var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; if (!this.noAssert) { if (typeof value !== 'number' || value % 1 !== 0) throw new TypeError("Illegal value: "+value+" (not an integer)"); value |= 0; if (typeof offset !== 'number' || offset % 1 !== 0) throw new TypeError("Illegal offset: "+offset+" (not an integer)"); offset >>>= 0; if (offset < 0 || offset + 0 > this.buffer.length) throw new RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.length); } offset += 4; var capacity4 = this.buffer.length; if (offset > capacity4) this.resize((capacity4 *= 2) > offset ? capacity4 : offset); offset -= 4; if (this.littleEndian) { this.buffer[offset+3] = (value >>> 24) & 0xFF; this.buffer[offset+2] = (value >>> 16) & 0xFF; this.buffer[offset+1] = (value >>> 8) & 0xFF; this.buffer[offset ] = value & 0xFF; } else { this.buffer[offset ] = (value >>> 24) & 0xFF; this.buffer[offset+1] = (value >>> 16) & 0xFF; this.buffer[offset+2] = (value >>> 8) & 0xFF; this.buffer[offset+3] = value & 0xFF; } if (relative) this.offset += 4; return this; }; /** * Writes a 32bit signed integer. This is an alias of {@link ByteBuffer#writeInt32}. * @param {number} value Value to write * @param {number=} offset Offset to write to. Will use and increase {@link ByteBuffer#offset} by `4` if omitted. * @expose */ ByteBuffer.prototype.writeInt = ByteBuffer.prototype.writeInt32; /** * Reads a 32bit signed integer. * @param {number=} offset Offset to read from. Will use and increase {@link ByteBuffer#offset} by `4` if omitted. * @returns {number} Value read * @expose */ ByteBuffer.prototype.readInt32 = function(offset) { var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; if (!this.noAssert) { if (typeof offset !== 'number' || offset % 1 !== 0) throw new TypeError("Illegal offset: "+offset+" (not an integer)"); offset >>>= 0; if (offset < 0 || offset + 4 > this.buffer.length) throw new RangeError("Illegal offset: 0 <= "+offset+" (+"+4+") <= "+this.buffer.length); } var value = 0; if (this.littleEndian) { value = this.buffer[offset+2] << 16; value |= this.buffer[offset+1] << 8; value |= this.buffer[offset ]; value += this.buffer[offset+3] << 24 >>> 0; } else { value = this.buffer[offset+1] << 16; value |= this.buffer[offset+2] << 8; value |= this.buffer[offset+3]; value += this.buffer[offset ] << 24 >>> 0; } value |= 0; // Cast to signed if (relative) this.offset += 4; return value; }; /** * Reads a 32bit signed integer. This is an alias of {@link ByteBuffer#readInt32}. * @param {number=} offset Offset to read from. Will use and advance {@link ByteBuffer#offset} by `4` if omitted. * @returns {number} Value read * @expose */ ByteBuffer.prototype.readInt = ByteBuffer.prototype.readInt32; /** * Writes a 32bit unsigned integer. * @param {number} value Value to write * @param {number=} offset Offset to write to. Will use and increase {@link ByteBuffer#offset} by `4` if omitted. * @expose */ ByteBuffer.prototype.writeUint32 = function(value, offset) { var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; if (!this.noAssert) { if (typeof value !== 'number' || value % 1 !== 0) throw new TypeError("Illegal value: "+value+" (not an integer)"); value >>>= 0; if (typeof offset !== 'number' || offset % 1 !== 0) throw new TypeError("Illegal offset: "+offset+" (not an integer)"); offset >>>= 0; if (offset < 0 || offset + 0 > this.buffer.length) throw new RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.length); } offset += 4; var capacity5 = this.buffer.length; if (offset > capacity5) this.resize((capacity5 *= 2) > offset ? capacity5 : offset); offset -= 4; if (this.littleEndian) { this.buffer[offset+3] = (value >>> 24) & 0xFF; this.buffer[offset+2] = (value >>> 16) & 0xFF; this.buffer[offset+1] = (value >>> 8) & 0xFF; this.buffer[offset ] = value & 0xFF; } else { this.buffer[offset ] = (value >>> 24) & 0xFF; this.buffer[offset+1] = (value >>> 16) & 0xFF; this.buffer[offset+2] = (value >>> 8) & 0xFF; this.buffer[offset+3] = value & 0xFF; } if (relative) this.offset += 4; return this; }; /** * Reads a 32bit unsigned integer. * @param {number=} offset Offset to read from. Will use and increase {@link ByteBuffer#offset} by `4` if omitted. * @returns {number} Value read * @expose */ ByteBuffer.prototype.readUint32 = function(offset) { var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; if (!this.noAssert) { if (typeof offset !== 'number' || offset % 1 !== 0) throw new TypeError("Illegal offset: "+offset+" (not an integer)"); offset >>>= 0; if (offset < 0 || offset + 4 > this.buffer.length) throw new RangeError("Illegal offset: 0 <= "+offset+" (+"+4+") <= "+this.buffer.length); } var value = 0; if (this.littleEndian) { value = this.buffer[offset+2] << 16; value |= this.buffer[offset+1] << 8; value |= this.buffer[offset ]; value += this.buffer[offset+3] << 24 >>> 0; } else { value = this.buffer[offset+1] << 16; value |= this.buffer[offset+2] << 8; value |= this.buffer[offset+3]; value += this.buffer[offset ] << 24 >>> 0; } if (relative) this.offset += 4; return value; }; // types/ints/int64 if (Long) { /** * Writes a 64bit signed integer. * @param {number|!Long} value Value to write * @param {number=} offset Offset to write to. Will use and increase {@link ByteBuffer#offset} by `8` if omitted. * @returns {!ByteBuffer} this * @expose */ ByteBuffer.prototype.writeInt64 = function(value, offset) { var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; if (!this.noAssert) { if (typeof value === 'number') value = Long.fromNumber(value); else if (!(value && value instanceof Long)) throw new TypeError("Illegal value: "+value+" (not an integer or Long)"); if (typeof offset !== 'number' || offset % 1 !== 0) throw new TypeError("Illegal offset: "+offset+" (not an integer)"); offset >>>= 0; if (offset < 0 || offset + 0 > this.buffer.length) throw new RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.length); } if (typeof value === 'number') value = Long.fromNumber(value); offset += 8; var capacity6 = this.buffer.length; if (offset > capacity6) this.resize((capacity6 *= 2) > offset ? capacity6 : offset); offset -= 8; var lo = value.low, hi = value.high; if (this.littleEndian) { this.buffer[offset+3] = (lo >>> 24) & 0xFF; this.buffer[offset+2] = (lo >>> 16) & 0xFF; this.buffer[offset+1] = (lo >>> 8) & 0xFF; this.buffer[offset ] = lo & 0xFF; offset += 4; this.buffer[offset+3] = (hi >>> 24) & 0xFF; this.buffer[offset+2] = (hi >>> 16) & 0xFF; this.buffer[offset+1] = (hi >>> 8) & 0xFF; this.buffer[offset ] = hi & 0xFF; } else { this.buffer[offset ] = (hi >>> 24) & 0xFF; this.buffer[offset+1] = (hi >>> 16) & 0xFF; this.buffer[offset+2] = (hi >>> 8) & 0xFF; this.buffer[offset+3] = hi & 0xFF; offset += 4; this.buffer[offset ] = (lo >>> 24) & 0xFF; this.buffer[offset+1] = (lo >>> 16) & 0xFF; this.buffer[offset+2] = (lo >>> 8) & 0xFF; this.buffer[offset+3] = lo & 0xFF; } if (relative) this.offset += 8; return this; }; /** * Writes a 64bit signed integer. This is an alias of {@link ByteBuffer#writeInt64}. * @param {number|!Long} value Value to write * @param {number=} offset Offset to write to. Will use and increase {@link ByteBuffer#offset} by `8` if omitted. * @returns {!ByteBuffer} this * @expose */ ByteBuffer.prototype.writeLong = ByteBuffer.prototype.writeInt64; /** * Reads a 64bit signed integer. * @param {number=} offset Offset to read from. Will use and increase {@link ByteBuffer#offset} by `8` if omitted. * @returns {!Long} * @expose */ ByteBuffer.prototype.readInt64 = function(offset) { var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; if (!this.noAssert) { if (typeof offset !== 'number' || offset % 1 !== 0) throw new TypeError("Illegal offset: "+offset+" (not an integer)"); offset >>>= 0; if (offset < 0 || offset + 8 > this.buffer.length) throw new RangeError("Illegal offset: 0 <= "+offset+" (+"+8+") <= "+this.buffer.length); } var lo = 0, hi = 0; if (this.littleEndian) { lo = this.buffer[offset+2] << 16; lo |= this.buffer[offset+1] << 8; lo |= this.buffer[offset ]; lo += this.buffer[offset+3] << 24 >>> 0; offset += 4; hi = this.buffer[offset+2] << 16; hi |= this.buffer[offset+1] << 8; hi |= this.buffer[offset ]; hi += this.buffer[offset+3] << 24 >>> 0; } else { hi = this.buffer[offset+1] << 16; hi |= this.buffer[offset+2] << 8; hi |= this.buffer[offset+3]; hi += this.buffer[offset ] << 24 >>> 0; offset += 4; lo = this.buffer[offset+1] << 16; lo |= this.buffer[offset+2] << 8; lo |= this.buffer[offset+3]; lo += this.buffer[offset ] << 24 >>> 0; } var value = new Long(lo, hi, false); if (relative) this.offset += 8; return value; }; /** * Reads a 64bit signed integer. This is an alias of {@link ByteBuffer#readInt64}. * @param {number=} offset Offset to read from. Will use and increase {@link ByteBuffer#offset} by `8` if omitted. * @returns {!Long} * @expose */ ByteBuffer.prototype.readLong = ByteBuffer.prototype.readInt64; /** * Writes a 64bit unsigned integer. * @param {number|!Long} value Value to write * @param {number=} offset Offset to write to. Will use and increase {@link ByteBuffer#offset} by `8` if omitted. * @returns {!ByteBuffer} this * @expose */ ByteBuffer.prototype.writeUint64 = function(value, offset) { var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; if (!this.noAssert) { if (typeof value === 'number') value = Long.fromNumber(value); else if (!(value && value instanceof Long)) throw new TypeError("Illegal value: "+value+" (not an integer or Long)"); if (typeof offset !== 'number' || offset % 1 !== 0) throw new TypeError("Illegal offset: "+offset+" (not an integer)"); offset >>>= 0; if (offset < 0 || offset + 0 > this.buffer.length) throw new RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.length); } if (typeof value === 'number') value = Long.fromNumber(value); offset += 8; var capacity7 = this.buffer.length; if (offset > capacity7) this.resize((capacity7 *= 2) > offset ? capacity7 : offset); offset -= 8; var lo = value.low, hi = value.high; if (this.littleEndian) { this.buffer[offset+3] = (lo >>> 24) & 0xFF; this.buffer[offset+2] = (lo >>> 16) & 0xFF; this.buffer[offset+1] = (lo >>> 8) & 0xFF; this.buffer[offset ] = lo & 0xFF; offset += 4; this.buffer[offset+3] = (hi >>> 24) & 0xFF; this.buffer[offset+2] = (hi >>> 16) & 0xFF; this.buffer[offset+1] = (hi >>> 8) & 0xFF; this.buffer[offset ] = hi & 0xFF; } else { this.buffer[offset ] = (hi >>> 24) & 0xFF; this.buffer[offset+1] = (hi >>> 16) & 0xFF; this.buffer[offset+2] = (hi >>> 8) & 0xFF; this.buffer[offset+3] = hi & 0xFF; offset += 4; this.buffer[offset ] = (lo >>> 24) & 0xFF; this.buffer[offset+1] = (lo >>> 16) & 0xFF; this.buffer[offset+2] = (lo >>> 8) & 0xFF; this.buffer[offset+3] = lo & 0xFF; } if (relative) this.offset += 8; return this; }; /** * Reads a 64bit unsigned integer. * @param {number=} offset Offset to read from. Will use and increase {@link ByteBuffer#offset} by `8` if omitted. * @returns {!Long} * @expose */ ByteBuffer.prototype.readUint64 = function(offset) { var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; if (!this.noAssert) { if (typeof offset !== 'number' || offset % 1 !== 0) throw new TypeError("Illegal offset: "+offset+" (not an integer)"); offset >>>= 0; if (offset < 0 || offset + 8 > this.buffer.length) throw new RangeError("Illegal offset: 0 <= "+offset+" (+"+8+") <= "+this.buffer.length); } var lo = 0, hi = 0; if (this.littleEndian) { lo = this.buffer[offset+2] << 16; lo |= this.buffer[offset+1] << 8; lo |= this.buffer[offset ]; lo += this.buffer[offset+3] << 24 >>> 0; offset += 4; hi = this.buffer[offset+2] << 16; hi |= this.buffer[offset+1] << 8; hi |= this.buffer[offset ]; hi += this.buffer[offset+3] << 24 >>> 0; } else { hi = this.buffer[offset+1] << 16; hi |= this.buffer[offset+2] << 8; hi |= this.buffer[offset+3]; hi += this.buffer[offset ] << 24 >>> 0; offset += 4; lo = this.buffer[offset+1] << 16; lo |= this.buffer[offset+2] << 8; lo |= this.buffer[offset+3]; lo += this.buffer[offset ] << 24 >>> 0; } var value = new Long(lo, hi, true); if (relative) this.offset += 8; return value; }; } // Long // types/floats/float32 /** * Writes a 32bit float. * @param {number} value Value to write * @param {number=} offset Offset to write to. Will use and increase {@link ByteBuffer#offset} by `4` if omitted. * @returns {!ByteBuffer} this * @expose */ ByteBuffer.prototype.writeFloat32 = function(value, offset) { var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; if (!this.noAssert) { if (typeof value !== 'number') throw new TypeError("Illegal value: "+value+" (not a number)"); if (typeof offset !== 'number' || offset % 1 !== 0) throw new TypeError("Illegal offset: "+offset+" (not an integer)"); offset >>>= 0; if (offset < 0 || offset + 0 > this.buffer.length) throw new RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.length); } offset += 4; var capacity8 = this.buffer.length; if (offset > capacity8) this.resize((capacity8 *= 2) > offset ? capacity8 : offset); offset -= 4; this.littleEndian ? this.buffer.writeFloatLE(value, offset, true) : this.buffer.writeFloatBE(value, offset, true); if (relative) this.offset += 4; return this; }; /** * Writes a 32bit float. This is an alias of {@link ByteBuffer#writeFloat32}. * @function * @param {number} value Value to write * @param {number=} offset Offset to write to. Will use and increase {@link ByteBuffer#offset} by `4` if omitted. * @returns {!ByteBuffer} this * @expose */ ByteBuffer.prototype.writeFloat = ByteBuffer.prototype.writeFloat32; /** * Reads a 32bit float. * @param {number=} offset Offset to read from. Will use and increase {@link ByteBuffer#offset} by `4` if omitted. * @returns {number} * @expose */ ByteBuffer.prototype.readFloat32 = function(offset) { var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; if (!this.noAssert) { if (typeof offset !== 'number' || offset % 1 !== 0) throw new TypeError("Illegal offset: "+offset+" (not an integer)"); offset >>>= 0; if (offset < 0 || offset + 4 > this.buffer.length) throw new RangeError("Illegal offset: 0 <= "+offset+" (+"+4+") <= "+this.buffer.length); } var value = this.littleEndian ? this.buffer.readFloatLE(offset, true) : this.buffer.readFloatBE(offset, true); if (relative) this.offset += 4; return value; }; /** * Reads a 32bit float. This is an alias of {@link ByteBuffer#readFloat32}. * @function * @param {number=} offset Offset to read from. Will use and increase {@link ByteBuffer#offset} by `4` if omitted. * @returns {number} * @expose */ ByteBuffer.prototype.readFloat = ByteBuffer.prototype.readFloat32; // types/floats/float64 /** * Writes a 64bit float. * @param {number} value Value to write * @param {number=} offset Offset to write to. Will use and increase {@link ByteBuffer#offset} by `8` if omitted. * @returns {!ByteBuffer} this * @expose */ ByteBuffer.prototype.writeFloat64 = function(value, offset) { var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; if (!this.noAssert) { if (typeof value !== 'number') throw new TypeError("Illegal value: "+value+" (not a number)"); if (typeof offset !== 'number' || offset % 1 !== 0) throw new TypeError("Illegal offset: "+offset+" (not an integer)"); offset >>>= 0; if (offset < 0 || offset + 0 > this.buffer.length) throw new RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.length); } offset += 8; var capacity9 = this.buffer.length; if (offset > capacity9) this.resize((capacity9 *= 2) > offset ? capacity9 : offset); offset -= 8; this.littleEndian ? this.buffer.writeDoubleLE(value, offset, true) : this.buffer.writeDoubleBE(value, offset, true); if (relative) this.offset += 8; return this; }; /** * Writes a 64bit float. This is an alias of {@link ByteBuffer#writeFloat64}. * @function * @param {number} value Value to write * @param {number=} offset Offset to write to. Will use and increase {@link ByteBuffer#offset} by `8` if omitted. * @returns {!ByteBuffer} this * @expose */ ByteBuffer.prototype.writeDouble = ByteBuffer.prototype.writeFloat64; /** * Reads a 64bit float. * @param {number=} offset Offset to read from. Will use and increase {@link ByteBuffer#offset} by `8` if omitted. * @returns {number} * @expose */ ByteBuffer.prototype.readFloat64 = function(offset) { var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; if (!this.noAssert) { if (typeof offset !== 'number' || offset % 1 !== 0) throw new TypeError("Illegal offset: "+offset+" (not an integer)"); offset >>>= 0; if (offset < 0 || offset + 8 > this.buffer.length) throw new RangeError("Illegal offset: 0 <= "+offset+" (+"+8+") <= "+this.buffer.length); } var value = this.littleEndian ? this.buffer.readDoubleLE(offset, true) : this.buffer.readDoubleBE(offset, true); if (relative) this.offset += 8; return value; }; /** * Reads a 64bit float. This is an alias of {@link ByteBuffer#readFloat64}. * @function * @param {number=} offset Offset to read from. Will use and increase {@link ByteBuffer#offset} by `8` if omitted. * @returns {number} * @expose */ ByteBuffer.prototype.readDouble = ByteBuffer.prototype.readFloat64; // types/varints/varint32 /** * Maximum number of bytes required to store a 32bit base 128 variable-length integer. * @type {number} * @const * @expose */ ByteBuffer.MAX_VARINT32_BYTES = 5; /** * Calculates the actual number of bytes required to store a 32bit base 128 variable-length integer. * @param {number} value Value to encode * @returns {number} Number of bytes required. Capped to {@link ByteBuffer.MAX_VARINT32_BYTES} * @expose */ ByteBuffer.calculateVarint32 = function(value) { // ref: src/google/protobuf/io/coded_stream.cc value = value >>> 0; if (value < 1 << 7 ) return 1; else if (value < 1 << 14) return 2; else if (value < 1 << 21) return 3; else if (value < 1 << 28) return 4; else return 5; }; /** * Zigzag encodes a signed 32bit integer so that it can be effectively used with varint encoding. * @param {number} n Signed 32bit integer * @returns {number} Unsigned zigzag encoded 32bit integer * @expose */ ByteBuffer.zigZagEncode32 = function(n) { return (((n |= 0) << 1) ^ (n >> 31)) >>> 0; // ref: src/google/protobuf/wire_format_lite.h }; /** * Decodes a zigzag encoded signed 32bit integer. * @param {number} n Unsigned zigzag encoded 32bit integer * @returns {number} Signed 32bit integer * @expose */ ByteBuffer.zigZagDecode32 = function(n) { return ((n >>> 1) ^ -(n & 1)) | 0; // // ref: src/google/protobuf/wire_format_lite.h }; /** * Writes a 32bit base 128 variable-length integer. * @param {number} value Value to write * @param {number=} offset Offset to write to. Will use and increase {@link ByteBuffer#offset} by the number of bytes * written if omitted. * @returns {!ByteBuffer|number} this if `offset` is omitted, else the actual number of bytes written * @expose */ ByteBuffer.prototype.writeVarint32 = function(value, offset) { var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; if (!this.noAssert) { if (typeof value !== 'number' || value % 1 !== 0) throw new TypeError("Illegal value: "+value+" (not an integer)"); value |= 0; if (typeof offset !== 'number' || offset % 1 !== 0) throw new TypeError("Illegal offset: "+offset+" (not an i