UNPKG

bytebuffer

Version:

The swiss army knife for binary data in JavaScript.

206 lines (197 loc) 7.01 kB
//? if (VARINT32) { // 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 */ ByteBufferPrototype.writeVarint32 = function(value, offset) { //? RELATIVE(); if (!this.noAssert) { //? ASSERT_INTEGER('value'); //? ASSERT_OFFSET(); } var size = ByteBuffer.calculateVarint32(value), b; //? ENSURE_CAPACITY('size'); // ref: http://code.google.com/searchframe#WTeibokF6gE/trunk/src/google/protobuf/io/coded_stream.cc //? if (NODE) this.buffer[offset] = b = value | 0x80; //? else this.view.setUint8(offset, b = value | 0x80); value >>>= 0; if (value >= 1 << 7) { b = (value >> 7) | 0x80; //? if (NODE) this.buffer[offset+1] = b; //? else this.view.setUint8(offset+1, b); if (value >= 1 << 14) { b = (value >> 14) | 0x80; //? if (NODE) this.buffer[offset+2] = b; //? else this.view.setUint8(offset+2, b); if (value >= 1 << 21) { b = (value >> 21) | 0x80; //? if (NODE) this.buffer[offset+3] = b; //? else this.view.setUint8(offset+3, b); if (value >= 1 << 28) { //? if (NODE) this.buffer[offset+4] = (value >> 28) & 0x0F; //? else this.view.setUint8(offset+4, (value >> 28) & 0x0F); size = 5; } else { //? if (NODE) this.buffer[offset+3] = b & 0x7F; //? else this.view.setUint8(offset+3, b & 0x7F); size = 4; } } else { //? if (NODE) this.buffer[offset+2] = b & 0x7F; //? else this.view.setUint8(offset+2, b & 0x7F); size = 3; } } else { //? if (NODE) this.buffer[offset+1] = b & 0x7F; //? else this.view.setUint8(offset+1, b & 0x7F); size = 2; } } else { //? if (NODE) this.buffer[offset] = b & 0x7F; //? else this.view.setUint8(offset, b & 0x7F); size = 1; } if (relative) { this.offset += size; return this; } return size; }; /** * Writes a zig-zag encoded 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 */ ByteBufferPrototype.writeVarint32ZigZag = function(value, offset) { return this.writeVarint32(ByteBuffer.zigZagEncode32(value), offset); }; /** * Reads a 32bit base 128 variable-length integer. * @param {number=} offset Offset to read from. Will use and increase {@link ByteBuffer#offset} by the number of bytes * written if omitted. * @returns {number|!{value: number, length: number}} The value read if offset is omitted, else the value read * and the actual number of bytes read. * @throws {Error} If it's not a valid varint. Has a property `truncated = true` if there is not enough data available * to fully decode the varint. * @expose */ ByteBufferPrototype.readVarint32 = function(offset) { //? RELATIVE(); if (!this.noAssert) { //? ASSERT_OFFSET(1); } // ref: src/google/protobuf/io/coded_stream.cc var size = 0, value = 0 >>> 0, temp, ioffset; do { ioffset = offset+size; if (!this.noAssert && ioffset > this.limit) { var err = Error("Truncated"); err['truncated'] = true; throw err; } //? if (NODE) temp = this.buffer[ioffset]; //? else temp = this.view.getUint8(ioffset); if (size < 5) value |= ((temp&0x7F)<<(7*size)) >>> 0; ++size; } while ((temp & 0x80) === 0x80); value = value | 0; // Make sure to discard the higher order bits if (relative) { this.offset += size; return value; } return { "value": value, "length": size }; }; /** * Reads a zig-zag encoded 32bit base 128 variable-length integer. * @param {number=} offset Offset to read from. Will use and increase {@link ByteBuffer#offset} by the number of bytes * written if omitted. * @returns {number|!{value: number, length: number}} The value read if offset is omitted, else the value read * and the actual number of bytes read. * @throws {Error} If it's not a valid varint * @expose */ ByteBufferPrototype.readVarint32ZigZag = function(offset) { var val = this.readVarint32(offset); if (typeof val === 'object') val["value"] = ByteBuffer.zigZagDecode32(val["value"]); else val = ByteBuffer.zigZagDecode32(val); return val; }; //? }