bytebuffer
Version:
The swiss army knife for binary data in JavaScript.
222 lines (211 loc) • 11.7 kB
JavaScript
//? if (VARINT64) {
// types/varints/varint64
if (Long) {
/**
* Maximum number of bytes required to store a 64bit base 128 variable-length integer.
* @type {number}
* @const
* @expose
*/
ByteBuffer.MAX_VARINT64_BYTES = 10;
/**
* Calculates the actual number of bytes required to store a 64bit base 128 variable-length integer.
* @param {number|!Long} value Value to encode
* @returns {number} Number of bytes required. Capped to {@link ByteBuffer.MAX_VARINT64_BYTES}
* @expose
*/
ByteBuffer.calculateVarint64 = function(value) {
//? LONG('value');
// ref: src/google/protobuf/io/coded_stream.cc
var part0 = value.toInt() >>> 0,
part1 = value.shiftRightUnsigned(28).toInt() >>> 0,
part2 = value.shiftRightUnsigned(56).toInt() >>> 0;
if (part2 == 0) {
if (part1 == 0) {
if (part0 < 1 << 14)
return part0 < 1 << 7 ? 1 : 2;
else
return part0 < 1 << 21 ? 3 : 4;
} else {
if (part1 < 1 << 14)
return part1 < 1 << 7 ? 5 : 6;
else
return part1 < 1 << 21 ? 7 : 8;
}
} else
return part2 < 1 << 7 ? 9 : 10;
};
/**
* Zigzag encodes a signed 64bit integer so that it can be effectively used with varint encoding.
* @param {number|!Long} value Signed long
* @returns {!Long} Unsigned zigzag encoded long
* @expose
*/
ByteBuffer.zigZagEncode64 = function(value) {
//? LONG('value', false);
// ref: src/google/protobuf/wire_format_lite.h
return value.shiftLeft(1).xor(value.shiftRight(63)).toUnsigned();
};
/**
* Decodes a zigzag encoded signed 64bit integer.
* @param {!Long|number} value Unsigned zigzag encoded long or JavaScript number
* @returns {!Long} Signed long
* @expose
*/
ByteBuffer.zigZagDecode64 = function(value) {
//? LONG('value', false);
// ref: src/google/protobuf/wire_format_lite.h
return value.shiftRightUnsigned(1).xor(value.and(Long.ONE).toSigned().negate()).toSigned();
};
/**
* Writes a 64bit base 128 variable-length integer.
* @param {number|Long} 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.writeVarint64 = function(value, offset) {
//? RELATIVE();
if (!this.noAssert) {
//? ASSERT_LONG('value');
//? ASSERT_OFFSET();
}
//? LONG('value', false);
var size = ByteBuffer.calculateVarint64(value),
part0 = value.toInt() >>> 0,
part1 = value.shiftRightUnsigned(28).toInt() >>> 0,
part2 = value.shiftRightUnsigned(56).toInt() >>> 0;
//? ENSURE_CAPACITY('size');
switch (size) {
//? if (NODE) {
case 10: this.buffer[offset+9] = (part2 >>> 7) & 0x01;
case 9 : this.buffer[offset+8] = size !== 9 ? (part2 ) | 0x80 : (part2 ) & 0x7F;
case 8 : this.buffer[offset+7] = size !== 8 ? (part1 >>> 21) | 0x80 : (part1 >>> 21) & 0x7F;
case 7 : this.buffer[offset+6] = size !== 7 ? (part1 >>> 14) | 0x80 : (part1 >>> 14) & 0x7F;
case 6 : this.buffer[offset+5] = size !== 6 ? (part1 >>> 7) | 0x80 : (part1 >>> 7) & 0x7F;
case 5 : this.buffer[offset+4] = size !== 5 ? (part1 ) | 0x80 : (part1 ) & 0x7F;
case 4 : this.buffer[offset+3] = size !== 4 ? (part0 >>> 21) | 0x80 : (part0 >>> 21) & 0x7F;
case 3 : this.buffer[offset+2] = size !== 3 ? (part0 >>> 14) | 0x80 : (part0 >>> 14) & 0x7F;
case 2 : this.buffer[offset+1] = size !== 2 ? (part0 >>> 7) | 0x80 : (part0 >>> 7) & 0x7F;
case 1 : this.buffer[offset ] = size !== 1 ? (part0 ) | 0x80 : (part0 ) & 0x7F;
//? } else {
case 10: this.view.setUint8(offset+9, (part2 >>> 7) & 0x01);
case 9 : this.view.setUint8(offset+8, size !== 9 ? (part2 ) | 0x80 : (part2 ) & 0x7F);
case 8 : this.view.setUint8(offset+7, size !== 8 ? (part1 >>> 21) | 0x80 : (part1 >>> 21) & 0x7F);
case 7 : this.view.setUint8(offset+6, size !== 7 ? (part1 >>> 14) | 0x80 : (part1 >>> 14) & 0x7F);
case 6 : this.view.setUint8(offset+5, size !== 6 ? (part1 >>> 7) | 0x80 : (part1 >>> 7) & 0x7F);
case 5 : this.view.setUint8(offset+4, size !== 5 ? (part1 ) | 0x80 : (part1 ) & 0x7F);
case 4 : this.view.setUint8(offset+3, size !== 4 ? (part0 >>> 21) | 0x80 : (part0 >>> 21) & 0x7F);
case 3 : this.view.setUint8(offset+2, size !== 3 ? (part0 >>> 14) | 0x80 : (part0 >>> 14) & 0x7F);
case 2 : this.view.setUint8(offset+1, size !== 2 ? (part0 >>> 7) | 0x80 : (part0 >>> 7) & 0x7F);
case 1 : this.view.setUint8(offset , size !== 1 ? (part0 ) | 0x80 : (part0 ) & 0x7F);
//? }
}
if (relative) {
this.offset += size;
return this;
} else {
return size;
}
};
/**
* Writes a zig-zag encoded 64bit base 128 variable-length integer.
* @param {number|Long} 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.writeVarint64ZigZag = function(value, offset) {
return this.writeVarint64(ByteBuffer.zigZagEncode64(value), offset);
};
/**
* Reads a 64bit base 128 variable-length integer. Requires Long.js.
* @param {number=} offset Offset to read from. Will use and increase {@link ByteBuffer#offset} by the number of bytes
* read if omitted.
* @returns {!Long|!{value: Long, 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.readVarint64 = function(offset) {
//? RELATIVE();
if (!this.noAssert) {
//? ASSERT_OFFSET(1);
}
// ref: src/google/protobuf/io/coded_stream.cc
var start = offset,
part0 = 0,
part1 = 0,
part2 = 0,
b = 0;
//? if (NODE) {
//? if (INLINE) { // Assert through checking for undefined (not optimal but coherent)
b = this.buffer[offset++]; part0 = (b & 0x7F) ; if ( b & 0x80 ) {
b = this.buffer[offset++]; part0 |= (b & 0x7F) << 7; if ((b & 0x80) || (this.noAssert && typeof b === 'undefined')) {
b = this.buffer[offset++]; part0 |= (b & 0x7F) << 14; if ((b & 0x80) || (this.noAssert && typeof b === 'undefined')) {
b = this.buffer[offset++]; part0 |= (b & 0x7F) << 21; if ((b & 0x80) || (this.noAssert && typeof b === 'undefined')) {
b = this.buffer[offset++]; part1 = (b & 0x7F) ; if ((b & 0x80) || (this.noAssert && typeof b === 'undefined')) {
b = this.buffer[offset++]; part1 |= (b & 0x7F) << 7; if ((b & 0x80) || (this.noAssert && typeof b === 'undefined')) {
b = this.buffer[offset++]; part1 |= (b & 0x7F) << 14; if ((b & 0x80) || (this.noAssert && typeof b === 'undefined')) {
b = this.buffer[offset++]; part1 |= (b & 0x7F) << 21; if ((b & 0x80) || (this.noAssert && typeof b === 'undefined')) {
b = this.buffer[offset++]; part2 = (b & 0x7F) ; if ((b & 0x80) || (this.noAssert && typeof b === 'undefined')) {
b = this.buffer[offset++]; part2 |= (b & 0x7F) << 7; if ((b & 0x80) || (this.noAssert && typeof b === 'undefined')) {
throw Error("Buffer overrun"); }}}}}}}}}}
//? } else { // Assert as usual
b = this.buffer.readUint8(offset++, true ); part0 = (b & 0x7F) ; if (b & 0x80) {
b = this.buffer.readUint8(offset++, this.noAssert); part0 |= (b & 0x7F) << 7; if (b & 0x80) {
b = this.buffer.readUint8(offset++, this.noAssert); part0 |= (b & 0x7F) << 14; if (b & 0x80) {
b = this.buffer.readUint8(offset++, this.noAssert); part0 |= (b & 0x7F) << 21; if (b & 0x80) {
b = this.buffer.readUint8(offset++, this.noAssert); part1 = (b & 0x7F) ; if (b & 0x80) {
b = this.buffer.readUint8(offset++, this.noAssert); part1 |= (b & 0x7F) << 7; if (b & 0x80) {
b = this.buffer.readUint8(offset++, this.noAssert); part1 |= (b & 0x7F) << 14; if (b & 0x80) {
b = this.buffer.readUint8(offset++, this.noAssert); part1 |= (b & 0x7F) << 21; if (b & 0x80) {
b = this.buffer.readUint8(offset++, this.noAssert); part2 = (b & 0x7F) ; if (b & 0x80) {
b = this.buffer.readUint8(offset++, this.noAssert); part2 |= (b & 0x7F) << 7; if (b & 0x80) {
throw Error("Buffer overrun"); }}}}}}}}}}
//? }
//? } else { // Asserts on its own
b = this.view.getUint8(offset++); part0 = (b & 0x7F) ; if (b & 0x80) {
b = this.view.getUint8(offset++); part0 |= (b & 0x7F) << 7; if (b & 0x80) {
b = this.view.getUint8(offset++); part0 |= (b & 0x7F) << 14; if (b & 0x80) {
b = this.view.getUint8(offset++); part0 |= (b & 0x7F) << 21; if (b & 0x80) {
b = this.view.getUint8(offset++); part1 = (b & 0x7F) ; if (b & 0x80) {
b = this.view.getUint8(offset++); part1 |= (b & 0x7F) << 7; if (b & 0x80) {
b = this.view.getUint8(offset++); part1 |= (b & 0x7F) << 14; if (b & 0x80) {
b = this.view.getUint8(offset++); part1 |= (b & 0x7F) << 21; if (b & 0x80) {
b = this.view.getUint8(offset++); part2 = (b & 0x7F) ; if (b & 0x80) {
b = this.view.getUint8(offset++); part2 |= (b & 0x7F) << 7; if (b & 0x80) {
throw Error("Buffer overrun"); }}}}}}}}}}
//? }
var value = Long.fromBits(part0 | (part1 << 28), (part1 >>> 4) | (part2) << 24, false);
if (relative) {
this.offset = offset;
return value;
} else {
return {
'value': value,
'length': offset-start
};
}
};
/**
* Reads a zig-zag encoded 64bit base 128 variable-length integer. Requires Long.js.
* @param {number=} offset Offset to read from. Will use and increase {@link ByteBuffer#offset} by the number of bytes
* read if omitted.
* @returns {!Long|!{value: Long, 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.readVarint64ZigZag = function(offset) {
var val = this.readVarint64(offset);
if (val && val['value'] instanceof Long)
val["value"] = ByteBuffer.zigZagDecode64(val["value"]);
else
val = ByteBuffer.zigZagDecode64(val);
return val;
};
} // Long
//? }