diff --git a/js/libsignal-protocol-worker.js b/js/libsignal-protocol-worker.js index ac536dff..20679574 100644 --- a/js/libsignal-protocol-worker.js +++ b/js/libsignal-protocol-worker.js @@ -25133,21 +25133,7 @@ run(); -/* vim: ts=4:sw=4:expandtab - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ +/* vim: ts=4:sw=4:expandtab */ var Internal = Internal || {}; (function() { @@ -25173,7 +25159,7 @@ var Internal = Internal || {}; var priv = new Uint8Array(privKey); priv[0] &= 248; priv[31] &= 127; - priv[31] |= 64 + priv[31] |= 64; // Where to store the result var publicKey_ptr = Module._malloc(32); diff --git a/js/libtextsecure.js b/js/libtextsecure.js index 5a357521..aab2efed 100644 --- a/js/libtextsecure.js +++ b/js/libtextsecure.js @@ -25257,21 +25257,7 @@ run(); -/* vim: ts=4:sw=4:expandtab - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ +/* vim: ts=4:sw=4:expandtab */ var Internal = Internal || {}; (function() { @@ -25297,7 +25283,7 @@ var Internal = Internal || {}; var priv = new Uint8Array(privKey); priv[0] &= 248; priv[31] &= 127; - priv[31] |= 64 + priv[31] |= 64; // Where to store the result var publicKey_ptr = Module._malloc(32); @@ -25488,1614 +25474,1614 @@ Curve25519Worker.prototype = { })(); -/* - Copyright 2013 Daniel Wirtz - Copyright 2009 The Closure Library Authors. All Rights Reserved. - - 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 long.js (c) 2013 Daniel Wirtz - * Released under the Apache License, Version 2.0 - * see: https://github.com/dcodeIO/long.js for details - */ -(function(global, factory) { - - /* AMD */ if (typeof define === 'function' && define["amd"]) - define([], factory); - /* CommonJS */ else if (typeof require === 'function' && typeof module === "object" && module && module["exports"]) - module["exports"] = factory(); - /* Global */ else - (global["dcodeIO"] = global["dcodeIO"] || {})["Long"] = factory(); - -})(this, function() { - "use strict"; - - /** - * Constructs a 64 bit two's-complement integer, given its low and high 32 bit values as *signed* integers. - * See the from* functions below for more convenient ways of constructing Longs. - * @exports Long - * @class A Long class for representing a 64 bit two's-complement integer value. - * @param {number} low The low (signed) 32 bits of the long - * @param {number} high The high (signed) 32 bits of the long - * @param {boolean=} unsigned Whether unsigned or not, defaults to `false` for signed - * @constructor - */ - function Long(low, high, unsigned) { - - /** - * The low 32 bits as a signed value. - * @type {number} - * @expose - */ - this.low = low | 0; - - /** - * The high 32 bits as a signed value. - * @type {number} - * @expose - */ - this.high = high | 0; - - /** - * Whether unsigned or not. - * @type {boolean} - * @expose - */ - this.unsigned = !!unsigned; - } - - // The internal representation of a long is the two given signed, 32-bit values. - // We use 32-bit pieces because these are the size of integers on which - // Javascript performs bit-operations. For operations like addition and - // multiplication, we split each number into 16 bit pieces, which can easily be - // multiplied within Javascript's floating-point representation without overflow - // or change in sign. - // - // In the algorithms below, we frequently reduce the negative case to the - // positive case by negating the input(s) and then post-processing the result. - // Note that we must ALWAYS check specially whether those values are MIN_VALUE - // (-2^63) because -MIN_VALUE == MIN_VALUE (since 2^63 cannot be represented as - // a positive number, it overflows back into a negative). Not handling this - // case would often result in infinite recursion. - // - // Common constant values ZERO, ONE, NEG_ONE, etc. are defined below the from* - // methods on which they depend. - - /** - * An indicator used to reliably determine if an object is a Long or not. - * @type {boolean} - * @const - * @expose - * @private - */ - Long.__isLong__; - - Object.defineProperty(Long.prototype, "__isLong__", { - value: true, - enumerable: false, - configurable: false - }); - - /** - * @function - * @param {*} obj Object - * @returns {boolean} - * @inner - */ - function isLong(obj) { - return (obj && obj["__isLong__"]) === true; - } - - /** - * Tests if the specified object is a Long. - * @function - * @param {*} obj Object - * @returns {boolean} - * @expose - */ - Long.isLong = isLong; - - /** - * A cache of the Long representations of small integer values. - * @type {!Object} - * @inner - */ - var INT_CACHE = {}; - - /** - * A cache of the Long representations of small unsigned integer values. - * @type {!Object} - * @inner - */ - var UINT_CACHE = {}; - - /** - * @param {number} value - * @param {boolean=} unsigned - * @returns {!Long} - * @inner - */ - function fromInt(value, unsigned) { - var obj, cachedObj, cache; - if (unsigned) { - value >>>= 0; - if (cache = (0 <= value && value < 256)) { - cachedObj = UINT_CACHE[value]; - if (cachedObj) - return cachedObj; - } - obj = fromBits(value, (value | 0) < 0 ? -1 : 0, true); - if (cache) - UINT_CACHE[value] = obj; - return obj; - } else { - value |= 0; - if (cache = (-128 <= value && value < 128)) { - cachedObj = INT_CACHE[value]; - if (cachedObj) - return cachedObj; - } - obj = fromBits(value, value < 0 ? -1 : 0, false); - if (cache) - INT_CACHE[value] = obj; - return obj; - } - } - - /** - * Returns a Long representing the given 32 bit integer value. - * @function - * @param {number} value The 32 bit integer in question - * @param {boolean=} unsigned Whether unsigned or not, defaults to `false` for signed - * @returns {!Long} The corresponding Long value - * @expose - */ - Long.fromInt = fromInt; - - /** - * @param {number} value - * @param {boolean=} unsigned - * @returns {!Long} - * @inner - */ - function fromNumber(value, unsigned) { - if (isNaN(value) || !isFinite(value)) - return unsigned ? UZERO : ZERO; - if (unsigned) { - if (value < 0) - return UZERO; - if (value >= TWO_PWR_64_DBL) - return MAX_UNSIGNED_VALUE; - } else { - if (value <= -TWO_PWR_63_DBL) - return MIN_VALUE; - if (value + 1 >= TWO_PWR_63_DBL) - return MAX_VALUE; - } - if (value < 0) - return fromNumber(-value, unsigned).neg(); - return fromBits((value % TWO_PWR_32_DBL) | 0, (value / TWO_PWR_32_DBL) | 0, unsigned); - } - - /** - * Returns a Long representing the given value, provided that it is a finite number. Otherwise, zero is returned. - * @function - * @param {number} value The number in question - * @param {boolean=} unsigned Whether unsigned or not, defaults to `false` for signed - * @returns {!Long} The corresponding Long value - * @expose - */ - Long.fromNumber = fromNumber; - - /** - * @param {number} lowBits - * @param {number} highBits - * @param {boolean=} unsigned - * @returns {!Long} - * @inner - */ - function fromBits(lowBits, highBits, unsigned) { - return new Long(lowBits, highBits, unsigned); - } - - /** - * Returns a Long representing the 64 bit integer that comes by concatenating the given low and high bits. Each is - * assumed to use 32 bits. - * @function - * @param {number} lowBits The low 32 bits - * @param {number} highBits The high 32 bits - * @param {boolean=} unsigned Whether unsigned or not, defaults to `false` for signed - * @returns {!Long} The corresponding Long value - * @expose - */ - Long.fromBits = fromBits; - - /** - * @function - * @param {number} base - * @param {number} exponent - * @returns {number} - * @inner - */ - var pow_dbl = Math.pow; // Used 4 times (4*8 to 15+4) - - /** - * @param {string} str - * @param {(boolean|number)=} unsigned - * @param {number=} radix - * @returns {!Long} - * @inner - */ - function fromString(str, unsigned, radix) { - if (str.length === 0) - throw Error('empty string'); - if (str === "NaN" || str === "Infinity" || str === "+Infinity" || str === "-Infinity") - return ZERO; - if (typeof unsigned === 'number') { - // For goog.math.long compatibility - radix = unsigned, - unsigned = false; - } else { - unsigned = !! unsigned; - } - radix = radix || 10; - if (radix < 2 || 36 < radix) - throw RangeError('radix'); - - var p; - if ((p = str.indexOf('-')) > 0) - throw Error('interior hyphen'); - else if (p === 0) { - return fromString(str.substring(1), unsigned, radix).neg(); - } - - // Do several (8) digits each time through the loop, so as to - // minimize the calls to the very expensive emulated div. - var radixToPower = fromNumber(pow_dbl(radix, 8)); - - var result = ZERO; - for (var i = 0; i < str.length; i += 8) { - var size = Math.min(8, str.length - i), - value = parseInt(str.substring(i, i + size), radix); - if (size < 8) { - var power = fromNumber(pow_dbl(radix, size)); - result = result.mul(power).add(fromNumber(value)); - } else { - result = result.mul(radixToPower); - result = result.add(fromNumber(value)); - } - } - result.unsigned = unsigned; - return result; - } - - /** - * Returns a Long representation of the given string, written using the specified radix. - * @function - * @param {string} str The textual representation of the Long - * @param {(boolean|number)=} unsigned Whether unsigned or not, defaults to `false` for signed - * @param {number=} radix The radix in which the text is written (2-36), defaults to 10 - * @returns {!Long} The corresponding Long value - * @expose - */ - Long.fromString = fromString; - - /** - * @function - * @param {!Long|number|string|!{low: number, high: number, unsigned: boolean}} val - * @returns {!Long} - * @inner - */ - function fromValue(val) { - if (val /* is compatible */ instanceof Long) - return val; - if (typeof val === 'number') - return fromNumber(val); - if (typeof val === 'string') - return fromString(val); - // Throws for non-objects, converts non-instanceof Long: - return fromBits(val.low, val.high, val.unsigned); - } - - /** - * Converts the specified value to a Long. - * @function - * @param {!Long|number|string|!{low: number, high: number, unsigned: boolean}} val Value - * @returns {!Long} - * @expose - */ - Long.fromValue = fromValue; - - // NOTE: the compiler should inline these constant values below and then remove these variables, so there should be - // no runtime penalty for these. - - /** - * @type {number} - * @const - * @inner - */ - var TWO_PWR_16_DBL = 1 << 16; - - /** - * @type {number} - * @const - * @inner - */ - var TWO_PWR_24_DBL = 1 << 24; - - /** - * @type {number} - * @const - * @inner - */ - var TWO_PWR_32_DBL = TWO_PWR_16_DBL * TWO_PWR_16_DBL; - - /** - * @type {number} - * @const - * @inner - */ - var TWO_PWR_64_DBL = TWO_PWR_32_DBL * TWO_PWR_32_DBL; - - /** - * @type {number} - * @const - * @inner - */ - var TWO_PWR_63_DBL = TWO_PWR_64_DBL / 2; - - /** - * @type {!Long} - * @const - * @inner - */ - var TWO_PWR_24 = fromInt(TWO_PWR_24_DBL); - - /** - * @type {!Long} - * @inner - */ - var ZERO = fromInt(0); - - /** - * Signed zero. - * @type {!Long} - * @expose - */ - Long.ZERO = ZERO; - - /** - * @type {!Long} - * @inner - */ - var UZERO = fromInt(0, true); - - /** - * Unsigned zero. - * @type {!Long} - * @expose - */ - Long.UZERO = UZERO; - - /** - * @type {!Long} - * @inner - */ - var ONE = fromInt(1); - - /** - * Signed one. - * @type {!Long} - * @expose - */ - Long.ONE = ONE; - - /** - * @type {!Long} - * @inner - */ - var UONE = fromInt(1, true); - - /** - * Unsigned one. - * @type {!Long} - * @expose - */ - Long.UONE = UONE; - - /** - * @type {!Long} - * @inner - */ - var NEG_ONE = fromInt(-1); - - /** - * Signed negative one. - * @type {!Long} - * @expose - */ - Long.NEG_ONE = NEG_ONE; - - /** - * @type {!Long} - * @inner - */ - var MAX_VALUE = fromBits(0xFFFFFFFF|0, 0x7FFFFFFF|0, false); - - /** - * Maximum signed value. - * @type {!Long} - * @expose - */ - Long.MAX_VALUE = MAX_VALUE; - - /** - * @type {!Long} - * @inner - */ - var MAX_UNSIGNED_VALUE = fromBits(0xFFFFFFFF|0, 0xFFFFFFFF|0, true); - - /** - * Maximum unsigned value. - * @type {!Long} - * @expose - */ - Long.MAX_UNSIGNED_VALUE = MAX_UNSIGNED_VALUE; - - /** - * @type {!Long} - * @inner - */ - var MIN_VALUE = fromBits(0, 0x80000000|0, false); - - /** - * Minimum signed value. - * @type {!Long} - * @expose - */ - Long.MIN_VALUE = MIN_VALUE; - - /** - * @alias Long.prototype - * @inner - */ - var LongPrototype = Long.prototype; - - /** - * Converts the Long to a 32 bit integer, assuming it is a 32 bit integer. - * @returns {number} - * @expose - */ - LongPrototype.toInt = function toInt() { - return this.unsigned ? this.low >>> 0 : this.low; - }; - - /** - * Converts the Long to a the nearest floating-point representation of this value (double, 53 bit mantissa). - * @returns {number} - * @expose - */ - LongPrototype.toNumber = function toNumber() { - if (this.unsigned) - return ((this.high >>> 0) * TWO_PWR_32_DBL) + (this.low >>> 0); - return this.high * TWO_PWR_32_DBL + (this.low >>> 0); - }; - - /** - * Converts the Long to a string written in the specified radix. - * @param {number=} radix Radix (2-36), defaults to 10 - * @returns {string} - * @override - * @throws {RangeError} If `radix` is out of range - * @expose - */ - LongPrototype.toString = function toString(radix) { - radix = radix || 10; - if (radix < 2 || 36 < radix) - throw RangeError('radix'); - if (this.isZero()) - return '0'; - if (this.isNegative()) { // Unsigned Longs are never negative - if (this.eq(MIN_VALUE)) { - // We need to change the Long value before it can be negated, so we remove - // the bottom-most digit in this base and then recurse to do the rest. - var radixLong = fromNumber(radix), - div = this.div(radixLong), - rem1 = div.mul(radixLong).sub(this); - return div.toString(radix) + rem1.toInt().toString(radix); - } else - return '-' + this.neg().toString(radix); - } - - // Do several (6) digits each time through the loop, so as to - // minimize the calls to the very expensive emulated div. - var radixToPower = fromNumber(pow_dbl(radix, 6), this.unsigned), - rem = this; - var result = ''; - while (true) { - var remDiv = rem.div(radixToPower), - intval = rem.sub(remDiv.mul(radixToPower)).toInt() >>> 0, - digits = intval.toString(radix); - rem = remDiv; - if (rem.isZero()) - return digits + result; - else { - while (digits.length < 6) - digits = '0' + digits; - result = '' + digits + result; - } - } - }; - - /** - * Gets the high 32 bits as a signed integer. - * @returns {number} Signed high bits - * @expose - */ - LongPrototype.getHighBits = function getHighBits() { - return this.high; - }; - - /** - * Gets the high 32 bits as an unsigned integer. - * @returns {number} Unsigned high bits - * @expose - */ - LongPrototype.getHighBitsUnsigned = function getHighBitsUnsigned() { - return this.high >>> 0; - }; - - /** - * Gets the low 32 bits as a signed integer. - * @returns {number} Signed low bits - * @expose - */ - LongPrototype.getLowBits = function getLowBits() { - return this.low; - }; - - /** - * Gets the low 32 bits as an unsigned integer. - * @returns {number} Unsigned low bits - * @expose - */ - LongPrototype.getLowBitsUnsigned = function getLowBitsUnsigned() { - return this.low >>> 0; - }; - - /** - * Gets the number of bits needed to represent the absolute value of this Long. - * @returns {number} - * @expose - */ - LongPrototype.getNumBitsAbs = function getNumBitsAbs() { - if (this.isNegative()) // Unsigned Longs are never negative - return this.eq(MIN_VALUE) ? 64 : this.neg().getNumBitsAbs(); - var val = this.high != 0 ? this.high : this.low; - for (var bit = 31; bit > 0; bit--) - if ((val & (1 << bit)) != 0) - break; - return this.high != 0 ? bit + 33 : bit + 1; - }; - - /** - * Tests if this Long's value equals zero. - * @returns {boolean} - * @expose - */ - LongPrototype.isZero = function isZero() { - return this.high === 0 && this.low === 0; - }; - - /** - * Tests if this Long's value is negative. - * @returns {boolean} - * @expose - */ - LongPrototype.isNegative = function isNegative() { - return !this.unsigned && this.high < 0; - }; - - /** - * Tests if this Long's value is positive. - * @returns {boolean} - * @expose - */ - LongPrototype.isPositive = function isPositive() { - return this.unsigned || this.high >= 0; - }; - - /** - * Tests if this Long's value is odd. - * @returns {boolean} - * @expose - */ - LongPrototype.isOdd = function isOdd() { - return (this.low & 1) === 1; - }; - - /** - * Tests if this Long's value is even. - * @returns {boolean} - * @expose - */ - LongPrototype.isEven = function isEven() { - return (this.low & 1) === 0; - }; - - /** - * Tests if this Long's value equals the specified's. - * @param {!Long|number|string} other Other value - * @returns {boolean} - * @expose - */ - LongPrototype.equals = function equals(other) { - if (!isLong(other)) - other = fromValue(other); - if (this.unsigned !== other.unsigned && (this.high >>> 31) === 1 && (other.high >>> 31) === 1) - return false; - return this.high === other.high && this.low === other.low; - }; - - /** - * Tests if this Long's value equals the specified's. This is an alias of {@link Long#equals}. - * @function - * @param {!Long|number|string} other Other value - * @returns {boolean} - * @expose - */ - LongPrototype.eq = LongPrototype.equals; - - /** - * Tests if this Long's value differs from the specified's. - * @param {!Long|number|string} other Other value - * @returns {boolean} - * @expose - */ - LongPrototype.notEquals = function notEquals(other) { - return !this.eq(/* validates */ other); - }; - - /** - * Tests if this Long's value differs from the specified's. This is an alias of {@link Long#notEquals}. - * @function - * @param {!Long|number|string} other Other value - * @returns {boolean} - * @expose - */ - LongPrototype.neq = LongPrototype.notEquals; - - /** - * Tests if this Long's value is less than the specified's. - * @param {!Long|number|string} other Other value - * @returns {boolean} - * @expose - */ - LongPrototype.lessThan = function lessThan(other) { - return this.comp(/* validates */ other) < 0; - }; - - /** - * Tests if this Long's value is less than the specified's. This is an alias of {@link Long#lessThan}. - * @function - * @param {!Long|number|string} other Other value - * @returns {boolean} - * @expose - */ - LongPrototype.lt = LongPrototype.lessThan; - - /** - * Tests if this Long's value is less than or equal the specified's. - * @param {!Long|number|string} other Other value - * @returns {boolean} - * @expose - */ - LongPrototype.lessThanOrEqual = function lessThanOrEqual(other) { - return this.comp(/* validates */ other) <= 0; - }; - - /** - * Tests if this Long's value is less than or equal the specified's. This is an alias of {@link Long#lessThanOrEqual}. - * @function - * @param {!Long|number|string} other Other value - * @returns {boolean} - * @expose - */ - LongPrototype.lte = LongPrototype.lessThanOrEqual; - - /** - * Tests if this Long's value is greater than the specified's. - * @param {!Long|number|string} other Other value - * @returns {boolean} - * @expose - */ - LongPrototype.greaterThan = function greaterThan(other) { - return this.comp(/* validates */ other) > 0; - }; - - /** - * Tests if this Long's value is greater than the specified's. This is an alias of {@link Long#greaterThan}. - * @function - * @param {!Long|number|string} other Other value - * @returns {boolean} - * @expose - */ - LongPrototype.gt = LongPrototype.greaterThan; - - /** - * Tests if this Long's value is greater than or equal the specified's. - * @param {!Long|number|string} other Other value - * @returns {boolean} - * @expose - */ - LongPrototype.greaterThanOrEqual = function greaterThanOrEqual(other) { - return this.comp(/* validates */ other) >= 0; - }; - - /** - * Tests if this Long's value is greater than or equal the specified's. This is an alias of {@link Long#greaterThanOrEqual}. - * @function - * @param {!Long|number|string} other Other value - * @returns {boolean} - * @expose - */ - LongPrototype.gte = LongPrototype.greaterThanOrEqual; - - /** - * Compares this Long's value with the specified's. - * @param {!Long|number|string} other Other value - * @returns {number} 0 if they are the same, 1 if the this is greater and -1 - * if the given one is greater - * @expose - */ - LongPrototype.compare = function compare(other) { - if (!isLong(other)) - other = fromValue(other); - if (this.eq(other)) - return 0; - var thisNeg = this.isNegative(), - otherNeg = other.isNegative(); - if (thisNeg && !otherNeg) - return -1; - if (!thisNeg && otherNeg) - return 1; - // At this point the sign bits are the same - if (!this.unsigned) - return this.sub(other).isNegative() ? -1 : 1; - // Both are positive if at least one is unsigned - return (other.high >>> 0) > (this.high >>> 0) || (other.high === this.high && (other.low >>> 0) > (this.low >>> 0)) ? -1 : 1; - }; - - /** - * Compares this Long's value with the specified's. This is an alias of {@link Long#compare}. - * @function - * @param {!Long|number|string} other Other value - * @returns {number} 0 if they are the same, 1 if the this is greater and -1 - * if the given one is greater - * @expose - */ - LongPrototype.comp = LongPrototype.compare; - - /** - * Negates this Long's value. - * @returns {!Long} Negated Long - * @expose - */ - LongPrototype.negate = function negate() { - if (!this.unsigned && this.eq(MIN_VALUE)) - return MIN_VALUE; - return this.not().add(ONE); - }; - - /** - * Negates this Long's value. This is an alias of {@link Long#negate}. - * @function - * @returns {!Long} Negated Long - * @expose - */ - LongPrototype.neg = LongPrototype.negate; - - /** - * Returns the sum of this and the specified Long. - * @param {!Long|number|string} addend Addend - * @returns {!Long} Sum - * @expose - */ - LongPrototype.add = function add(addend) { - if (!isLong(addend)) - addend = fromValue(addend); - - // Divide each number into 4 chunks of 16 bits, and then sum the chunks. - - var a48 = this.high >>> 16; - var a32 = this.high & 0xFFFF; - var a16 = this.low >>> 16; - var a00 = this.low & 0xFFFF; - - var b48 = addend.high >>> 16; - var b32 = addend.high & 0xFFFF; - var b16 = addend.low >>> 16; - var b00 = addend.low & 0xFFFF; - - var c48 = 0, c32 = 0, c16 = 0, c00 = 0; - c00 += a00 + b00; - c16 += c00 >>> 16; - c00 &= 0xFFFF; - c16 += a16 + b16; - c32 += c16 >>> 16; - c16 &= 0xFFFF; - c32 += a32 + b32; - c48 += c32 >>> 16; - c32 &= 0xFFFF; - c48 += a48 + b48; - c48 &= 0xFFFF; - return fromBits((c16 << 16) | c00, (c48 << 16) | c32, this.unsigned); - }; - - /** - * Returns the difference of this and the specified Long. - * @param {!Long|number|string} subtrahend Subtrahend - * @returns {!Long} Difference - * @expose - */ - LongPrototype.subtract = function subtract(subtrahend) { - if (!isLong(subtrahend)) - subtrahend = fromValue(subtrahend); - return this.add(subtrahend.neg()); - }; - - /** - * Returns the difference of this and the specified Long. This is an alias of {@link Long#subtract}. - * @function - * @param {!Long|number|string} subtrahend Subtrahend - * @returns {!Long} Difference - * @expose - */ - LongPrototype.sub = LongPrototype.subtract; - - /** - * Returns the product of this and the specified Long. - * @param {!Long|number|string} multiplier Multiplier - * @returns {!Long} Product - * @expose - */ - LongPrototype.multiply = function multiply(multiplier) { - if (this.isZero()) - return ZERO; - if (!isLong(multiplier)) - multiplier = fromValue(multiplier); - if (multiplier.isZero()) - return ZERO; - if (this.eq(MIN_VALUE)) - return multiplier.isOdd() ? MIN_VALUE : ZERO; - if (multiplier.eq(MIN_VALUE)) - return this.isOdd() ? MIN_VALUE : ZERO; - - if (this.isNegative()) { - if (multiplier.isNegative()) - return this.neg().mul(multiplier.neg()); - else - return this.neg().mul(multiplier).neg(); - } else if (multiplier.isNegative()) - return this.mul(multiplier.neg()).neg(); - - // If both longs are small, use float multiplication - if (this.lt(TWO_PWR_24) && multiplier.lt(TWO_PWR_24)) - return fromNumber(this.toNumber() * multiplier.toNumber(), this.unsigned); - - // Divide each long into 4 chunks of 16 bits, and then add up 4x4 products. - // We can skip products that would overflow. - - var a48 = this.high >>> 16; - var a32 = this.high & 0xFFFF; - var a16 = this.low >>> 16; - var a00 = this.low & 0xFFFF; - - var b48 = multiplier.high >>> 16; - var b32 = multiplier.high & 0xFFFF; - var b16 = multiplier.low >>> 16; - var b00 = multiplier.low & 0xFFFF; - - var c48 = 0, c32 = 0, c16 = 0, c00 = 0; - c00 += a00 * b00; - c16 += c00 >>> 16; - c00 &= 0xFFFF; - c16 += a16 * b00; - c32 += c16 >>> 16; - c16 &= 0xFFFF; - c16 += a00 * b16; - c32 += c16 >>> 16; - c16 &= 0xFFFF; - c32 += a32 * b00; - c48 += c32 >>> 16; - c32 &= 0xFFFF; - c32 += a16 * b16; - c48 += c32 >>> 16; - c32 &= 0xFFFF; - c32 += a00 * b32; - c48 += c32 >>> 16; - c32 &= 0xFFFF; - c48 += a48 * b00 + a32 * b16 + a16 * b32 + a00 * b48; - c48 &= 0xFFFF; - return fromBits((c16 << 16) | c00, (c48 << 16) | c32, this.unsigned); - }; - - /** - * Returns the product of this and the specified Long. This is an alias of {@link Long#multiply}. - * @function - * @param {!Long|number|string} multiplier Multiplier - * @returns {!Long} Product - * @expose - */ - LongPrototype.mul = LongPrototype.multiply; - - /** - * Returns this Long divided by the specified. The result is signed if this Long is signed or - * unsigned if this Long is unsigned. - * @param {!Long|number|string} divisor Divisor - * @returns {!Long} Quotient - * @expose - */ - LongPrototype.divide = function divide(divisor) { - if (!isLong(divisor)) - divisor = fromValue(divisor); - if (divisor.isZero()) - throw Error('division by zero'); - if (this.isZero()) - return this.unsigned ? UZERO : ZERO; - var approx, rem, res; - if (!this.unsigned) { - if (this.eq(MIN_VALUE)) { - if (divisor.eq(ONE) || divisor.eq(NEG_ONE)) - return MIN_VALUE; // recall that -MIN_VALUE == MIN_VALUE - else if (divisor.eq(MIN_VALUE)) - return ONE; - else { - // At this point, we have |other| >= 2, so |this/other| < |MIN_VALUE|. - var halfThis = this.shr(1); - approx = halfThis.div(divisor).shl(1); - if (approx.eq(ZERO)) { - return divisor.isNegative() ? ONE : NEG_ONE; - } else { - rem = this.sub(divisor.mul(approx)); - res = approx.add(rem.div(divisor)); - return res; - } - } - } else if (divisor.eq(MIN_VALUE)) - return this.unsigned ? UZERO : ZERO; - if (this.isNegative()) { - if (divisor.isNegative()) - return this.neg().div(divisor.neg()); - return this.neg().div(divisor).neg(); - } else if (divisor.isNegative()) - return this.div(divisor.neg()).neg(); - } else if (!divisor.unsigned) - divisor = divisor.toUnsigned(); - - // The algorithm below has not been made for unsigned longs. It's therefore - // required to take special care of the MSB prior to running it. - if (this.unsigned) { - if (divisor.gt(this)) - return UZERO; - if (divisor.gt(this.shru(1))) // 15 >>> 1 = 7 ; with divisor = 8 ; true - return UONE; - res = UZERO; - } else - res = ZERO; - - // Repeat the following until the remainder is less than other: find a - // floating-point that approximates remainder / other *from below*, add this - // into the result, and subtract it from the remainder. It is critical that - // the approximate value is less than or equal to the real value so that the - // remainder never becomes negative. - rem = this; - while (rem.gte(divisor)) { - // Approximate the result of division. This may be a little greater or - // smaller than the actual value. - approx = Math.max(1, Math.floor(rem.toNumber() / divisor.toNumber())); - - // We will tweak the approximate result by changing it in the 48-th digit or - // the smallest non-fractional digit, whichever is larger. - var log2 = Math.ceil(Math.log(approx) / Math.LN2), - delta = (log2 <= 48) ? 1 : pow_dbl(2, log2 - 48), - - // Decrease the approximation until it is smaller than the remainder. Note - // that if it is too large, the product overflows and is negative. - approxRes = fromNumber(approx), - approxRem = approxRes.mul(divisor); - while (approxRem.isNegative() || approxRem.gt(rem)) { - approx -= delta; - approxRes = fromNumber(approx, this.unsigned); - approxRem = approxRes.mul(divisor); - } - - // We know the answer can't be zero... and actually, zero would cause - // infinite recursion since we would make no progress. - if (approxRes.isZero()) - approxRes = ONE; - - res = res.add(approxRes); - rem = rem.sub(approxRem); - } - return res; - }; - - /** - * Returns this Long divided by the specified. This is an alias of {@link Long#divide}. - * @function - * @param {!Long|number|string} divisor Divisor - * @returns {!Long} Quotient - * @expose - */ - LongPrototype.div = LongPrototype.divide; - - /** - * Returns this Long modulo the specified. - * @param {!Long|number|string} divisor Divisor - * @returns {!Long} Remainder - * @expose - */ - LongPrototype.modulo = function modulo(divisor) { - if (!isLong(divisor)) - divisor = fromValue(divisor); - return this.sub(this.div(divisor).mul(divisor)); - }; - - /** - * Returns this Long modulo the specified. This is an alias of {@link Long#modulo}. - * @function - * @param {!Long|number|string} divisor Divisor - * @returns {!Long} Remainder - * @expose - */ - LongPrototype.mod = LongPrototype.modulo; - - /** - * Returns the bitwise NOT of this Long. - * @returns {!Long} - * @expose - */ - LongPrototype.not = function not() { - return fromBits(~this.low, ~this.high, this.unsigned); - }; - - /** - * Returns the bitwise AND of this Long and the specified. - * @param {!Long|number|string} other Other Long - * @returns {!Long} - * @expose - */ - LongPrototype.and = function and(other) { - if (!isLong(other)) - other = fromValue(other); - return fromBits(this.low & other.low, this.high & other.high, this.unsigned); - }; - - /** - * Returns the bitwise OR of this Long and the specified. - * @param {!Long|number|string} other Other Long - * @returns {!Long} - * @expose - */ - LongPrototype.or = function or(other) { - if (!isLong(other)) - other = fromValue(other); - return fromBits(this.low | other.low, this.high | other.high, this.unsigned); - }; - - /** - * Returns the bitwise XOR of this Long and the given one. - * @param {!Long|number|string} other Other Long - * @returns {!Long} - * @expose - */ - LongPrototype.xor = function xor(other) { - if (!isLong(other)) - other = fromValue(other); - return fromBits(this.low ^ other.low, this.high ^ other.high, this.unsigned); - }; - - /** - * Returns this Long with bits shifted to the left by the given amount. - * @param {number|!Long} numBits Number of bits - * @returns {!Long} Shifted Long - * @expose - */ - LongPrototype.shiftLeft = function shiftLeft(numBits) { - if (isLong(numBits)) - numBits = numBits.toInt(); - if ((numBits &= 63) === 0) - return this; - else if (numBits < 32) - return fromBits(this.low << numBits, (this.high << numBits) | (this.low >>> (32 - numBits)), this.unsigned); - else - return fromBits(0, this.low << (numBits - 32), this.unsigned); - }; - - /** - * Returns this Long with bits shifted to the left by the given amount. This is an alias of {@link Long#shiftLeft}. - * @function - * @param {number|!Long} numBits Number of bits - * @returns {!Long} Shifted Long - * @expose - */ - LongPrototype.shl = LongPrototype.shiftLeft; - - /** - * Returns this Long with bits arithmetically shifted to the right by the given amount. - * @param {number|!Long} numBits Number of bits - * @returns {!Long} Shifted Long - * @expose - */ - LongPrototype.shiftRight = function shiftRight(numBits) { - if (isLong(numBits)) - numBits = numBits.toInt(); - if ((numBits &= 63) === 0) - return this; - else if (numBits < 32) - return fromBits((this.low >>> numBits) | (this.high << (32 - numBits)), this.high >> numBits, this.unsigned); - else - return fromBits(this.high >> (numBits - 32), this.high >= 0 ? 0 : -1, this.unsigned); - }; - - /** - * Returns this Long with bits arithmetically shifted to the right by the given amount. This is an alias of {@link Long#shiftRight}. - * @function - * @param {number|!Long} numBits Number of bits - * @returns {!Long} Shifted Long - * @expose - */ - LongPrototype.shr = LongPrototype.shiftRight; - - /** - * Returns this Long with bits logically shifted to the right by the given amount. - * @param {number|!Long} numBits Number of bits - * @returns {!Long} Shifted Long - * @expose - */ - LongPrototype.shiftRightUnsigned = function shiftRightUnsigned(numBits) { - if (isLong(numBits)) - numBits = numBits.toInt(); - numBits &= 63; - if (numBits === 0) - return this; - else { - var high = this.high; - if (numBits < 32) { - var low = this.low; - return fromBits((low >>> numBits) | (high << (32 - numBits)), high >>> numBits, this.unsigned); - } else if (numBits === 32) - return fromBits(high, 0, this.unsigned); - else - return fromBits(high >>> (numBits - 32), 0, this.unsigned); - } - }; - - /** - * Returns this Long with bits logically shifted to the right by the given amount. This is an alias of {@link Long#shiftRightUnsigned}. - * @function - * @param {number|!Long} numBits Number of bits - * @returns {!Long} Shifted Long - * @expose - */ - LongPrototype.shru = LongPrototype.shiftRightUnsigned; - - /** - * Converts this Long to signed. - * @returns {!Long} Signed long - * @expose - */ - LongPrototype.toSigned = function toSigned() { - if (!this.unsigned) - return this; - return fromBits(this.low, this.high, false); - }; - - /** - * Converts this Long to unsigned. - * @returns {!Long} Unsigned long - * @expose - */ - LongPrototype.toUnsigned = function toUnsigned() { - if (this.unsigned) - return this; - return fromBits(this.low, this.high, true); - }; - - return Long; -}); - -/* - Copyright 2013-2014 Daniel Wirtz - - 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 - * This version of ByteBuffer.js uses an ArrayBuffer as its backing buffer which is accessed through a DataView and is - * compatible with modern browsers. - * Released under the Apache License, Version 2.0 - * see: https://github.com/dcodeIO/ByteBuffer.js for details - */ // -(function(global) { - "use strict"; - - /** - * @param {function(new: Long, number, number, boolean=)=} Long - * @returns {function(new: ByteBuffer, number=, boolean=, boolean=)}} - * @inner - */ - function loadByteBuffer(Long) { - - /** - * 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 RangeError("Illegal capacity"); - littleEndian = !!littleEndian; - noAssert = !!noAssert; - } - - /** - * Backing buffer. - * @type {!ArrayBuffer} - * @expose - */ - this.buffer = capacity === 0 ? EMPTY_BUFFER : new ArrayBuffer(capacity); - - /** - * Data view to manipulate the backing buffer. Becomes `null` if the backing buffer has a capacity of `0`. - * @type {?DataView} - * @expose - */ - this.view = capacity === 0 ? null : new DataView(this.buffer); - - /** - * 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.5.5"; - - /** - * 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. May be `null` if Long.js has not been loaded - * and int64 support is not available. - * @type {?Long} - * @const - * @see https://github.com/dcodeIO/Long.js - * @expose - */ - ByteBuffer.Long = Long || null; - - /** - * @alias ByteBuffer.prototype - * @inner - */ - var ByteBufferPrototype = ByteBuffer.prototype; - - // helpers - - /** - * @type {!ArrayBuffer} - * @inner - */ - var EMPTY_BUFFER = new ArrayBuffer(0); - - /** - * String.fromCharCode reference for compile-time renaming. - * @type {function(...number):string} - * @inner - */ - var stringFromCharCode = String.fromCharCode; - - /** - * Creates a source function for a string. - * @param {string} s String to read from - * @returns {function():number|null} Source function returning the next char code respectively `null` if there are - * no more characters left. - * @throws {TypeError} If the argument is invalid - * @inner - */ - function stringSource(s) { - var i=0; return function() { - return i < s.length ? s.charCodeAt(i++) : null; - }; - } - - /** - * Creates a destination function for a string. - * @returns {function(number=):undefined|string} Destination function successively called with the next char code. - * Returns the final string when called without arguments. - * @inner - */ - function stringDestination() { - var cs = [], ps = []; return function() { - if (arguments.length === 0) - return ps.join('')+stringFromCharCode.apply(String, cs); - if (cs.length + arguments.length > 1024) - ps.push(stringFromCharCode.apply(String, cs)), - cs.length = 0; - Array.prototype.push.apply(cs, arguments); - }; - } - - /** - * 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.} 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 0) capacity += length; - } - if (capacity === 0) - return new ByteBuffer(0, littleEndian, noAssert); - var bb = new ByteBuffer(capacity, littleEndian, noAssert), - bi; - var view = new Uint8Array(bb.buffer); - i=0; while (i} 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 Error("Unsupported encoding: "+encoding); - } - } - if (buffer === null || typeof buffer !== 'object') - throw TypeError("Illegal buffer"); - var bb; - if (ByteBuffer.isByteBuffer(buffer)) { - bb = ByteBufferPrototype.clone.call(buffer); - bb.markedOffset = -1; - return bb; - } - if (buffer instanceof Uint8Array) { // Extract ArrayBuffer from Uint8Array - bb = new ByteBuffer(0, littleEndian, noAssert); - if (buffer.length > 0) { // Avoid references to more than one EMPTY_BUFFER - bb.buffer = buffer.buffer; - bb.offset = buffer.byteOffset; - bb.limit = buffer.byteOffset + buffer.length; - bb.view = buffer.length > 0 ? new DataView(buffer.buffer) : null; - } - } else if (buffer instanceof ArrayBuffer) { // Reuse ArrayBuffer - bb = new ByteBuffer(0, littleEndian, noAssert); - if (buffer.byteLength > 0) { - bb.buffer = buffer; - bb.offset = 0; - bb.limit = buffer.byteLength; - bb.view = buffer.byteLength > 0 ? new DataView(buffer) : null; - } - } else if (Object.prototype.toString.call(buffer) === "[object Array]") { // Create from octets - bb = new ByteBuffer(buffer.length, littleEndian, noAssert); - bb.limit = buffer.length; - for (i=0; i + Copyright 2009 The Closure Library Authors. All Rights Reserved. + + 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 long.js (c) 2013 Daniel Wirtz + * Released under the Apache License, Version 2.0 + * see: https://github.com/dcodeIO/long.js for details + */ +(function(global, factory) { + + /* AMD */ if (typeof define === 'function' && define["amd"]) + define([], factory); + /* CommonJS */ else if (typeof require === 'function' && typeof module === "object" && module && module["exports"]) + module["exports"] = factory(); + /* Global */ else + (global["dcodeIO"] = global["dcodeIO"] || {})["Long"] = factory(); + +})(this, function() { + "use strict"; + + /** + * Constructs a 64 bit two's-complement integer, given its low and high 32 bit values as *signed* integers. + * See the from* functions below for more convenient ways of constructing Longs. + * @exports Long + * @class A Long class for representing a 64 bit two's-complement integer value. + * @param {number} low The low (signed) 32 bits of the long + * @param {number} high The high (signed) 32 bits of the long + * @param {boolean=} unsigned Whether unsigned or not, defaults to `false` for signed + * @constructor + */ + function Long(low, high, unsigned) { + + /** + * The low 32 bits as a signed value. + * @type {number} + * @expose + */ + this.low = low | 0; + + /** + * The high 32 bits as a signed value. + * @type {number} + * @expose + */ + this.high = high | 0; + + /** + * Whether unsigned or not. + * @type {boolean} + * @expose + */ + this.unsigned = !!unsigned; + } + + // The internal representation of a long is the two given signed, 32-bit values. + // We use 32-bit pieces because these are the size of integers on which + // Javascript performs bit-operations. For operations like addition and + // multiplication, we split each number into 16 bit pieces, which can easily be + // multiplied within Javascript's floating-point representation without overflow + // or change in sign. + // + // In the algorithms below, we frequently reduce the negative case to the + // positive case by negating the input(s) and then post-processing the result. + // Note that we must ALWAYS check specially whether those values are MIN_VALUE + // (-2^63) because -MIN_VALUE == MIN_VALUE (since 2^63 cannot be represented as + // a positive number, it overflows back into a negative). Not handling this + // case would often result in infinite recursion. + // + // Common constant values ZERO, ONE, NEG_ONE, etc. are defined below the from* + // methods on which they depend. + + /** + * An indicator used to reliably determine if an object is a Long or not. + * @type {boolean} + * @const + * @expose + * @private + */ + Long.__isLong__; + + Object.defineProperty(Long.prototype, "__isLong__", { + value: true, + enumerable: false, + configurable: false + }); + + /** + * @function + * @param {*} obj Object + * @returns {boolean} + * @inner + */ + function isLong(obj) { + return (obj && obj["__isLong__"]) === true; + } + + /** + * Tests if the specified object is a Long. + * @function + * @param {*} obj Object + * @returns {boolean} + * @expose + */ + Long.isLong = isLong; + + /** + * A cache of the Long representations of small integer values. + * @type {!Object} + * @inner + */ + var INT_CACHE = {}; + + /** + * A cache of the Long representations of small unsigned integer values. + * @type {!Object} + * @inner + */ + var UINT_CACHE = {}; + + /** + * @param {number} value + * @param {boolean=} unsigned + * @returns {!Long} + * @inner + */ + function fromInt(value, unsigned) { + var obj, cachedObj, cache; + if (unsigned) { + value >>>= 0; + if (cache = (0 <= value && value < 256)) { + cachedObj = UINT_CACHE[value]; + if (cachedObj) + return cachedObj; + } + obj = fromBits(value, (value | 0) < 0 ? -1 : 0, true); + if (cache) + UINT_CACHE[value] = obj; + return obj; + } else { + value |= 0; + if (cache = (-128 <= value && value < 128)) { + cachedObj = INT_CACHE[value]; + if (cachedObj) + return cachedObj; + } + obj = fromBits(value, value < 0 ? -1 : 0, false); + if (cache) + INT_CACHE[value] = obj; + return obj; + } + } + + /** + * Returns a Long representing the given 32 bit integer value. + * @function + * @param {number} value The 32 bit integer in question + * @param {boolean=} unsigned Whether unsigned or not, defaults to `false` for signed + * @returns {!Long} The corresponding Long value + * @expose + */ + Long.fromInt = fromInt; + + /** + * @param {number} value + * @param {boolean=} unsigned + * @returns {!Long} + * @inner + */ + function fromNumber(value, unsigned) { + if (isNaN(value) || !isFinite(value)) + return unsigned ? UZERO : ZERO; + if (unsigned) { + if (value < 0) + return UZERO; + if (value >= TWO_PWR_64_DBL) + return MAX_UNSIGNED_VALUE; + } else { + if (value <= -TWO_PWR_63_DBL) + return MIN_VALUE; + if (value + 1 >= TWO_PWR_63_DBL) + return MAX_VALUE; + } + if (value < 0) + return fromNumber(-value, unsigned).neg(); + return fromBits((value % TWO_PWR_32_DBL) | 0, (value / TWO_PWR_32_DBL) | 0, unsigned); + } + + /** + * Returns a Long representing the given value, provided that it is a finite number. Otherwise, zero is returned. + * @function + * @param {number} value The number in question + * @param {boolean=} unsigned Whether unsigned or not, defaults to `false` for signed + * @returns {!Long} The corresponding Long value + * @expose + */ + Long.fromNumber = fromNumber; + + /** + * @param {number} lowBits + * @param {number} highBits + * @param {boolean=} unsigned + * @returns {!Long} + * @inner + */ + function fromBits(lowBits, highBits, unsigned) { + return new Long(lowBits, highBits, unsigned); + } + + /** + * Returns a Long representing the 64 bit integer that comes by concatenating the given low and high bits. Each is + * assumed to use 32 bits. + * @function + * @param {number} lowBits The low 32 bits + * @param {number} highBits The high 32 bits + * @param {boolean=} unsigned Whether unsigned or not, defaults to `false` for signed + * @returns {!Long} The corresponding Long value + * @expose + */ + Long.fromBits = fromBits; + + /** + * @function + * @param {number} base + * @param {number} exponent + * @returns {number} + * @inner + */ + var pow_dbl = Math.pow; // Used 4 times (4*8 to 15+4) + + /** + * @param {string} str + * @param {(boolean|number)=} unsigned + * @param {number=} radix + * @returns {!Long} + * @inner + */ + function fromString(str, unsigned, radix) { + if (str.length === 0) + throw Error('empty string'); + if (str === "NaN" || str === "Infinity" || str === "+Infinity" || str === "-Infinity") + return ZERO; + if (typeof unsigned === 'number') { + // For goog.math.long compatibility + radix = unsigned, + unsigned = false; + } else { + unsigned = !! unsigned; + } + radix = radix || 10; + if (radix < 2 || 36 < radix) + throw RangeError('radix'); + + var p; + if ((p = str.indexOf('-')) > 0) + throw Error('interior hyphen'); + else if (p === 0) { + return fromString(str.substring(1), unsigned, radix).neg(); + } + + // Do several (8) digits each time through the loop, so as to + // minimize the calls to the very expensive emulated div. + var radixToPower = fromNumber(pow_dbl(radix, 8)); + + var result = ZERO; + for (var i = 0; i < str.length; i += 8) { + var size = Math.min(8, str.length - i), + value = parseInt(str.substring(i, i + size), radix); + if (size < 8) { + var power = fromNumber(pow_dbl(radix, size)); + result = result.mul(power).add(fromNumber(value)); + } else { + result = result.mul(radixToPower); + result = result.add(fromNumber(value)); + } + } + result.unsigned = unsigned; + return result; + } + + /** + * Returns a Long representation of the given string, written using the specified radix. + * @function + * @param {string} str The textual representation of the Long + * @param {(boolean|number)=} unsigned Whether unsigned or not, defaults to `false` for signed + * @param {number=} radix The radix in which the text is written (2-36), defaults to 10 + * @returns {!Long} The corresponding Long value + * @expose + */ + Long.fromString = fromString; + + /** + * @function + * @param {!Long|number|string|!{low: number, high: number, unsigned: boolean}} val + * @returns {!Long} + * @inner + */ + function fromValue(val) { + if (val /* is compatible */ instanceof Long) + return val; + if (typeof val === 'number') + return fromNumber(val); + if (typeof val === 'string') + return fromString(val); + // Throws for non-objects, converts non-instanceof Long: + return fromBits(val.low, val.high, val.unsigned); + } + + /** + * Converts the specified value to a Long. + * @function + * @param {!Long|number|string|!{low: number, high: number, unsigned: boolean}} val Value + * @returns {!Long} + * @expose + */ + Long.fromValue = fromValue; + + // NOTE: the compiler should inline these constant values below and then remove these variables, so there should be + // no runtime penalty for these. + + /** + * @type {number} + * @const + * @inner + */ + var TWO_PWR_16_DBL = 1 << 16; + + /** + * @type {number} + * @const + * @inner + */ + var TWO_PWR_24_DBL = 1 << 24; + + /** + * @type {number} + * @const + * @inner + */ + var TWO_PWR_32_DBL = TWO_PWR_16_DBL * TWO_PWR_16_DBL; + + /** + * @type {number} + * @const + * @inner + */ + var TWO_PWR_64_DBL = TWO_PWR_32_DBL * TWO_PWR_32_DBL; + + /** + * @type {number} + * @const + * @inner + */ + var TWO_PWR_63_DBL = TWO_PWR_64_DBL / 2; + + /** + * @type {!Long} + * @const + * @inner + */ + var TWO_PWR_24 = fromInt(TWO_PWR_24_DBL); + + /** + * @type {!Long} + * @inner + */ + var ZERO = fromInt(0); + + /** + * Signed zero. + * @type {!Long} + * @expose + */ + Long.ZERO = ZERO; + + /** + * @type {!Long} + * @inner + */ + var UZERO = fromInt(0, true); + + /** + * Unsigned zero. + * @type {!Long} + * @expose + */ + Long.UZERO = UZERO; + + /** + * @type {!Long} + * @inner + */ + var ONE = fromInt(1); + + /** + * Signed one. + * @type {!Long} + * @expose + */ + Long.ONE = ONE; + + /** + * @type {!Long} + * @inner + */ + var UONE = fromInt(1, true); + + /** + * Unsigned one. + * @type {!Long} + * @expose + */ + Long.UONE = UONE; + + /** + * @type {!Long} + * @inner + */ + var NEG_ONE = fromInt(-1); + + /** + * Signed negative one. + * @type {!Long} + * @expose + */ + Long.NEG_ONE = NEG_ONE; + + /** + * @type {!Long} + * @inner + */ + var MAX_VALUE = fromBits(0xFFFFFFFF|0, 0x7FFFFFFF|0, false); + + /** + * Maximum signed value. + * @type {!Long} + * @expose + */ + Long.MAX_VALUE = MAX_VALUE; + + /** + * @type {!Long} + * @inner + */ + var MAX_UNSIGNED_VALUE = fromBits(0xFFFFFFFF|0, 0xFFFFFFFF|0, true); + + /** + * Maximum unsigned value. + * @type {!Long} + * @expose + */ + Long.MAX_UNSIGNED_VALUE = MAX_UNSIGNED_VALUE; + + /** + * @type {!Long} + * @inner + */ + var MIN_VALUE = fromBits(0, 0x80000000|0, false); + + /** + * Minimum signed value. + * @type {!Long} + * @expose + */ + Long.MIN_VALUE = MIN_VALUE; + + /** + * @alias Long.prototype + * @inner + */ + var LongPrototype = Long.prototype; + + /** + * Converts the Long to a 32 bit integer, assuming it is a 32 bit integer. + * @returns {number} + * @expose + */ + LongPrototype.toInt = function toInt() { + return this.unsigned ? this.low >>> 0 : this.low; + }; + + /** + * Converts the Long to a the nearest floating-point representation of this value (double, 53 bit mantissa). + * @returns {number} + * @expose + */ + LongPrototype.toNumber = function toNumber() { + if (this.unsigned) + return ((this.high >>> 0) * TWO_PWR_32_DBL) + (this.low >>> 0); + return this.high * TWO_PWR_32_DBL + (this.low >>> 0); + }; + + /** + * Converts the Long to a string written in the specified radix. + * @param {number=} radix Radix (2-36), defaults to 10 + * @returns {string} + * @override + * @throws {RangeError} If `radix` is out of range + * @expose + */ + LongPrototype.toString = function toString(radix) { + radix = radix || 10; + if (radix < 2 || 36 < radix) + throw RangeError('radix'); + if (this.isZero()) + return '0'; + if (this.isNegative()) { // Unsigned Longs are never negative + if (this.eq(MIN_VALUE)) { + // We need to change the Long value before it can be negated, so we remove + // the bottom-most digit in this base and then recurse to do the rest. + var radixLong = fromNumber(radix), + div = this.div(radixLong), + rem1 = div.mul(radixLong).sub(this); + return div.toString(radix) + rem1.toInt().toString(radix); + } else + return '-' + this.neg().toString(radix); + } + + // Do several (6) digits each time through the loop, so as to + // minimize the calls to the very expensive emulated div. + var radixToPower = fromNumber(pow_dbl(radix, 6), this.unsigned), + rem = this; + var result = ''; + while (true) { + var remDiv = rem.div(radixToPower), + intval = rem.sub(remDiv.mul(radixToPower)).toInt() >>> 0, + digits = intval.toString(radix); + rem = remDiv; + if (rem.isZero()) + return digits + result; + else { + while (digits.length < 6) + digits = '0' + digits; + result = '' + digits + result; + } + } + }; + + /** + * Gets the high 32 bits as a signed integer. + * @returns {number} Signed high bits + * @expose + */ + LongPrototype.getHighBits = function getHighBits() { + return this.high; + }; + + /** + * Gets the high 32 bits as an unsigned integer. + * @returns {number} Unsigned high bits + * @expose + */ + LongPrototype.getHighBitsUnsigned = function getHighBitsUnsigned() { + return this.high >>> 0; + }; + + /** + * Gets the low 32 bits as a signed integer. + * @returns {number} Signed low bits + * @expose + */ + LongPrototype.getLowBits = function getLowBits() { + return this.low; + }; + + /** + * Gets the low 32 bits as an unsigned integer. + * @returns {number} Unsigned low bits + * @expose + */ + LongPrototype.getLowBitsUnsigned = function getLowBitsUnsigned() { + return this.low >>> 0; + }; + + /** + * Gets the number of bits needed to represent the absolute value of this Long. + * @returns {number} + * @expose + */ + LongPrototype.getNumBitsAbs = function getNumBitsAbs() { + if (this.isNegative()) // Unsigned Longs are never negative + return this.eq(MIN_VALUE) ? 64 : this.neg().getNumBitsAbs(); + var val = this.high != 0 ? this.high : this.low; + for (var bit = 31; bit > 0; bit--) + if ((val & (1 << bit)) != 0) + break; + return this.high != 0 ? bit + 33 : bit + 1; + }; + + /** + * Tests if this Long's value equals zero. + * @returns {boolean} + * @expose + */ + LongPrototype.isZero = function isZero() { + return this.high === 0 && this.low === 0; + }; + + /** + * Tests if this Long's value is negative. + * @returns {boolean} + * @expose + */ + LongPrototype.isNegative = function isNegative() { + return !this.unsigned && this.high < 0; + }; + + /** + * Tests if this Long's value is positive. + * @returns {boolean} + * @expose + */ + LongPrototype.isPositive = function isPositive() { + return this.unsigned || this.high >= 0; + }; + + /** + * Tests if this Long's value is odd. + * @returns {boolean} + * @expose + */ + LongPrototype.isOdd = function isOdd() { + return (this.low & 1) === 1; + }; + + /** + * Tests if this Long's value is even. + * @returns {boolean} + * @expose + */ + LongPrototype.isEven = function isEven() { + return (this.low & 1) === 0; + }; + + /** + * Tests if this Long's value equals the specified's. + * @param {!Long|number|string} other Other value + * @returns {boolean} + * @expose + */ + LongPrototype.equals = function equals(other) { + if (!isLong(other)) + other = fromValue(other); + if (this.unsigned !== other.unsigned && (this.high >>> 31) === 1 && (other.high >>> 31) === 1) + return false; + return this.high === other.high && this.low === other.low; + }; + + /** + * Tests if this Long's value equals the specified's. This is an alias of {@link Long#equals}. + * @function + * @param {!Long|number|string} other Other value + * @returns {boolean} + * @expose + */ + LongPrototype.eq = LongPrototype.equals; + + /** + * Tests if this Long's value differs from the specified's. + * @param {!Long|number|string} other Other value + * @returns {boolean} + * @expose + */ + LongPrototype.notEquals = function notEquals(other) { + return !this.eq(/* validates */ other); + }; + + /** + * Tests if this Long's value differs from the specified's. This is an alias of {@link Long#notEquals}. + * @function + * @param {!Long|number|string} other Other value + * @returns {boolean} + * @expose + */ + LongPrototype.neq = LongPrototype.notEquals; + + /** + * Tests if this Long's value is less than the specified's. + * @param {!Long|number|string} other Other value + * @returns {boolean} + * @expose + */ + LongPrototype.lessThan = function lessThan(other) { + return this.comp(/* validates */ other) < 0; + }; + + /** + * Tests if this Long's value is less than the specified's. This is an alias of {@link Long#lessThan}. + * @function + * @param {!Long|number|string} other Other value + * @returns {boolean} + * @expose + */ + LongPrototype.lt = LongPrototype.lessThan; + + /** + * Tests if this Long's value is less than or equal the specified's. + * @param {!Long|number|string} other Other value + * @returns {boolean} + * @expose + */ + LongPrototype.lessThanOrEqual = function lessThanOrEqual(other) { + return this.comp(/* validates */ other) <= 0; + }; + + /** + * Tests if this Long's value is less than or equal the specified's. This is an alias of {@link Long#lessThanOrEqual}. + * @function + * @param {!Long|number|string} other Other value + * @returns {boolean} + * @expose + */ + LongPrototype.lte = LongPrototype.lessThanOrEqual; + + /** + * Tests if this Long's value is greater than the specified's. + * @param {!Long|number|string} other Other value + * @returns {boolean} + * @expose + */ + LongPrototype.greaterThan = function greaterThan(other) { + return this.comp(/* validates */ other) > 0; + }; + + /** + * Tests if this Long's value is greater than the specified's. This is an alias of {@link Long#greaterThan}. + * @function + * @param {!Long|number|string} other Other value + * @returns {boolean} + * @expose + */ + LongPrototype.gt = LongPrototype.greaterThan; + + /** + * Tests if this Long's value is greater than or equal the specified's. + * @param {!Long|number|string} other Other value + * @returns {boolean} + * @expose + */ + LongPrototype.greaterThanOrEqual = function greaterThanOrEqual(other) { + return this.comp(/* validates */ other) >= 0; + }; + + /** + * Tests if this Long's value is greater than or equal the specified's. This is an alias of {@link Long#greaterThanOrEqual}. + * @function + * @param {!Long|number|string} other Other value + * @returns {boolean} + * @expose + */ + LongPrototype.gte = LongPrototype.greaterThanOrEqual; + + /** + * Compares this Long's value with the specified's. + * @param {!Long|number|string} other Other value + * @returns {number} 0 if they are the same, 1 if the this is greater and -1 + * if the given one is greater + * @expose + */ + LongPrototype.compare = function compare(other) { + if (!isLong(other)) + other = fromValue(other); + if (this.eq(other)) + return 0; + var thisNeg = this.isNegative(), + otherNeg = other.isNegative(); + if (thisNeg && !otherNeg) + return -1; + if (!thisNeg && otherNeg) + return 1; + // At this point the sign bits are the same + if (!this.unsigned) + return this.sub(other).isNegative() ? -1 : 1; + // Both are positive if at least one is unsigned + return (other.high >>> 0) > (this.high >>> 0) || (other.high === this.high && (other.low >>> 0) > (this.low >>> 0)) ? -1 : 1; + }; + + /** + * Compares this Long's value with the specified's. This is an alias of {@link Long#compare}. + * @function + * @param {!Long|number|string} other Other value + * @returns {number} 0 if they are the same, 1 if the this is greater and -1 + * if the given one is greater + * @expose + */ + LongPrototype.comp = LongPrototype.compare; + + /** + * Negates this Long's value. + * @returns {!Long} Negated Long + * @expose + */ + LongPrototype.negate = function negate() { + if (!this.unsigned && this.eq(MIN_VALUE)) + return MIN_VALUE; + return this.not().add(ONE); + }; + + /** + * Negates this Long's value. This is an alias of {@link Long#negate}. + * @function + * @returns {!Long} Negated Long + * @expose + */ + LongPrototype.neg = LongPrototype.negate; + + /** + * Returns the sum of this and the specified Long. + * @param {!Long|number|string} addend Addend + * @returns {!Long} Sum + * @expose + */ + LongPrototype.add = function add(addend) { + if (!isLong(addend)) + addend = fromValue(addend); + + // Divide each number into 4 chunks of 16 bits, and then sum the chunks. + + var a48 = this.high >>> 16; + var a32 = this.high & 0xFFFF; + var a16 = this.low >>> 16; + var a00 = this.low & 0xFFFF; + + var b48 = addend.high >>> 16; + var b32 = addend.high & 0xFFFF; + var b16 = addend.low >>> 16; + var b00 = addend.low & 0xFFFF; + + var c48 = 0, c32 = 0, c16 = 0, c00 = 0; + c00 += a00 + b00; + c16 += c00 >>> 16; + c00 &= 0xFFFF; + c16 += a16 + b16; + c32 += c16 >>> 16; + c16 &= 0xFFFF; + c32 += a32 + b32; + c48 += c32 >>> 16; + c32 &= 0xFFFF; + c48 += a48 + b48; + c48 &= 0xFFFF; + return fromBits((c16 << 16) | c00, (c48 << 16) | c32, this.unsigned); + }; + + /** + * Returns the difference of this and the specified Long. + * @param {!Long|number|string} subtrahend Subtrahend + * @returns {!Long} Difference + * @expose + */ + LongPrototype.subtract = function subtract(subtrahend) { + if (!isLong(subtrahend)) + subtrahend = fromValue(subtrahend); + return this.add(subtrahend.neg()); + }; + + /** + * Returns the difference of this and the specified Long. This is an alias of {@link Long#subtract}. + * @function + * @param {!Long|number|string} subtrahend Subtrahend + * @returns {!Long} Difference + * @expose + */ + LongPrototype.sub = LongPrototype.subtract; + + /** + * Returns the product of this and the specified Long. + * @param {!Long|number|string} multiplier Multiplier + * @returns {!Long} Product + * @expose + */ + LongPrototype.multiply = function multiply(multiplier) { + if (this.isZero()) + return ZERO; + if (!isLong(multiplier)) + multiplier = fromValue(multiplier); + if (multiplier.isZero()) + return ZERO; + if (this.eq(MIN_VALUE)) + return multiplier.isOdd() ? MIN_VALUE : ZERO; + if (multiplier.eq(MIN_VALUE)) + return this.isOdd() ? MIN_VALUE : ZERO; + + if (this.isNegative()) { + if (multiplier.isNegative()) + return this.neg().mul(multiplier.neg()); + else + return this.neg().mul(multiplier).neg(); + } else if (multiplier.isNegative()) + return this.mul(multiplier.neg()).neg(); + + // If both longs are small, use float multiplication + if (this.lt(TWO_PWR_24) && multiplier.lt(TWO_PWR_24)) + return fromNumber(this.toNumber() * multiplier.toNumber(), this.unsigned); + + // Divide each long into 4 chunks of 16 bits, and then add up 4x4 products. + // We can skip products that would overflow. + + var a48 = this.high >>> 16; + var a32 = this.high & 0xFFFF; + var a16 = this.low >>> 16; + var a00 = this.low & 0xFFFF; + + var b48 = multiplier.high >>> 16; + var b32 = multiplier.high & 0xFFFF; + var b16 = multiplier.low >>> 16; + var b00 = multiplier.low & 0xFFFF; + + var c48 = 0, c32 = 0, c16 = 0, c00 = 0; + c00 += a00 * b00; + c16 += c00 >>> 16; + c00 &= 0xFFFF; + c16 += a16 * b00; + c32 += c16 >>> 16; + c16 &= 0xFFFF; + c16 += a00 * b16; + c32 += c16 >>> 16; + c16 &= 0xFFFF; + c32 += a32 * b00; + c48 += c32 >>> 16; + c32 &= 0xFFFF; + c32 += a16 * b16; + c48 += c32 >>> 16; + c32 &= 0xFFFF; + c32 += a00 * b32; + c48 += c32 >>> 16; + c32 &= 0xFFFF; + c48 += a48 * b00 + a32 * b16 + a16 * b32 + a00 * b48; + c48 &= 0xFFFF; + return fromBits((c16 << 16) | c00, (c48 << 16) | c32, this.unsigned); + }; + + /** + * Returns the product of this and the specified Long. This is an alias of {@link Long#multiply}. + * @function + * @param {!Long|number|string} multiplier Multiplier + * @returns {!Long} Product + * @expose + */ + LongPrototype.mul = LongPrototype.multiply; + + /** + * Returns this Long divided by the specified. The result is signed if this Long is signed or + * unsigned if this Long is unsigned. + * @param {!Long|number|string} divisor Divisor + * @returns {!Long} Quotient + * @expose + */ + LongPrototype.divide = function divide(divisor) { + if (!isLong(divisor)) + divisor = fromValue(divisor); + if (divisor.isZero()) + throw Error('division by zero'); + if (this.isZero()) + return this.unsigned ? UZERO : ZERO; + var approx, rem, res; + if (!this.unsigned) { + if (this.eq(MIN_VALUE)) { + if (divisor.eq(ONE) || divisor.eq(NEG_ONE)) + return MIN_VALUE; // recall that -MIN_VALUE == MIN_VALUE + else if (divisor.eq(MIN_VALUE)) + return ONE; + else { + // At this point, we have |other| >= 2, so |this/other| < |MIN_VALUE|. + var halfThis = this.shr(1); + approx = halfThis.div(divisor).shl(1); + if (approx.eq(ZERO)) { + return divisor.isNegative() ? ONE : NEG_ONE; + } else { + rem = this.sub(divisor.mul(approx)); + res = approx.add(rem.div(divisor)); + return res; + } + } + } else if (divisor.eq(MIN_VALUE)) + return this.unsigned ? UZERO : ZERO; + if (this.isNegative()) { + if (divisor.isNegative()) + return this.neg().div(divisor.neg()); + return this.neg().div(divisor).neg(); + } else if (divisor.isNegative()) + return this.div(divisor.neg()).neg(); + } else if (!divisor.unsigned) + divisor = divisor.toUnsigned(); + + // The algorithm below has not been made for unsigned longs. It's therefore + // required to take special care of the MSB prior to running it. + if (this.unsigned) { + if (divisor.gt(this)) + return UZERO; + if (divisor.gt(this.shru(1))) // 15 >>> 1 = 7 ; with divisor = 8 ; true + return UONE; + res = UZERO; + } else + res = ZERO; + + // Repeat the following until the remainder is less than other: find a + // floating-point that approximates remainder / other *from below*, add this + // into the result, and subtract it from the remainder. It is critical that + // the approximate value is less than or equal to the real value so that the + // remainder never becomes negative. + rem = this; + while (rem.gte(divisor)) { + // Approximate the result of division. This may be a little greater or + // smaller than the actual value. + approx = Math.max(1, Math.floor(rem.toNumber() / divisor.toNumber())); + + // We will tweak the approximate result by changing it in the 48-th digit or + // the smallest non-fractional digit, whichever is larger. + var log2 = Math.ceil(Math.log(approx) / Math.LN2), + delta = (log2 <= 48) ? 1 : pow_dbl(2, log2 - 48), + + // Decrease the approximation until it is smaller than the remainder. Note + // that if it is too large, the product overflows and is negative. + approxRes = fromNumber(approx), + approxRem = approxRes.mul(divisor); + while (approxRem.isNegative() || approxRem.gt(rem)) { + approx -= delta; + approxRes = fromNumber(approx, this.unsigned); + approxRem = approxRes.mul(divisor); + } + + // We know the answer can't be zero... and actually, zero would cause + // infinite recursion since we would make no progress. + if (approxRes.isZero()) + approxRes = ONE; + + res = res.add(approxRes); + rem = rem.sub(approxRem); + } + return res; + }; + + /** + * Returns this Long divided by the specified. This is an alias of {@link Long#divide}. + * @function + * @param {!Long|number|string} divisor Divisor + * @returns {!Long} Quotient + * @expose + */ + LongPrototype.div = LongPrototype.divide; + + /** + * Returns this Long modulo the specified. + * @param {!Long|number|string} divisor Divisor + * @returns {!Long} Remainder + * @expose + */ + LongPrototype.modulo = function modulo(divisor) { + if (!isLong(divisor)) + divisor = fromValue(divisor); + return this.sub(this.div(divisor).mul(divisor)); + }; + + /** + * Returns this Long modulo the specified. This is an alias of {@link Long#modulo}. + * @function + * @param {!Long|number|string} divisor Divisor + * @returns {!Long} Remainder + * @expose + */ + LongPrototype.mod = LongPrototype.modulo; + + /** + * Returns the bitwise NOT of this Long. + * @returns {!Long} + * @expose + */ + LongPrototype.not = function not() { + return fromBits(~this.low, ~this.high, this.unsigned); + }; + + /** + * Returns the bitwise AND of this Long and the specified. + * @param {!Long|number|string} other Other Long + * @returns {!Long} + * @expose + */ + LongPrototype.and = function and(other) { + if (!isLong(other)) + other = fromValue(other); + return fromBits(this.low & other.low, this.high & other.high, this.unsigned); + }; + + /** + * Returns the bitwise OR of this Long and the specified. + * @param {!Long|number|string} other Other Long + * @returns {!Long} + * @expose + */ + LongPrototype.or = function or(other) { + if (!isLong(other)) + other = fromValue(other); + return fromBits(this.low | other.low, this.high | other.high, this.unsigned); + }; + + /** + * Returns the bitwise XOR of this Long and the given one. + * @param {!Long|number|string} other Other Long + * @returns {!Long} + * @expose + */ + LongPrototype.xor = function xor(other) { + if (!isLong(other)) + other = fromValue(other); + return fromBits(this.low ^ other.low, this.high ^ other.high, this.unsigned); + }; + + /** + * Returns this Long with bits shifted to the left by the given amount. + * @param {number|!Long} numBits Number of bits + * @returns {!Long} Shifted Long + * @expose + */ + LongPrototype.shiftLeft = function shiftLeft(numBits) { + if (isLong(numBits)) + numBits = numBits.toInt(); + if ((numBits &= 63) === 0) + return this; + else if (numBits < 32) + return fromBits(this.low << numBits, (this.high << numBits) | (this.low >>> (32 - numBits)), this.unsigned); + else + return fromBits(0, this.low << (numBits - 32), this.unsigned); + }; + + /** + * Returns this Long with bits shifted to the left by the given amount. This is an alias of {@link Long#shiftLeft}. + * @function + * @param {number|!Long} numBits Number of bits + * @returns {!Long} Shifted Long + * @expose + */ + LongPrototype.shl = LongPrototype.shiftLeft; + + /** + * Returns this Long with bits arithmetically shifted to the right by the given amount. + * @param {number|!Long} numBits Number of bits + * @returns {!Long} Shifted Long + * @expose + */ + LongPrototype.shiftRight = function shiftRight(numBits) { + if (isLong(numBits)) + numBits = numBits.toInt(); + if ((numBits &= 63) === 0) + return this; + else if (numBits < 32) + return fromBits((this.low >>> numBits) | (this.high << (32 - numBits)), this.high >> numBits, this.unsigned); + else + return fromBits(this.high >> (numBits - 32), this.high >= 0 ? 0 : -1, this.unsigned); + }; + + /** + * Returns this Long with bits arithmetically shifted to the right by the given amount. This is an alias of {@link Long#shiftRight}. + * @function + * @param {number|!Long} numBits Number of bits + * @returns {!Long} Shifted Long + * @expose + */ + LongPrototype.shr = LongPrototype.shiftRight; + + /** + * Returns this Long with bits logically shifted to the right by the given amount. + * @param {number|!Long} numBits Number of bits + * @returns {!Long} Shifted Long + * @expose + */ + LongPrototype.shiftRightUnsigned = function shiftRightUnsigned(numBits) { + if (isLong(numBits)) + numBits = numBits.toInt(); + numBits &= 63; + if (numBits === 0) + return this; + else { + var high = this.high; + if (numBits < 32) { + var low = this.low; + return fromBits((low >>> numBits) | (high << (32 - numBits)), high >>> numBits, this.unsigned); + } else if (numBits === 32) + return fromBits(high, 0, this.unsigned); + else + return fromBits(high >>> (numBits - 32), 0, this.unsigned); + } + }; + + /** + * Returns this Long with bits logically shifted to the right by the given amount. This is an alias of {@link Long#shiftRightUnsigned}. + * @function + * @param {number|!Long} numBits Number of bits + * @returns {!Long} Shifted Long + * @expose + */ + LongPrototype.shru = LongPrototype.shiftRightUnsigned; + + /** + * Converts this Long to signed. + * @returns {!Long} Signed long + * @expose + */ + LongPrototype.toSigned = function toSigned() { + if (!this.unsigned) + return this; + return fromBits(this.low, this.high, false); + }; + + /** + * Converts this Long to unsigned. + * @returns {!Long} Unsigned long + * @expose + */ + LongPrototype.toUnsigned = function toUnsigned() { + if (this.unsigned) + return this; + return fromBits(this.low, this.high, true); + }; + + return Long; +}); + +/* + Copyright 2013-2014 Daniel Wirtz + + 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 + * This version of ByteBuffer.js uses an ArrayBuffer as its backing buffer which is accessed through a DataView and is + * compatible with modern browsers. + * Released under the Apache License, Version 2.0 + * see: https://github.com/dcodeIO/ByteBuffer.js for details + */ // +(function(global) { + "use strict"; + + /** + * @param {function(new: Long, number, number, boolean=)=} Long + * @returns {function(new: ByteBuffer, number=, boolean=, boolean=)}} + * @inner + */ + function loadByteBuffer(Long) { + + /** + * 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 RangeError("Illegal capacity"); + littleEndian = !!littleEndian; + noAssert = !!noAssert; + } + + /** + * Backing buffer. + * @type {!ArrayBuffer} + * @expose + */ + this.buffer = capacity === 0 ? EMPTY_BUFFER : new ArrayBuffer(capacity); + + /** + * Data view to manipulate the backing buffer. Becomes `null` if the backing buffer has a capacity of `0`. + * @type {?DataView} + * @expose + */ + this.view = capacity === 0 ? null : new DataView(this.buffer); + + /** + * 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.5.5"; + + /** + * 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. May be `null` if Long.js has not been loaded + * and int64 support is not available. + * @type {?Long} + * @const + * @see https://github.com/dcodeIO/Long.js + * @expose + */ + ByteBuffer.Long = Long || null; + + /** + * @alias ByteBuffer.prototype + * @inner + */ + var ByteBufferPrototype = ByteBuffer.prototype; + + // helpers + + /** + * @type {!ArrayBuffer} + * @inner + */ + var EMPTY_BUFFER = new ArrayBuffer(0); + + /** + * String.fromCharCode reference for compile-time renaming. + * @type {function(...number):string} + * @inner + */ + var stringFromCharCode = String.fromCharCode; + + /** + * Creates a source function for a string. + * @param {string} s String to read from + * @returns {function():number|null} Source function returning the next char code respectively `null` if there are + * no more characters left. + * @throws {TypeError} If the argument is invalid + * @inner + */ + function stringSource(s) { + var i=0; return function() { + return i < s.length ? s.charCodeAt(i++) : null; + }; + } + + /** + * Creates a destination function for a string. + * @returns {function(number=):undefined|string} Destination function successively called with the next char code. + * Returns the final string when called without arguments. + * @inner + */ + function stringDestination() { + var cs = [], ps = []; return function() { + if (arguments.length === 0) + return ps.join('')+stringFromCharCode.apply(String, cs); + if (cs.length + arguments.length > 1024) + ps.push(stringFromCharCode.apply(String, cs)), + cs.length = 0; + Array.prototype.push.apply(cs, arguments); + }; + } + + /** + * 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.} 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 0) capacity += length; + } + if (capacity === 0) + return new ByteBuffer(0, littleEndian, noAssert); + var bb = new ByteBuffer(capacity, littleEndian, noAssert), + bi; + var view = new Uint8Array(bb.buffer); + i=0; while (i} 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 Error("Unsupported encoding: "+encoding); + } + } + if (buffer === null || typeof buffer !== 'object') + throw TypeError("Illegal buffer"); + var bb; + if (ByteBuffer.isByteBuffer(buffer)) { + bb = ByteBufferPrototype.clone.call(buffer); + bb.markedOffset = -1; + return bb; + } + if (buffer instanceof Uint8Array) { // Extract ArrayBuffer from Uint8Array + bb = new ByteBuffer(0, littleEndian, noAssert); + if (buffer.length > 0) { // Avoid references to more than one EMPTY_BUFFER + bb.buffer = buffer.buffer; + bb.offset = buffer.byteOffset; + bb.limit = buffer.byteOffset + buffer.length; + bb.view = buffer.length > 0 ? new DataView(buffer.buffer) : null; + } + } else if (buffer instanceof ArrayBuffer) { // Reuse ArrayBuffer + bb = new ByteBuffer(0, littleEndian, noAssert); + if (buffer.byteLength > 0) { + bb.buffer = buffer; + bb.offset = 0; + bb.limit = buffer.byteLength; + bb.view = buffer.byteLength > 0 ? new DataView(buffer) : null; + } + } else if (Object.prototype.toString.call(buffer) === "[object Array]") { // Create from octets + bb = new ByteBuffer(buffer.length, littleEndian, noAssert); + bb.limit = buffer.length; + for (i=0; i>>= 0; if (offset < 0 || offset + 0 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.byteLength); - } + } offset += 1; var capacity0 = this.buffer.byteLength; if (offset > capacity0) this.resize((capacity0 *= 2) > offset ? capacity0 : offset); offset -= 1; - this.view.setInt8(offset, value); + this.view.setInt8(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 - */ - ByteBufferPrototype.writeByte = ByteBufferPrototype.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 - */ - ByteBufferPrototype.readInt8 = function(offset) { + 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 + */ + ByteBufferPrototype.writeByte = ByteBufferPrototype.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 + */ + ByteBufferPrototype.readInt8 = function(offset) { var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; - if (!this.noAssert) { + if (!this.noAssert) { if (typeof offset !== 'number' || offset % 1 !== 0) throw TypeError("Illegal offset: "+offset+" (not an integer)"); offset >>>= 0; if (offset < 0 || offset + 1 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= "+offset+" (+"+1+") <= "+this.buffer.byteLength); - } - var value = this.view.getInt8(offset); + } + var value = this.view.getInt8(offset); 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 - */ - ByteBufferPrototype.readByte = ByteBufferPrototype.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 - */ - ByteBufferPrototype.writeUint8 = function(value, offset) { + 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 + */ + ByteBufferPrototype.readByte = ByteBufferPrototype.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 + */ + ByteBufferPrototype.writeUint8 = function(value, offset) { var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; - if (!this.noAssert) { + if (!this.noAssert) { if (typeof value !== 'number' || value % 1 !== 0) throw TypeError("Illegal value: "+value+" (not an integer)"); value >>>= 0; @@ -27174,52 +27160,52 @@ Curve25519Worker.prototype = { offset >>>= 0; if (offset < 0 || offset + 0 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.byteLength); - } + } offset += 1; var capacity1 = this.buffer.byteLength; if (offset > capacity1) this.resize((capacity1 *= 2) > offset ? capacity1 : offset); offset -= 1; - this.view.setUint8(offset, value); + this.view.setUint8(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 - */ - ByteBufferPrototype.readUint8 = function(offset) { + 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 + */ + ByteBufferPrototype.readUint8 = function(offset) { var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; - if (!this.noAssert) { + if (!this.noAssert) { if (typeof offset !== 'number' || offset % 1 !== 0) throw TypeError("Illegal offset: "+offset+" (not an integer)"); offset >>>= 0; if (offset < 0 || offset + 1 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= "+offset+" (+"+1+") <= "+this.buffer.byteLength); - } - var value = this.view.getUint8(offset); + } + var value = this.view.getUint8(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 - */ - ByteBufferPrototype.writeInt16 = function(value, offset) { + 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 + */ + ByteBufferPrototype.writeInt16 = function(value, offset) { var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; - if (!this.noAssert) { + if (!this.noAssert) { if (typeof value !== 'number' || value % 1 !== 0) throw TypeError("Illegal value: "+value+" (not an integer)"); value |= 0; @@ -27228,74 +27214,74 @@ Curve25519Worker.prototype = { offset >>>= 0; if (offset < 0 || offset + 0 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.byteLength); - } + } offset += 2; var capacity2 = this.buffer.byteLength; if (offset > capacity2) this.resize((capacity2 *= 2) > offset ? capacity2 : offset); offset -= 2; - this.view.setInt16(offset, value, this.littleEndian); + this.view.setInt16(offset, value, this.littleEndian); 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 - */ - ByteBufferPrototype.writeShort = ByteBufferPrototype.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 - */ - ByteBufferPrototype.readInt16 = function(offset) { + 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 + */ + ByteBufferPrototype.writeShort = ByteBufferPrototype.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 + */ + ByteBufferPrototype.readInt16 = function(offset) { var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; - if (!this.noAssert) { + if (!this.noAssert) { if (typeof offset !== 'number' || offset % 1 !== 0) throw TypeError("Illegal offset: "+offset+" (not an integer)"); offset >>>= 0; if (offset < 0 || offset + 2 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= "+offset+" (+"+2+") <= "+this.buffer.byteLength); - } - var value = this.view.getInt16(offset, this.littleEndian); + } + var value = this.view.getInt16(offset, this.littleEndian); 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 - */ - ByteBufferPrototype.readShort = ByteBufferPrototype.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 - */ - ByteBufferPrototype.writeUint16 = function(value, offset) { + 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 + */ + ByteBufferPrototype.readShort = ByteBufferPrototype.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 + */ + ByteBufferPrototype.writeUint16 = function(value, offset) { var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; - if (!this.noAssert) { + if (!this.noAssert) { if (typeof value !== 'number' || value % 1 !== 0) throw TypeError("Illegal value: "+value+" (not an integer)"); value >>>= 0; @@ -27304,52 +27290,52 @@ Curve25519Worker.prototype = { offset >>>= 0; if (offset < 0 || offset + 0 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.byteLength); - } + } offset += 2; var capacity3 = this.buffer.byteLength; if (offset > capacity3) this.resize((capacity3 *= 2) > offset ? capacity3 : offset); offset -= 2; - this.view.setUint16(offset, value, this.littleEndian); + this.view.setUint16(offset, value, this.littleEndian); 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 - */ - ByteBufferPrototype.readUint16 = function(offset) { + 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 + */ + ByteBufferPrototype.readUint16 = function(offset) { var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; - if (!this.noAssert) { + if (!this.noAssert) { if (typeof offset !== 'number' || offset % 1 !== 0) throw TypeError("Illegal offset: "+offset+" (not an integer)"); offset >>>= 0; if (offset < 0 || offset + 2 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= "+offset+" (+"+2+") <= "+this.buffer.byteLength); - } - var value = this.view.getUint16(offset, this.littleEndian); + } + var value = this.view.getUint16(offset, this.littleEndian); 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 - */ - ByteBufferPrototype.writeInt32 = function(value, offset) { + 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 + */ + ByteBufferPrototype.writeInt32 = function(value, offset) { var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; - if (!this.noAssert) { + if (!this.noAssert) { if (typeof value !== 'number' || value % 1 !== 0) throw TypeError("Illegal value: "+value+" (not an integer)"); value |= 0; @@ -27358,64 +27344,64 @@ Curve25519Worker.prototype = { offset >>>= 0; if (offset < 0 || offset + 0 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.byteLength); - } + } offset += 4; var capacity4 = this.buffer.byteLength; if (offset > capacity4) this.resize((capacity4 *= 2) > offset ? capacity4 : offset); offset -= 4; - this.view.setInt32(offset, value, this.littleEndian); + this.view.setInt32(offset, value, this.littleEndian); 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 - */ - ByteBufferPrototype.writeInt = ByteBufferPrototype.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 - */ - ByteBufferPrototype.readInt32 = function(offset) { + 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 + */ + ByteBufferPrototype.writeInt = ByteBufferPrototype.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 + */ + ByteBufferPrototype.readInt32 = function(offset) { var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; - if (!this.noAssert) { + if (!this.noAssert) { if (typeof offset !== 'number' || offset % 1 !== 0) throw TypeError("Illegal offset: "+offset+" (not an integer)"); offset >>>= 0; if (offset < 0 || offset + 4 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= "+offset+" (+"+4+") <= "+this.buffer.byteLength); - } - var value = this.view.getInt32(offset, this.littleEndian); + } + var value = this.view.getInt32(offset, this.littleEndian); 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 - */ - ByteBufferPrototype.readInt = ByteBufferPrototype.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 - */ - ByteBufferPrototype.writeUint32 = function(value, offset) { + 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 + */ + ByteBufferPrototype.readInt = ByteBufferPrototype.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 + */ + ByteBufferPrototype.writeUint32 = function(value, offset) { var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; - if (!this.noAssert) { + if (!this.noAssert) { if (typeof value !== 'number' || value % 1 !== 0) throw TypeError("Illegal value: "+value+" (not an integer)"); value >>>= 0; @@ -27424,53 +27410,53 @@ Curve25519Worker.prototype = { offset >>>= 0; if (offset < 0 || offset + 0 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.byteLength); - } + } offset += 4; var capacity5 = this.buffer.byteLength; if (offset > capacity5) this.resize((capacity5 *= 2) > offset ? capacity5 : offset); offset -= 4; - this.view.setUint32(offset, value, this.littleEndian); + this.view.setUint32(offset, value, this.littleEndian); 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 - */ - ByteBufferPrototype.readUint32 = function(offset) { + 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 + */ + ByteBufferPrototype.readUint32 = function(offset) { var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; - if (!this.noAssert) { + if (!this.noAssert) { if (typeof offset !== 'number' || offset % 1 !== 0) throw TypeError("Illegal offset: "+offset+" (not an integer)"); offset >>>= 0; if (offset < 0 || offset + 4 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= "+offset+" (+"+4+") <= "+this.buffer.byteLength); - } - var value = this.view.getUint32(offset, this.littleEndian); + } + var value = this.view.getUint32(offset, this.littleEndian); 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 - */ - ByteBufferPrototype.writeInt64 = function(value, offset) { + 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 + */ + ByteBufferPrototype.writeInt64 = function(value, offset) { var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; - if (!this.noAssert) { + if (!this.noAssert) { if (typeof value === 'number') value = Long.fromNumber(value); else if (typeof value === 'string') @@ -27482,7 +27468,7 @@ Curve25519Worker.prototype = { offset >>>= 0; if (offset < 0 || offset + 0 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.byteLength); - } + } if (typeof value === 'number') value = Long.fromNumber(value); else if (typeof value === 'string') @@ -27492,68 +27478,68 @@ Curve25519Worker.prototype = { if (offset > capacity6) this.resize((capacity6 *= 2) > offset ? capacity6 : offset); offset -= 8; - if (this.littleEndian) { - this.view.setInt32(offset , value.low , true); - this.view.setInt32(offset+4, value.high, true); - } else { - this.view.setInt32(offset , value.high, false); - this.view.setInt32(offset+4, value.low , false); - } + if (this.littleEndian) { + this.view.setInt32(offset , value.low , true); + this.view.setInt32(offset+4, value.high, true); + } else { + this.view.setInt32(offset , value.high, false); + this.view.setInt32(offset+4, value.low , false); + } 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 - */ - ByteBufferPrototype.writeLong = ByteBufferPrototype.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 - */ - ByteBufferPrototype.readInt64 = function(offset) { + 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 + */ + ByteBufferPrototype.writeLong = ByteBufferPrototype.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 + */ + ByteBufferPrototype.readInt64 = function(offset) { var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; - if (!this.noAssert) { + if (!this.noAssert) { if (typeof offset !== 'number' || offset % 1 !== 0) throw TypeError("Illegal offset: "+offset+" (not an integer)"); offset >>>= 0; if (offset < 0 || offset + 8 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= "+offset+" (+"+8+") <= "+this.buffer.byteLength); - } - var value = this.littleEndian - ? new Long(this.view.getInt32(offset , true ), this.view.getInt32(offset+4, true ), false) - : new Long(this.view.getInt32(offset+4, false), this.view.getInt32(offset , false), false); + } + var value = this.littleEndian + ? new Long(this.view.getInt32(offset , true ), this.view.getInt32(offset+4, true ), false) + : new Long(this.view.getInt32(offset+4, false), this.view.getInt32(offset , false), 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 - */ - ByteBufferPrototype.readLong = ByteBufferPrototype.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 - */ - ByteBufferPrototype.writeUint64 = function(value, offset) { + 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 + */ + ByteBufferPrototype.readLong = ByteBufferPrototype.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 + */ + ByteBufferPrototype.writeUint64 = function(value, offset) { var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; - if (!this.noAssert) { + if (!this.noAssert) { if (typeof value === 'number') value = Long.fromNumber(value); else if (typeof value === 'string') @@ -27565,7 +27551,7 @@ Curve25519Worker.prototype = { offset >>>= 0; if (offset < 0 || offset + 0 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.byteLength); - } + } if (typeof value === 'number') value = Long.fromNumber(value); else if (typeof value === 'string') @@ -27575,244 +27561,244 @@ Curve25519Worker.prototype = { if (offset > capacity7) this.resize((capacity7 *= 2) > offset ? capacity7 : offset); offset -= 8; - if (this.littleEndian) { - this.view.setInt32(offset , value.low , true); - this.view.setInt32(offset+4, value.high, true); - } else { - this.view.setInt32(offset , value.high, false); - this.view.setInt32(offset+4, value.low , false); - } + if (this.littleEndian) { + this.view.setInt32(offset , value.low , true); + this.view.setInt32(offset+4, value.high, true); + } else { + this.view.setInt32(offset , value.high, false); + this.view.setInt32(offset+4, value.low , false); + } 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 - */ - ByteBufferPrototype.readUint64 = function(offset) { + 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 + */ + ByteBufferPrototype.readUint64 = function(offset) { var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; - if (!this.noAssert) { + if (!this.noAssert) { if (typeof offset !== 'number' || offset % 1 !== 0) throw TypeError("Illegal offset: "+offset+" (not an integer)"); offset >>>= 0; if (offset < 0 || offset + 8 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= "+offset+" (+"+8+") <= "+this.buffer.byteLength); - } - var value = this.littleEndian - ? new Long(this.view.getInt32(offset , true ), this.view.getInt32(offset+4, true ), true) - : new Long(this.view.getInt32(offset+4, false), this.view.getInt32(offset , false), true); + } + var value = this.littleEndian + ? new Long(this.view.getInt32(offset , true ), this.view.getInt32(offset+4, true ), true) + : new Long(this.view.getInt32(offset+4, false), this.view.getInt32(offset , false), 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 - */ - ByteBufferPrototype.writeFloat32 = function(value, offset) { + 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 + */ + ByteBufferPrototype.writeFloat32 = function(value, offset) { var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; - if (!this.noAssert) { - if (typeof value !== 'number') - throw TypeError("Illegal value: "+value+" (not a number)"); + if (!this.noAssert) { + if (typeof value !== 'number') + throw TypeError("Illegal value: "+value+" (not a number)"); if (typeof offset !== 'number' || offset % 1 !== 0) throw TypeError("Illegal offset: "+offset+" (not an integer)"); offset >>>= 0; if (offset < 0 || offset + 0 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.byteLength); - } + } offset += 4; var capacity8 = this.buffer.byteLength; if (offset > capacity8) this.resize((capacity8 *= 2) > offset ? capacity8 : offset); offset -= 4; - this.view.setFloat32(offset, value, this.littleEndian); + this.view.setFloat32(offset, value, this.littleEndian); 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 - */ - ByteBufferPrototype.writeFloat = ByteBufferPrototype.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 - */ - ByteBufferPrototype.readFloat32 = function(offset) { + 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 + */ + ByteBufferPrototype.writeFloat = ByteBufferPrototype.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 + */ + ByteBufferPrototype.readFloat32 = function(offset) { var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; - if (!this.noAssert) { + if (!this.noAssert) { if (typeof offset !== 'number' || offset % 1 !== 0) throw TypeError("Illegal offset: "+offset+" (not an integer)"); offset >>>= 0; if (offset < 0 || offset + 4 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= "+offset+" (+"+4+") <= "+this.buffer.byteLength); - } - var value = this.view.getFloat32(offset, this.littleEndian); + } + var value = this.view.getFloat32(offset, this.littleEndian); 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 - */ - ByteBufferPrototype.readFloat = ByteBufferPrototype.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 - */ - ByteBufferPrototype.writeFloat64 = function(value, offset) { + 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 + */ + ByteBufferPrototype.readFloat = ByteBufferPrototype.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 + */ + ByteBufferPrototype.writeFloat64 = function(value, offset) { var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; - if (!this.noAssert) { - if (typeof value !== 'number') - throw TypeError("Illegal value: "+value+" (not a number)"); + if (!this.noAssert) { + if (typeof value !== 'number') + throw TypeError("Illegal value: "+value+" (not a number)"); if (typeof offset !== 'number' || offset % 1 !== 0) throw TypeError("Illegal offset: "+offset+" (not an integer)"); offset >>>= 0; if (offset < 0 || offset + 0 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.byteLength); - } + } offset += 8; var capacity9 = this.buffer.byteLength; if (offset > capacity9) this.resize((capacity9 *= 2) > offset ? capacity9 : offset); offset -= 8; - this.view.setFloat64(offset, value, this.littleEndian); + this.view.setFloat64(offset, value, this.littleEndian); 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 - */ - ByteBufferPrototype.writeDouble = ByteBufferPrototype.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 - */ - ByteBufferPrototype.readFloat64 = function(offset) { + 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 + */ + ByteBufferPrototype.writeDouble = ByteBufferPrototype.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 + */ + ByteBufferPrototype.readFloat64 = function(offset) { var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; - if (!this.noAssert) { + if (!this.noAssert) { if (typeof offset !== 'number' || offset % 1 !== 0) throw TypeError("Illegal offset: "+offset+" (not an integer)"); offset >>>= 0; if (offset < 0 || offset + 8 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= "+offset+" (+"+8+") <= "+this.buffer.byteLength); - } - var value = this.view.getFloat64(offset, this.littleEndian); + } + var value = this.view.getFloat64(offset, this.littleEndian); 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 - */ - ByteBufferPrototype.readDouble = ByteBufferPrototype.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 - */ - ByteBufferPrototype.writeVarint32 = function(value, offset) { + 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 + */ + ByteBufferPrototype.readDouble = ByteBufferPrototype.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 + */ + ByteBufferPrototype.writeVarint32 = function(value, offset) { var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; - if (!this.noAssert) { + if (!this.noAssert) { if (typeof value !== 'number' || value % 1 !== 0) throw TypeError("Illegal value: "+value+" (not an integer)"); value |= 0; @@ -27821,217 +27807,217 @@ Curve25519Worker.prototype = { offset >>>= 0; if (offset < 0 || offset + 0 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.byteLength); - } - var size = ByteBuffer.calculateVarint32(value), - b; + } + var size = ByteBuffer.calculateVarint32(value), + b; offset += size; var capacity10 = this.buffer.byteLength; if (offset > capacity10) this.resize((capacity10 *= 2) > offset ? capacity10 : offset); offset -= size; - // ref: http://code.google.com/searchframe#WTeibokF6gE/trunk/src/google/protobuf/io/coded_stream.cc - this.view.setUint8(offset, b = value | 0x80); - value >>>= 0; - if (value >= 1 << 7) { - b = (value >> 7) | 0x80; - this.view.setUint8(offset+1, b); - if (value >= 1 << 14) { - b = (value >> 14) | 0x80; - this.view.setUint8(offset+2, b); - if (value >= 1 << 21) { - b = (value >> 21) | 0x80; - this.view.setUint8(offset+3, b); - if (value >= 1 << 28) { - this.view.setUint8(offset+4, (value >> 28) & 0x0F); - size = 5; - } else { - this.view.setUint8(offset+3, b & 0x7F); - size = 4; - } - } else { - this.view.setUint8(offset+2, b & 0x7F); - size = 3; - } - } else { - this.view.setUint8(offset+1, b & 0x7F); - size = 2; - } - } 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) { + // ref: http://code.google.com/searchframe#WTeibokF6gE/trunk/src/google/protobuf/io/coded_stream.cc + this.view.setUint8(offset, b = value | 0x80); + value >>>= 0; + if (value >= 1 << 7) { + b = (value >> 7) | 0x80; + this.view.setUint8(offset+1, b); + if (value >= 1 << 14) { + b = (value >> 14) | 0x80; + this.view.setUint8(offset+2, b); + if (value >= 1 << 21) { + b = (value >> 21) | 0x80; + this.view.setUint8(offset+3, b); + if (value >= 1 << 28) { + this.view.setUint8(offset+4, (value >> 28) & 0x0F); + size = 5; + } else { + this.view.setUint8(offset+3, b & 0x7F); + size = 4; + } + } else { + this.view.setUint8(offset+2, b & 0x7F); + size = 3; + } + } else { + this.view.setUint8(offset+1, b & 0x7F); + size = 2; + } + } 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) { var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; - if (!this.noAssert) { + if (!this.noAssert) { if (typeof offset !== 'number' || offset % 1 !== 0) throw TypeError("Illegal offset: "+offset+" (not an integer)"); offset >>>= 0; if (offset < 0 || offset + 1 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= "+offset+" (+"+1+") <= "+this.buffer.byteLength); - } - // 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; - } - 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; - }; - - // 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) { + } + // 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; + } + 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; + }; + + // 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) { if (typeof value === 'number') value = Long.fromNumber(value); else if (typeof value === 'string') value = Long.fromString(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) { + // 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) { if (typeof value === 'number') value = Long.fromNumber(value, false); else if (typeof value === 'string') value = Long.fromString(value, false); else if (value.unsigned !== false) value = value.toSigned(); - // 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) { + // 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) { if (typeof value === 'number') value = Long.fromNumber(value, false); else if (typeof value === 'string') value = Long.fromString(value, false); else if (value.unsigned !== false) value = value.toSigned(); - // 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) { + // 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) { var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; - if (!this.noAssert) { + if (!this.noAssert) { if (typeof value === 'number') value = Long.fromNumber(value); else if (typeof value === 'string') @@ -28043,401 +28029,401 @@ Curve25519Worker.prototype = { offset >>>= 0; if (offset < 0 || offset + 0 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.byteLength); - } + } if (typeof value === 'number') value = Long.fromNumber(value, false); else if (typeof value === 'string') value = Long.fromString(value, false); else if (value.unsigned !== false) value = value.toSigned(); - var size = ByteBuffer.calculateVarint64(value), - part0 = value.toInt() >>> 0, - part1 = value.shiftRightUnsigned(28).toInt() >>> 0, - part2 = value.shiftRightUnsigned(56).toInt() >>> 0; + var size = ByteBuffer.calculateVarint64(value), + part0 = value.toInt() >>> 0, + part1 = value.shiftRightUnsigned(28).toInt() >>> 0, + part2 = value.shiftRightUnsigned(56).toInt() >>> 0; offset += size; var capacity11 = this.buffer.byteLength; if (offset > capacity11) this.resize((capacity11 *= 2) > offset ? capacity11 : offset); offset -= size; - switch (size) { - 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) { + switch (size) { + 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) { var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; - if (!this.noAssert) { + if (!this.noAssert) { if (typeof offset !== 'number' || offset % 1 !== 0) throw TypeError("Illegal offset: "+offset+" (not an integer)"); offset >>>= 0; if (offset < 0 || offset + 1 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= "+offset+" (+"+1+") <= "+this.buffer.byteLength); - } - // ref: src/google/protobuf/io/coded_stream.cc - var start = offset, - part0 = 0, - part1 = 0, - part2 = 0, - b = 0; - 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 - - - // types/strings/cstring - - /** - * Writes a NULL-terminated UTF8 encoded string. For this to work the specified string must not contain any NULL - * characters itself. - * @param {string} str String to write - * @param {number=} offset Offset to write to. Will use and increase {@link ByteBuffer#offset} by the number of bytes - * contained in `str` + 1 if omitted. - * @returns {!ByteBuffer|number} this if offset is omitted, else the actual number of bytes written - * @expose - */ - ByteBufferPrototype.writeCString = function(str, offset) { + } + // ref: src/google/protobuf/io/coded_stream.cc + var start = offset, + part0 = 0, + part1 = 0, + part2 = 0, + b = 0; + 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 + + + // types/strings/cstring + + /** + * Writes a NULL-terminated UTF8 encoded string. For this to work the specified string must not contain any NULL + * characters itself. + * @param {string} str String to write + * @param {number=} offset Offset to write to. Will use and increase {@link ByteBuffer#offset} by the number of bytes + * contained in `str` + 1 if omitted. + * @returns {!ByteBuffer|number} this if offset is omitted, else the actual number of bytes written + * @expose + */ + ByteBufferPrototype.writeCString = function(str, offset) { var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; - var i, - k = str.length; - if (!this.noAssert) { - if (typeof str !== 'string') - throw TypeError("Illegal str: Not a string"); - for (i=0; i>>= 0; if (offset < 0 || offset + 0 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.byteLength); - } - // UTF8 strings do not contain zero bytes in between except for the zero character, so: - k = utfx.calculateUTF16asUTF8(stringSource(str))[1]; + } + // UTF8 strings do not contain zero bytes in between except for the zero character, so: + k = utfx.calculateUTF16asUTF8(stringSource(str))[1]; offset += k+1; var capacity12 = this.buffer.byteLength; if (offset > capacity12) this.resize((capacity12 *= 2) > offset ? capacity12 : offset); offset -= k+1; - utfx.encodeUTF16toUTF8(stringSource(str), function(b) { - this.view.setUint8(offset++, b); - }.bind(this)); - this.view.setUint8(offset++, 0); - if (relative) { - this.offset = offset; - return this; - } - return k; - }; - - /** - * Reads a NULL-terminated UTF8 encoded string. For this to work the string read must not contain any NULL characters - * itself. - * @param {number=} offset Offset to read from. Will use and increase {@link ByteBuffer#offset} by the number of bytes - * read if omitted. - * @returns {string|!{string: string, length: number}} The string read if offset is omitted, else the string - * read and the actual number of bytes read. - * @expose - */ - ByteBufferPrototype.readCString = function(offset) { + utfx.encodeUTF16toUTF8(stringSource(str), function(b) { + this.view.setUint8(offset++, b); + }.bind(this)); + this.view.setUint8(offset++, 0); + if (relative) { + this.offset = offset; + return this; + } + return k; + }; + + /** + * Reads a NULL-terminated UTF8 encoded string. For this to work the string read must not contain any NULL characters + * itself. + * @param {number=} offset Offset to read from. Will use and increase {@link ByteBuffer#offset} by the number of bytes + * read if omitted. + * @returns {string|!{string: string, length: number}} The string read if offset is omitted, else the string + * read and the actual number of bytes read. + * @expose + */ + ByteBufferPrototype.readCString = function(offset) { var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; - if (!this.noAssert) { + if (!this.noAssert) { if (typeof offset !== 'number' || offset % 1 !== 0) throw TypeError("Illegal offset: "+offset+" (not an integer)"); offset >>>= 0; if (offset < 0 || offset + 1 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= "+offset+" (+"+1+") <= "+this.buffer.byteLength); - } - var start = offset, - temp; - // UTF8 strings do not contain zero bytes in between except for the zero character itself, so: - var sd, b = -1; - utfx.decodeUTF8toUTF16(function() { - if (b === 0) return null; - if (offset >= this.limit) - throw RangeError("Illegal range: Truncated data, "+offset+" < "+this.limit); - return (b = this.view.getUint8(offset++)) === 0 ? null : b; - }.bind(this), sd = stringDestination(), true); - if (relative) { - this.offset = offset; - return sd(); - } else { - return { - "string": sd(), - "length": offset - start - }; - } - }; - - // types/strings/istring - - /** - * Writes a length as uint32 prefixed UTF8 encoded string. - * @param {string} str String 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 - * @see ByteBuffer#writeVarint32 - */ - ByteBufferPrototype.writeIString = function(str, offset) { + } + var start = offset, + temp; + // UTF8 strings do not contain zero bytes in between except for the zero character itself, so: + var sd, b = -1; + utfx.decodeUTF8toUTF16(function() { + if (b === 0) return null; + if (offset >= this.limit) + throw RangeError("Illegal range: Truncated data, "+offset+" < "+this.limit); + return (b = this.view.getUint8(offset++)) === 0 ? null : b; + }.bind(this), sd = stringDestination(), true); + if (relative) { + this.offset = offset; + return sd(); + } else { + return { + "string": sd(), + "length": offset - start + }; + } + }; + + // types/strings/istring + + /** + * Writes a length as uint32 prefixed UTF8 encoded string. + * @param {string} str String 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 + * @see ByteBuffer#writeVarint32 + */ + ByteBufferPrototype.writeIString = function(str, offset) { var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; - if (!this.noAssert) { - if (typeof str !== 'string') - throw TypeError("Illegal str: Not a string"); + if (!this.noAssert) { + if (typeof str !== 'string') + throw TypeError("Illegal str: Not a string"); if (typeof offset !== 'number' || offset % 1 !== 0) throw TypeError("Illegal offset: "+offset+" (not an integer)"); offset >>>= 0; if (offset < 0 || offset + 0 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.byteLength); - } - var start = offset, - k; - k = utfx.calculateUTF16asUTF8(stringSource(str), this.noAssert)[1]; + } + var start = offset, + k; + k = utfx.calculateUTF16asUTF8(stringSource(str), this.noAssert)[1]; offset += 4+k; var capacity13 = this.buffer.byteLength; if (offset > capacity13) this.resize((capacity13 *= 2) > offset ? capacity13 : offset); offset -= 4+k; - this.view.setUint32(offset, k, this.littleEndian); - offset += 4; - utfx.encodeUTF16toUTF8(stringSource(str), function(b) { - this.view.setUint8(offset++, b); - }.bind(this)); - if (offset !== start + 4 + k) - throw RangeError("Illegal range: Truncated data, "+offset+" == "+(offset+4+k)); - if (relative) { - this.offset = offset; - return this; - } - return offset - start; - }; - - /** - * Reads a length as uint32 prefixed UTF8 encoded string. - * @param {number=} offset Offset to read from. Will use and increase {@link ByteBuffer#offset} by the number of bytes - * read if omitted. - * @returns {string|!{string: string, length: number}} The string read if offset is omitted, else the string - * read and the actual number of bytes read. - * @expose - * @see ByteBuffer#readVarint32 - */ - ByteBufferPrototype.readIString = function(offset) { + this.view.setUint32(offset, k, this.littleEndian); + offset += 4; + utfx.encodeUTF16toUTF8(stringSource(str), function(b) { + this.view.setUint8(offset++, b); + }.bind(this)); + if (offset !== start + 4 + k) + throw RangeError("Illegal range: Truncated data, "+offset+" == "+(offset+4+k)); + if (relative) { + this.offset = offset; + return this; + } + return offset - start; + }; + + /** + * Reads a length as uint32 prefixed UTF8 encoded string. + * @param {number=} offset Offset to read from. Will use and increase {@link ByteBuffer#offset} by the number of bytes + * read if omitted. + * @returns {string|!{string: string, length: number}} The string read if offset is omitted, else the string + * read and the actual number of bytes read. + * @expose + * @see ByteBuffer#readVarint32 + */ + ByteBufferPrototype.readIString = function(offset) { var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; - if (!this.noAssert) { + if (!this.noAssert) { if (typeof offset !== 'number' || offset % 1 !== 0) throw TypeError("Illegal offset: "+offset+" (not an integer)"); offset >>>= 0; if (offset < 0 || offset + 4 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= "+offset+" (+"+4+") <= "+this.buffer.byteLength); - } - var temp = 0, - start = offset, - str; - temp = this.view.getUint32(offset, this.littleEndian); - offset += 4; - var k = offset + temp, - sd; - utfx.decodeUTF8toUTF16(function() { - return offset < k ? this.view.getUint8(offset++) : null; - }.bind(this), sd = stringDestination(), this.noAssert); - str = sd(); - if (relative) { - this.offset = offset; - return str; - } else { - return { - 'string': str, - 'length': offset - start - }; - } - }; - - // types/strings/utf8string - - /** - * Metrics representing number of UTF8 characters. Evaluates to `c`. - * @type {string} - * @const - * @expose - */ - ByteBuffer.METRICS_CHARS = 'c'; - - /** - * Metrics representing number of bytes. Evaluates to `b`. - * @type {string} - * @const - * @expose - */ - ByteBuffer.METRICS_BYTES = 'b'; - - /** - * Writes an UTF8 encoded string. - * @param {string} str String to write - * @param {number=} offset Offset to write to. Will use and increase {@link ByteBuffer#offset} if omitted. - * @returns {!ByteBuffer|number} this if offset is omitted, else the actual number of bytes written. - * @expose - */ - ByteBufferPrototype.writeUTF8String = function(str, offset) { + } + var temp = 0, + start = offset, + str; + temp = this.view.getUint32(offset, this.littleEndian); + offset += 4; + var k = offset + temp, + sd; + utfx.decodeUTF8toUTF16(function() { + return offset < k ? this.view.getUint8(offset++) : null; + }.bind(this), sd = stringDestination(), this.noAssert); + str = sd(); + if (relative) { + this.offset = offset; + return str; + } else { + return { + 'string': str, + 'length': offset - start + }; + } + }; + + // types/strings/utf8string + + /** + * Metrics representing number of UTF8 characters. Evaluates to `c`. + * @type {string} + * @const + * @expose + */ + ByteBuffer.METRICS_CHARS = 'c'; + + /** + * Metrics representing number of bytes. Evaluates to `b`. + * @type {string} + * @const + * @expose + */ + ByteBuffer.METRICS_BYTES = 'b'; + + /** + * Writes an UTF8 encoded string. + * @param {string} str String to write + * @param {number=} offset Offset to write to. Will use and increase {@link ByteBuffer#offset} if omitted. + * @returns {!ByteBuffer|number} this if offset is omitted, else the actual number of bytes written. + * @expose + */ + ByteBufferPrototype.writeUTF8String = function(str, offset) { var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; - if (!this.noAssert) { + if (!this.noAssert) { if (typeof offset !== 'number' || offset % 1 !== 0) throw TypeError("Illegal offset: "+offset+" (not an integer)"); offset >>>= 0; if (offset < 0 || offset + 0 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.byteLength); - } - var k; - var start = offset; - k = utfx.calculateUTF16asUTF8(stringSource(str))[1]; + } + var k; + var start = offset; + k = utfx.calculateUTF16asUTF8(stringSource(str))[1]; offset += k; var capacity14 = this.buffer.byteLength; if (offset > capacity14) this.resize((capacity14 *= 2) > offset ? capacity14 : offset); offset -= k; - utfx.encodeUTF16toUTF8(stringSource(str), function(b) { - this.view.setUint8(offset++, b); - }.bind(this)); - if (relative) { - this.offset = offset; - return this; - } - return offset - start; - }; - - /** - * Writes an UTF8 encoded string. This is an alias of {@link ByteBuffer#writeUTF8String}. - * @function - * @param {string} str String to write - * @param {number=} offset Offset to write to. Will use and increase {@link ByteBuffer#offset} if omitted. - * @returns {!ByteBuffer|number} this if offset is omitted, else the actual number of bytes written. - * @expose - */ - ByteBufferPrototype.writeString = ByteBufferPrototype.writeUTF8String; - - /** - * Calculates the number of UTF8 characters of a string. JavaScript itself uses UTF-16, so that a string's - * `length` property does not reflect its actual UTF8 size if it contains code points larger than 0xFFFF. - * @function - * @param {string} str String to calculate - * @returns {number} Number of UTF8 characters - * @expose - */ - ByteBuffer.calculateUTF8Chars = function(str) { - return utfx.calculateUTF16asUTF8(stringSource(str))[0]; - }; - - /** - * Calculates the number of UTF8 bytes of a string. - * @function - * @param {string} str String to calculate - * @returns {number} Number of UTF8 bytes - * @expose - */ - ByteBuffer.calculateUTF8Bytes = function(str) { - return utfx.calculateUTF16asUTF8(stringSource(str))[1]; - }; - - /** - * Reads an UTF8 encoded string. - * @param {number} length Number of characters or bytes to read. - * @param {string=} metrics Metrics specifying what `length` is meant to count. Defaults to - * {@link ByteBuffer.METRICS_CHARS}. - * @param {number=} offset Offset to read from. Will use and increase {@link ByteBuffer#offset} by the number of bytes - * read if omitted. - * @returns {string|!{string: string, length: number}} The string read if offset is omitted, else the string - * read and the actual number of bytes read. - * @expose - */ - ByteBufferPrototype.readUTF8String = function(length, metrics, offset) { - if (typeof metrics === 'number') { - offset = metrics; - metrics = undefined; - } + utfx.encodeUTF16toUTF8(stringSource(str), function(b) { + this.view.setUint8(offset++, b); + }.bind(this)); + if (relative) { + this.offset = offset; + return this; + } + return offset - start; + }; + + /** + * Writes an UTF8 encoded string. This is an alias of {@link ByteBuffer#writeUTF8String}. + * @function + * @param {string} str String to write + * @param {number=} offset Offset to write to. Will use and increase {@link ByteBuffer#offset} if omitted. + * @returns {!ByteBuffer|number} this if offset is omitted, else the actual number of bytes written. + * @expose + */ + ByteBufferPrototype.writeString = ByteBufferPrototype.writeUTF8String; + + /** + * Calculates the number of UTF8 characters of a string. JavaScript itself uses UTF-16, so that a string's + * `length` property does not reflect its actual UTF8 size if it contains code points larger than 0xFFFF. + * @function + * @param {string} str String to calculate + * @returns {number} Number of UTF8 characters + * @expose + */ + ByteBuffer.calculateUTF8Chars = function(str) { + return utfx.calculateUTF16asUTF8(stringSource(str))[0]; + }; + + /** + * Calculates the number of UTF8 bytes of a string. + * @function + * @param {string} str String to calculate + * @returns {number} Number of UTF8 bytes + * @expose + */ + ByteBuffer.calculateUTF8Bytes = function(str) { + return utfx.calculateUTF16asUTF8(stringSource(str))[1]; + }; + + /** + * Reads an UTF8 encoded string. + * @param {number} length Number of characters or bytes to read. + * @param {string=} metrics Metrics specifying what `length` is meant to count. Defaults to + * {@link ByteBuffer.METRICS_CHARS}. + * @param {number=} offset Offset to read from. Will use and increase {@link ByteBuffer#offset} by the number of bytes + * read if omitted. + * @returns {string|!{string: string, length: number}} The string read if offset is omitted, else the string + * read and the actual number of bytes read. + * @expose + */ + ByteBufferPrototype.readUTF8String = function(length, metrics, offset) { + if (typeof metrics === 'number') { + offset = metrics; + metrics = undefined; + } var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; - if (typeof metrics === 'undefined') metrics = ByteBuffer.METRICS_CHARS; - if (!this.noAssert) { + if (typeof metrics === 'undefined') metrics = ByteBuffer.METRICS_CHARS; + if (!this.noAssert) { if (typeof length !== 'number' || length % 1 !== 0) throw TypeError("Illegal length: "+length+" (not an integer)"); length |= 0; @@ -28446,284 +28432,284 @@ Curve25519Worker.prototype = { offset >>>= 0; if (offset < 0 || offset + 0 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.byteLength); - } - var i = 0, - start = offset, - sd; - if (metrics === ByteBuffer.METRICS_CHARS) { // The same for node and the browser - sd = stringDestination(); - utfx.decodeUTF8(function() { - return i < length && offset < this.limit ? this.view.getUint8(offset++) : null; - }.bind(this), function(cp) { - ++i; utfx.UTF8toUTF16(cp, sd); - }.bind(this)); - if (i !== length) - throw RangeError("Illegal range: Truncated data, "+i+" == "+length); - if (relative) { - this.offset = offset; - return sd(); - } else { - return { - "string": sd(), - "length": offset - start - }; - } - } else if (metrics === ByteBuffer.METRICS_BYTES) { - if (!this.noAssert) { + } + var i = 0, + start = offset, + sd; + if (metrics === ByteBuffer.METRICS_CHARS) { // The same for node and the browser + sd = stringDestination(); + utfx.decodeUTF8(function() { + return i < length && offset < this.limit ? this.view.getUint8(offset++) : null; + }.bind(this), function(cp) { + ++i; utfx.UTF8toUTF16(cp, sd); + }.bind(this)); + if (i !== length) + throw RangeError("Illegal range: Truncated data, "+i+" == "+length); + if (relative) { + this.offset = offset; + return sd(); + } else { + return { + "string": sd(), + "length": offset - start + }; + } + } else if (metrics === ByteBuffer.METRICS_BYTES) { + if (!this.noAssert) { if (typeof offset !== 'number' || offset % 1 !== 0) throw TypeError("Illegal offset: "+offset+" (not an integer)"); offset >>>= 0; if (offset < 0 || offset + length > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= "+offset+" (+"+length+") <= "+this.buffer.byteLength); - } - var k = offset + length; - utfx.decodeUTF8toUTF16(function() { - return offset < k ? this.view.getUint8(offset++) : null; - }.bind(this), sd = stringDestination(), this.noAssert); - if (offset !== k) - throw RangeError("Illegal range: Truncated data, "+offset+" == "+k); - if (relative) { - this.offset = offset; - return sd(); - } else { - return { - 'string': sd(), - 'length': offset - start - }; - } - } else - throw TypeError("Unsupported metrics: "+metrics); - }; - - /** - * Reads an UTF8 encoded string. This is an alias of {@link ByteBuffer#readUTF8String}. - * @function - * @param {number} length Number of characters or bytes to read - * @param {number=} metrics Metrics specifying what `n` is meant to count. Defaults to - * {@link ByteBuffer.METRICS_CHARS}. - * @param {number=} offset Offset to read from. Will use and increase {@link ByteBuffer#offset} by the number of bytes - * read if omitted. - * @returns {string|!{string: string, length: number}} The string read if offset is omitted, else the string - * read and the actual number of bytes read. - * @expose - */ - ByteBufferPrototype.readString = ByteBufferPrototype.readUTF8String; - - // types/strings/vstring - - /** - * Writes a length as varint32 prefixed UTF8 encoded string. - * @param {string} str String 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 - * @see ByteBuffer#writeVarint32 - */ - ByteBufferPrototype.writeVString = function(str, offset) { + } + var k = offset + length; + utfx.decodeUTF8toUTF16(function() { + return offset < k ? this.view.getUint8(offset++) : null; + }.bind(this), sd = stringDestination(), this.noAssert); + if (offset !== k) + throw RangeError("Illegal range: Truncated data, "+offset+" == "+k); + if (relative) { + this.offset = offset; + return sd(); + } else { + return { + 'string': sd(), + 'length': offset - start + }; + } + } else + throw TypeError("Unsupported metrics: "+metrics); + }; + + /** + * Reads an UTF8 encoded string. This is an alias of {@link ByteBuffer#readUTF8String}. + * @function + * @param {number} length Number of characters or bytes to read + * @param {number=} metrics Metrics specifying what `n` is meant to count. Defaults to + * {@link ByteBuffer.METRICS_CHARS}. + * @param {number=} offset Offset to read from. Will use and increase {@link ByteBuffer#offset} by the number of bytes + * read if omitted. + * @returns {string|!{string: string, length: number}} The string read if offset is omitted, else the string + * read and the actual number of bytes read. + * @expose + */ + ByteBufferPrototype.readString = ByteBufferPrototype.readUTF8String; + + // types/strings/vstring + + /** + * Writes a length as varint32 prefixed UTF8 encoded string. + * @param {string} str String 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 + * @see ByteBuffer#writeVarint32 + */ + ByteBufferPrototype.writeVString = function(str, offset) { var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; - if (!this.noAssert) { - if (typeof str !== 'string') - throw TypeError("Illegal str: Not a string"); + if (!this.noAssert) { + if (typeof str !== 'string') + throw TypeError("Illegal str: Not a string"); if (typeof offset !== 'number' || offset % 1 !== 0) throw TypeError("Illegal offset: "+offset+" (not an integer)"); offset >>>= 0; if (offset < 0 || offset + 0 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.byteLength); - } - var start = offset, - k, l; - k = utfx.calculateUTF16asUTF8(stringSource(str), this.noAssert)[1]; - l = ByteBuffer.calculateVarint32(k); + } + var start = offset, + k, l; + k = utfx.calculateUTF16asUTF8(stringSource(str), this.noAssert)[1]; + l = ByteBuffer.calculateVarint32(k); offset += l+k; var capacity15 = this.buffer.byteLength; if (offset > capacity15) this.resize((capacity15 *= 2) > offset ? capacity15 : offset); offset -= l+k; - offset += this.writeVarint32(k, offset); - utfx.encodeUTF16toUTF8(stringSource(str), function(b) { - this.view.setUint8(offset++, b); - }.bind(this)); - if (offset !== start+k+l) - throw RangeError("Illegal range: Truncated data, "+offset+" == "+(offset+k+l)); - if (relative) { - this.offset = offset; - return this; - } - return offset - start; - }; - - /** - * Reads a length as varint32 prefixed UTF8 encoded string. - * @param {number=} offset Offset to read from. Will use and increase {@link ByteBuffer#offset} by the number of bytes - * read if omitted. - * @returns {string|!{string: string, length: number}} The string read if offset is omitted, else the string - * read and the actual number of bytes read. - * @expose - * @see ByteBuffer#readVarint32 - */ - ByteBufferPrototype.readVString = function(offset) { + offset += this.writeVarint32(k, offset); + utfx.encodeUTF16toUTF8(stringSource(str), function(b) { + this.view.setUint8(offset++, b); + }.bind(this)); + if (offset !== start+k+l) + throw RangeError("Illegal range: Truncated data, "+offset+" == "+(offset+k+l)); + if (relative) { + this.offset = offset; + return this; + } + return offset - start; + }; + + /** + * Reads a length as varint32 prefixed UTF8 encoded string. + * @param {number=} offset Offset to read from. Will use and increase {@link ByteBuffer#offset} by the number of bytes + * read if omitted. + * @returns {string|!{string: string, length: number}} The string read if offset is omitted, else the string + * read and the actual number of bytes read. + * @expose + * @see ByteBuffer#readVarint32 + */ + ByteBufferPrototype.readVString = function(offset) { var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; - if (!this.noAssert) { + if (!this.noAssert) { if (typeof offset !== 'number' || offset % 1 !== 0) throw TypeError("Illegal offset: "+offset+" (not an integer)"); offset >>>= 0; if (offset < 0 || offset + 1 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= "+offset+" (+"+1+") <= "+this.buffer.byteLength); - } - var temp = this.readVarint32(offset), - start = offset, - str; - offset += temp['length']; - temp = temp['value']; - var k = offset + temp, - sd = stringDestination(); - utfx.decodeUTF8toUTF16(function() { - return offset < k ? this.view.getUint8(offset++) : null; - }.bind(this), sd, this.noAssert); - str = sd(); - if (relative) { - this.offset = offset; - return str; - } else { - return { - 'string': str, - 'length': offset - start - }; - } - }; - - - /** - * Appends some data to this ByteBuffer. This will overwrite any contents behind the specified offset up to the appended - * data's length. - * @param {!ByteBuffer|!ArrayBuffer|!Uint8Array|string} source Data to append. If `source` is a ByteBuffer, its offsets - * will be modified according to the performed read operation. - * @param {(string|number)=} encoding Encoding if `data` is a string ("base64", "hex", "binary", defaults to "utf8") - * @param {number=} offset Offset to append at. Will use and increase {@link ByteBuffer#offset} by the number of bytes - * read if omitted. - * @returns {!ByteBuffer} this - * @expose - * @example A relative `<01 02>03.append(<04 05>)` will result in `<01 02 04 05>, 04 05|` - * @example An absolute `<01 02>03.append(04 05>, 1)` will result in `<01 04>05, 04 05|` - */ - ByteBufferPrototype.append = function(source, encoding, offset) { - if (typeof encoding === 'number' || typeof encoding !== 'string') { - offset = encoding; - encoding = undefined; - } + } + var temp = this.readVarint32(offset), + start = offset, + str; + offset += temp['length']; + temp = temp['value']; + var k = offset + temp, + sd = stringDestination(); + utfx.decodeUTF8toUTF16(function() { + return offset < k ? this.view.getUint8(offset++) : null; + }.bind(this), sd, this.noAssert); + str = sd(); + if (relative) { + this.offset = offset; + return str; + } else { + return { + 'string': str, + 'length': offset - start + }; + } + }; + + + /** + * Appends some data to this ByteBuffer. This will overwrite any contents behind the specified offset up to the appended + * data's length. + * @param {!ByteBuffer|!ArrayBuffer|!Uint8Array|string} source Data to append. If `source` is a ByteBuffer, its offsets + * will be modified according to the performed read operation. + * @param {(string|number)=} encoding Encoding if `data` is a string ("base64", "hex", "binary", defaults to "utf8") + * @param {number=} offset Offset to append at. Will use and increase {@link ByteBuffer#offset} by the number of bytes + * read if omitted. + * @returns {!ByteBuffer} this + * @expose + * @example A relative `<01 02>03.append(<04 05>)` will result in `<01 02 04 05>, 04 05|` + * @example An absolute `<01 02>03.append(04 05>, 1)` will result in `<01 04>05, 04 05|` + */ + ByteBufferPrototype.append = function(source, encoding, offset) { + if (typeof encoding === 'number' || typeof encoding !== 'string') { + offset = encoding; + encoding = undefined; + } var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; - if (!this.noAssert) { + if (!this.noAssert) { if (typeof offset !== 'number' || offset % 1 !== 0) throw TypeError("Illegal offset: "+offset+" (not an integer)"); offset >>>= 0; if (offset < 0 || offset + 0 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.byteLength); - } - if (!(source instanceof ByteBuffer)) - source = ByteBuffer.wrap(source, encoding); - var length = source.limit - source.offset; - if (length <= 0) return this; // Nothing to append + } + if (!(source instanceof ByteBuffer)) + source = ByteBuffer.wrap(source, encoding); + var length = source.limit - source.offset; + if (length <= 0) return this; // Nothing to append offset += length; var capacity16 = this.buffer.byteLength; if (offset > capacity16) this.resize((capacity16 *= 2) > offset ? capacity16 : offset); offset -= length; - new Uint8Array(this.buffer, offset).set(new Uint8Array(source.buffer).subarray(source.offset, source.limit)); - source.offset += length; + new Uint8Array(this.buffer, offset).set(new Uint8Array(source.buffer).subarray(source.offset, source.limit)); + source.offset += length; if (relative) this.offset += length; - return this; - }; - - /** - * Appends this ByteBuffer's contents to another ByteBuffer. This will overwrite any contents at and after the - specified offset up to the length of this ByteBuffer's data. - * @param {!ByteBuffer} target Target ByteBuffer - * @param {number=} offset Offset to append to. Will use and increase {@link ByteBuffer#offset} by the number of bytes - * read if omitted. - * @returns {!ByteBuffer} this - * @expose - * @see ByteBuffer#append - */ - ByteBufferPrototype.appendTo = function(target, offset) { - target.append(this, offset); - return this; - }; - - /** - * Enables or disables assertions of argument types and offsets. Assertions are enabled by default but you can opt to - * disable them if your code already makes sure that everything is valid. - * @param {boolean} assert `true` to enable assertions, otherwise `false` - * @returns {!ByteBuffer} this - * @expose - */ - ByteBufferPrototype.assert = function(assert) { - this.noAssert = !assert; - return this; - }; - - /** - * Gets the capacity of this ByteBuffer's backing buffer. - * @returns {number} Capacity of the backing buffer - * @expose - */ - ByteBufferPrototype.capacity = function() { - return this.buffer.byteLength; - }; - - /** - * Clears this ByteBuffer's offsets by setting {@link ByteBuffer#offset} to `0` and {@link ByteBuffer#limit} to the - * backing buffer's capacity. Discards {@link ByteBuffer#markedOffset}. - * @returns {!ByteBuffer} this - * @expose - */ - ByteBufferPrototype.clear = function() { - this.offset = 0; - this.limit = this.buffer.byteLength; - this.markedOffset = -1; - return this; - }; - - /** - * Creates a cloned instance of this ByteBuffer, preset with this ByteBuffer's values for {@link ByteBuffer#offset}, - * {@link ByteBuffer#markedOffset} and {@link ByteBuffer#limit}. - * @param {boolean=} copy Whether to copy the backing buffer or to return another view on the same, defaults to `false` - * @returns {!ByteBuffer} Cloned instance - * @expose - */ - ByteBufferPrototype.clone = function(copy) { - var bb = new ByteBuffer(0, this.littleEndian, this.noAssert); - if (copy) { - var buffer = new ArrayBuffer(this.buffer.byteLength); - new Uint8Array(buffer).set(this.buffer); - bb.buffer = buffer; - bb.view = new DataView(buffer); - } else { - bb.buffer = this.buffer; - bb.view = this.view; - } - bb.offset = this.offset; - bb.markedOffset = this.markedOffset; - bb.limit = this.limit; - return bb; - }; - - /** - * Compacts this ByteBuffer to be backed by a {@link ByteBuffer#buffer} of its contents' length. Contents are the bytes - * between {@link ByteBuffer#offset} and {@link ByteBuffer#limit}. Will set `offset = 0` and `limit = capacity` and - * adapt {@link ByteBuffer#markedOffset} to the same relative position if set. - * @param {number=} begin Offset to start at, defaults to {@link ByteBuffer#offset} - * @param {number=} end Offset to end at, defaults to {@link ByteBuffer#limit} - * @returns {!ByteBuffer} this - * @expose - */ - ByteBufferPrototype.compact = function(begin, end) { - if (typeof begin === 'undefined') begin = this.offset; - if (typeof end === 'undefined') end = this.limit; - if (!this.noAssert) { + return this; + }; + + /** + * Appends this ByteBuffer's contents to another ByteBuffer. This will overwrite any contents at and after the + specified offset up to the length of this ByteBuffer's data. + * @param {!ByteBuffer} target Target ByteBuffer + * @param {number=} offset Offset to append to. Will use and increase {@link ByteBuffer#offset} by the number of bytes + * read if omitted. + * @returns {!ByteBuffer} this + * @expose + * @see ByteBuffer#append + */ + ByteBufferPrototype.appendTo = function(target, offset) { + target.append(this, offset); + return this; + }; + + /** + * Enables or disables assertions of argument types and offsets. Assertions are enabled by default but you can opt to + * disable them if your code already makes sure that everything is valid. + * @param {boolean} assert `true` to enable assertions, otherwise `false` + * @returns {!ByteBuffer} this + * @expose + */ + ByteBufferPrototype.assert = function(assert) { + this.noAssert = !assert; + return this; + }; + + /** + * Gets the capacity of this ByteBuffer's backing buffer. + * @returns {number} Capacity of the backing buffer + * @expose + */ + ByteBufferPrototype.capacity = function() { + return this.buffer.byteLength; + }; + + /** + * Clears this ByteBuffer's offsets by setting {@link ByteBuffer#offset} to `0` and {@link ByteBuffer#limit} to the + * backing buffer's capacity. Discards {@link ByteBuffer#markedOffset}. + * @returns {!ByteBuffer} this + * @expose + */ + ByteBufferPrototype.clear = function() { + this.offset = 0; + this.limit = this.buffer.byteLength; + this.markedOffset = -1; + return this; + }; + + /** + * Creates a cloned instance of this ByteBuffer, preset with this ByteBuffer's values for {@link ByteBuffer#offset}, + * {@link ByteBuffer#markedOffset} and {@link ByteBuffer#limit}. + * @param {boolean=} copy Whether to copy the backing buffer or to return another view on the same, defaults to `false` + * @returns {!ByteBuffer} Cloned instance + * @expose + */ + ByteBufferPrototype.clone = function(copy) { + var bb = new ByteBuffer(0, this.littleEndian, this.noAssert); + if (copy) { + var buffer = new ArrayBuffer(this.buffer.byteLength); + new Uint8Array(buffer).set(this.buffer); + bb.buffer = buffer; + bb.view = new DataView(buffer); + } else { + bb.buffer = this.buffer; + bb.view = this.view; + } + bb.offset = this.offset; + bb.markedOffset = this.markedOffset; + bb.limit = this.limit; + return bb; + }; + + /** + * Compacts this ByteBuffer to be backed by a {@link ByteBuffer#buffer} of its contents' length. Contents are the bytes + * between {@link ByteBuffer#offset} and {@link ByteBuffer#limit}. Will set `offset = 0` and `limit = capacity` and + * adapt {@link ByteBuffer#markedOffset} to the same relative position if set. + * @param {number=} begin Offset to start at, defaults to {@link ByteBuffer#offset} + * @param {number=} end Offset to end at, defaults to {@link ByteBuffer#limit} + * @returns {!ByteBuffer} this + * @expose + */ + ByteBufferPrototype.compact = function(begin, end) { + if (typeof begin === 'undefined') begin = this.offset; + if (typeof end === 'undefined') end = this.limit; + if (!this.noAssert) { if (typeof begin !== 'number' || begin % 1 !== 0) throw TypeError("Illegal begin: Not an integer"); begin >>>= 0; @@ -28732,40 +28718,40 @@ Curve25519Worker.prototype = { end >>>= 0; if (begin < 0 || begin > end || end > this.buffer.byteLength) throw RangeError("Illegal range: 0 <= "+begin+" <= "+end+" <= "+this.buffer.byteLength); - } - if (begin === 0 && end === this.buffer.byteLength) - return this; // Already compacted - var len = end - begin; - if (len === 0) { - this.buffer = EMPTY_BUFFER; - this.view = null; - if (this.markedOffset >= 0) this.markedOffset -= begin; - this.offset = 0; - this.limit = 0; - return this; - } - var buffer = new ArrayBuffer(len); - new Uint8Array(buffer).set(new Uint8Array(this.buffer).subarray(begin, end)); - this.buffer = buffer; - this.view = new DataView(buffer); - if (this.markedOffset >= 0) this.markedOffset -= begin; - this.offset = 0; - this.limit = len; - return this; - }; - - /** - * Creates a copy of this ByteBuffer's contents. Contents are the bytes between {@link ByteBuffer#offset} and - * {@link ByteBuffer#limit}. - * @param {number=} begin Begin offset, defaults to {@link ByteBuffer#offset}. - * @param {number=} end End offset, defaults to {@link ByteBuffer#limit}. - * @returns {!ByteBuffer} Copy - * @expose - */ - ByteBufferPrototype.copy = function(begin, end) { - if (typeof begin === 'undefined') begin = this.offset; - if (typeof end === 'undefined') end = this.limit; - if (!this.noAssert) { + } + if (begin === 0 && end === this.buffer.byteLength) + return this; // Already compacted + var len = end - begin; + if (len === 0) { + this.buffer = EMPTY_BUFFER; + this.view = null; + if (this.markedOffset >= 0) this.markedOffset -= begin; + this.offset = 0; + this.limit = 0; + return this; + } + var buffer = new ArrayBuffer(len); + new Uint8Array(buffer).set(new Uint8Array(this.buffer).subarray(begin, end)); + this.buffer = buffer; + this.view = new DataView(buffer); + if (this.markedOffset >= 0) this.markedOffset -= begin; + this.offset = 0; + this.limit = len; + return this; + }; + + /** + * Creates a copy of this ByteBuffer's contents. Contents are the bytes between {@link ByteBuffer#offset} and + * {@link ByteBuffer#limit}. + * @param {number=} begin Begin offset, defaults to {@link ByteBuffer#offset}. + * @param {number=} end End offset, defaults to {@link ByteBuffer#limit}. + * @returns {!ByteBuffer} Copy + * @expose + */ + ByteBufferPrototype.copy = function(begin, end) { + if (typeof begin === 'undefined') begin = this.offset; + if (typeof end === 'undefined') end = this.limit; + if (!this.noAssert) { if (typeof begin !== 'number' || begin % 1 !== 0) throw TypeError("Illegal begin: Not an integer"); begin >>>= 0; @@ -28774,94 +28760,94 @@ Curve25519Worker.prototype = { end >>>= 0; if (begin < 0 || begin > end || end > this.buffer.byteLength) throw RangeError("Illegal range: 0 <= "+begin+" <= "+end+" <= "+this.buffer.byteLength); - } - if (begin === end) - return new ByteBuffer(0, this.littleEndian, this.noAssert); - var capacity = end - begin, - bb = new ByteBuffer(capacity, this.littleEndian, this.noAssert); - bb.offset = 0; - bb.limit = capacity; - if (bb.markedOffset >= 0) bb.markedOffset -= begin; - this.copyTo(bb, 0, begin, end); - return bb; - }; - - /** - * Copies this ByteBuffer's contents to another ByteBuffer. Contents are the bytes between {@link ByteBuffer#offset} and - * {@link ByteBuffer#limit}. - * @param {!ByteBuffer} target Target ByteBuffer - * @param {number=} targetOffset Offset to copy to. Will use and increase the target's {@link ByteBuffer#offset} - * by the number of bytes copied if omitted. - * @param {number=} sourceOffset Offset to start copying from. Will use and increase {@link ByteBuffer#offset} by the - * number of bytes copied if omitted. - * @param {number=} sourceLimit Offset to end copying from, defaults to {@link ByteBuffer#limit} - * @returns {!ByteBuffer} this - * @expose - */ - ByteBufferPrototype.copyTo = function(target, targetOffset, sourceOffset, sourceLimit) { - var relative, - targetRelative; - if (!this.noAssert) { - if (!ByteBuffer.isByteBuffer(target)) - throw TypeError("Illegal target: Not a ByteBuffer"); - } - targetOffset = (targetRelative = typeof targetOffset === 'undefined') ? target.offset : targetOffset | 0; - sourceOffset = (relative = typeof sourceOffset === 'undefined') ? this.offset : sourceOffset | 0; - sourceLimit = typeof sourceLimit === 'undefined' ? this.limit : sourceLimit | 0; - - if (targetOffset < 0 || targetOffset > target.buffer.byteLength) - throw RangeError("Illegal target range: 0 <= "+targetOffset+" <= "+target.buffer.byteLength); - if (sourceOffset < 0 || sourceLimit > this.buffer.byteLength) - throw RangeError("Illegal source range: 0 <= "+sourceOffset+" <= "+this.buffer.byteLength); - - var len = sourceLimit - sourceOffset; - if (len === 0) - return target; // Nothing to copy - - target.ensureCapacity(targetOffset + len); - - new Uint8Array(target.buffer).set(new Uint8Array(this.buffer).subarray(sourceOffset, sourceLimit), targetOffset); - - if (relative) this.offset += len; - if (targetRelative) target.offset += len; - - return this; - }; - - /** - * Makes sure that this ByteBuffer is backed by a {@link ByteBuffer#buffer} of at least the specified capacity. If the - * current capacity is exceeded, it will be doubled. If double the current capacity is less than the required capacity, - * the required capacity will be used instead. - * @param {number} capacity Required capacity - * @returns {!ByteBuffer} this - * @expose - */ - ByteBufferPrototype.ensureCapacity = function(capacity) { - var current = this.buffer.byteLength; - if (current < capacity) - return this.resize((current *= 2) > capacity ? current : capacity); - return this; - }; - - /** - * Overwrites this ByteBuffer's contents with the specified value. Contents are the bytes between - * {@link ByteBuffer#offset} and {@link ByteBuffer#limit}. - * @param {number|string} value Byte value to fill with. If given as a string, the first character is used. - * @param {number=} begin Begin offset. Will use and increase {@link ByteBuffer#offset} by the number of bytes - * written if omitted. defaults to {@link ByteBuffer#offset}. - * @param {number=} end End offset, defaults to {@link ByteBuffer#limit}. - * @returns {!ByteBuffer} this - * @expose - * @example `someByteBuffer.clear().fill(0)` fills the entire backing buffer with zeroes - */ - ByteBufferPrototype.fill = function(value, begin, end) { + } + if (begin === end) + return new ByteBuffer(0, this.littleEndian, this.noAssert); + var capacity = end - begin, + bb = new ByteBuffer(capacity, this.littleEndian, this.noAssert); + bb.offset = 0; + bb.limit = capacity; + if (bb.markedOffset >= 0) bb.markedOffset -= begin; + this.copyTo(bb, 0, begin, end); + return bb; + }; + + /** + * Copies this ByteBuffer's contents to another ByteBuffer. Contents are the bytes between {@link ByteBuffer#offset} and + * {@link ByteBuffer#limit}. + * @param {!ByteBuffer} target Target ByteBuffer + * @param {number=} targetOffset Offset to copy to. Will use and increase the target's {@link ByteBuffer#offset} + * by the number of bytes copied if omitted. + * @param {number=} sourceOffset Offset to start copying from. Will use and increase {@link ByteBuffer#offset} by the + * number of bytes copied if omitted. + * @param {number=} sourceLimit Offset to end copying from, defaults to {@link ByteBuffer#limit} + * @returns {!ByteBuffer} this + * @expose + */ + ByteBufferPrototype.copyTo = function(target, targetOffset, sourceOffset, sourceLimit) { + var relative, + targetRelative; + if (!this.noAssert) { + if (!ByteBuffer.isByteBuffer(target)) + throw TypeError("Illegal target: Not a ByteBuffer"); + } + targetOffset = (targetRelative = typeof targetOffset === 'undefined') ? target.offset : targetOffset | 0; + sourceOffset = (relative = typeof sourceOffset === 'undefined') ? this.offset : sourceOffset | 0; + sourceLimit = typeof sourceLimit === 'undefined' ? this.limit : sourceLimit | 0; + + if (targetOffset < 0 || targetOffset > target.buffer.byteLength) + throw RangeError("Illegal target range: 0 <= "+targetOffset+" <= "+target.buffer.byteLength); + if (sourceOffset < 0 || sourceLimit > this.buffer.byteLength) + throw RangeError("Illegal source range: 0 <= "+sourceOffset+" <= "+this.buffer.byteLength); + + var len = sourceLimit - sourceOffset; + if (len === 0) + return target; // Nothing to copy + + target.ensureCapacity(targetOffset + len); + + new Uint8Array(target.buffer).set(new Uint8Array(this.buffer).subarray(sourceOffset, sourceLimit), targetOffset); + + if (relative) this.offset += len; + if (targetRelative) target.offset += len; + + return this; + }; + + /** + * Makes sure that this ByteBuffer is backed by a {@link ByteBuffer#buffer} of at least the specified capacity. If the + * current capacity is exceeded, it will be doubled. If double the current capacity is less than the required capacity, + * the required capacity will be used instead. + * @param {number} capacity Required capacity + * @returns {!ByteBuffer} this + * @expose + */ + ByteBufferPrototype.ensureCapacity = function(capacity) { + var current = this.buffer.byteLength; + if (current < capacity) + return this.resize((current *= 2) > capacity ? current : capacity); + return this; + }; + + /** + * Overwrites this ByteBuffer's contents with the specified value. Contents are the bytes between + * {@link ByteBuffer#offset} and {@link ByteBuffer#limit}. + * @param {number|string} value Byte value to fill with. If given as a string, the first character is used. + * @param {number=} begin Begin offset. Will use and increase {@link ByteBuffer#offset} by the number of bytes + * written if omitted. defaults to {@link ByteBuffer#offset}. + * @param {number=} end End offset, defaults to {@link ByteBuffer#limit}. + * @returns {!ByteBuffer} this + * @expose + * @example `someByteBuffer.clear().fill(0)` fills the entire backing buffer with zeroes + */ + ByteBufferPrototype.fill = function(value, begin, end) { var relative = typeof begin === 'undefined'; if (relative) begin = this.offset; - if (typeof value === 'string' && value.length > 0) - value = value.charCodeAt(0); - if (typeof begin === 'undefined') begin = this.offset; - if (typeof end === 'undefined') end = this.limit; - if (!this.noAssert) { + if (typeof value === 'string' && value.length > 0) + value = value.charCodeAt(0); + if (typeof begin === 'undefined') begin = this.offset; + if (typeof end === 'undefined') end = this.limit; + if (!this.noAssert) { if (typeof value !== 'number' || value % 1 !== 0) throw TypeError("Illegal value: "+value+" (not an integer)"); value |= 0; @@ -28873,227 +28859,227 @@ Curve25519Worker.prototype = { end >>>= 0; if (begin < 0 || begin > end || end > this.buffer.byteLength) throw RangeError("Illegal range: 0 <= "+begin+" <= "+end+" <= "+this.buffer.byteLength); - } - if (begin >= end) - return this; // Nothing to fill - while (begin < end) this.view.setUint8(begin++, value); - if (relative) this.offset = begin; - return this; - }; - - /** - * Makes this ByteBuffer ready for a new sequence of write or relative read operations. Sets `limit = offset` and - * `offset = 0`. Make sure always to flip a ByteBuffer when all relative read or write operations are complete. - * @returns {!ByteBuffer} this - * @expose - */ - ByteBufferPrototype.flip = function() { - this.limit = this.offset; - this.offset = 0; - return this; - }; - /** - * Marks an offset on this ByteBuffer to be used later. - * @param {number=} offset Offset to mark. Defaults to {@link ByteBuffer#offset}. - * @returns {!ByteBuffer} this - * @throws {TypeError} If `offset` is not a valid number - * @throws {RangeError} If `offset` is out of bounds - * @see ByteBuffer#reset - * @expose - */ - ByteBufferPrototype.mark = function(offset) { - offset = typeof offset === 'undefined' ? this.offset : offset; - if (!this.noAssert) { + } + if (begin >= end) + return this; // Nothing to fill + while (begin < end) this.view.setUint8(begin++, value); + if (relative) this.offset = begin; + return this; + }; + + /** + * Makes this ByteBuffer ready for a new sequence of write or relative read operations. Sets `limit = offset` and + * `offset = 0`. Make sure always to flip a ByteBuffer when all relative read or write operations are complete. + * @returns {!ByteBuffer} this + * @expose + */ + ByteBufferPrototype.flip = function() { + this.limit = this.offset; + this.offset = 0; + return this; + }; + /** + * Marks an offset on this ByteBuffer to be used later. + * @param {number=} offset Offset to mark. Defaults to {@link ByteBuffer#offset}. + * @returns {!ByteBuffer} this + * @throws {TypeError} If `offset` is not a valid number + * @throws {RangeError} If `offset` is out of bounds + * @see ByteBuffer#reset + * @expose + */ + ByteBufferPrototype.mark = function(offset) { + offset = typeof offset === 'undefined' ? this.offset : offset; + if (!this.noAssert) { if (typeof offset !== 'number' || offset % 1 !== 0) throw TypeError("Illegal offset: "+offset+" (not an integer)"); offset >>>= 0; if (offset < 0 || offset + 0 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.byteLength); - } - this.markedOffset = offset; - return this; - }; - /** - * Sets the byte order. - * @param {boolean} littleEndian `true` for little endian byte order, `false` for big endian - * @returns {!ByteBuffer} this - * @expose - */ - ByteBufferPrototype.order = function(littleEndian) { - if (!this.noAssert) { - if (typeof littleEndian !== 'boolean') - throw TypeError("Illegal littleEndian: Not a boolean"); - } - this.littleEndian = !!littleEndian; - return this; - }; - - /** - * Switches (to) little endian byte order. - * @param {boolean=} littleEndian Defaults to `true`, otherwise uses big endian - * @returns {!ByteBuffer} this - * @expose - */ - ByteBufferPrototype.LE = function(littleEndian) { - this.littleEndian = typeof littleEndian !== 'undefined' ? !!littleEndian : true; - return this; - }; - - /** - * Switches (to) big endian byte order. - * @param {boolean=} bigEndian Defaults to `true`, otherwise uses little endian - * @returns {!ByteBuffer} this - * @expose - */ - ByteBufferPrototype.BE = function(bigEndian) { - this.littleEndian = typeof bigEndian !== 'undefined' ? !bigEndian : false; - return this; - }; - /** - * Prepends some data to this ByteBuffer. This will overwrite any contents before the specified offset up to the - * prepended data's length. If there is not enough space available before the specified `offset`, the backing buffer - * will be resized and its contents moved accordingly. - * @param {!ByteBuffer|string|!ArrayBuffer} source Data to prepend. If `source` is a ByteBuffer, its offset will be - * modified according to the performed read operation. - * @param {(string|number)=} encoding Encoding if `data` is a string ("base64", "hex", "binary", defaults to "utf8") - * @param {number=} offset Offset to prepend at. Will use and decrease {@link ByteBuffer#offset} by the number of bytes - * prepended if omitted. - * @returns {!ByteBuffer} this - * @expose - * @example A relative `00<01 02 03>.prepend(<04 05>)` results in `<04 05 01 02 03>, 04 05|` - * @example An absolute `00<01 02 03>.prepend(<04 05>, 2)` results in `04<05 02 03>, 04 05|` - */ - ByteBufferPrototype.prepend = function(source, encoding, offset) { - if (typeof encoding === 'number' || typeof encoding !== 'string') { - offset = encoding; - encoding = undefined; - } + } + this.markedOffset = offset; + return this; + }; + /** + * Sets the byte order. + * @param {boolean} littleEndian `true` for little endian byte order, `false` for big endian + * @returns {!ByteBuffer} this + * @expose + */ + ByteBufferPrototype.order = function(littleEndian) { + if (!this.noAssert) { + if (typeof littleEndian !== 'boolean') + throw TypeError("Illegal littleEndian: Not a boolean"); + } + this.littleEndian = !!littleEndian; + return this; + }; + + /** + * Switches (to) little endian byte order. + * @param {boolean=} littleEndian Defaults to `true`, otherwise uses big endian + * @returns {!ByteBuffer} this + * @expose + */ + ByteBufferPrototype.LE = function(littleEndian) { + this.littleEndian = typeof littleEndian !== 'undefined' ? !!littleEndian : true; + return this; + }; + + /** + * Switches (to) big endian byte order. + * @param {boolean=} bigEndian Defaults to `true`, otherwise uses little endian + * @returns {!ByteBuffer} this + * @expose + */ + ByteBufferPrototype.BE = function(bigEndian) { + this.littleEndian = typeof bigEndian !== 'undefined' ? !bigEndian : false; + return this; + }; + /** + * Prepends some data to this ByteBuffer. This will overwrite any contents before the specified offset up to the + * prepended data's length. If there is not enough space available before the specified `offset`, the backing buffer + * will be resized and its contents moved accordingly. + * @param {!ByteBuffer|string|!ArrayBuffer} source Data to prepend. If `source` is a ByteBuffer, its offset will be + * modified according to the performed read operation. + * @param {(string|number)=} encoding Encoding if `data` is a string ("base64", "hex", "binary", defaults to "utf8") + * @param {number=} offset Offset to prepend at. Will use and decrease {@link ByteBuffer#offset} by the number of bytes + * prepended if omitted. + * @returns {!ByteBuffer} this + * @expose + * @example A relative `00<01 02 03>.prepend(<04 05>)` results in `<04 05 01 02 03>, 04 05|` + * @example An absolute `00<01 02 03>.prepend(<04 05>, 2)` results in `04<05 02 03>, 04 05|` + */ + ByteBufferPrototype.prepend = function(source, encoding, offset) { + if (typeof encoding === 'number' || typeof encoding !== 'string') { + offset = encoding; + encoding = undefined; + } var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; - if (!this.noAssert) { + if (!this.noAssert) { if (typeof offset !== 'number' || offset % 1 !== 0) throw TypeError("Illegal offset: "+offset+" (not an integer)"); offset >>>= 0; if (offset < 0 || offset + 0 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.byteLength); - } - if (!(source instanceof ByteBuffer)) - source = ByteBuffer.wrap(source, encoding); - var len = source.limit - source.offset; - if (len <= 0) return this; // Nothing to prepend - var diff = len - offset; - var arrayView; - if (diff > 0) { // Not enough space before offset, so resize + move - var buffer = new ArrayBuffer(this.buffer.byteLength + diff); - arrayView = new Uint8Array(buffer); - arrayView.set(new Uint8Array(this.buffer).subarray(offset, this.buffer.byteLength), len); - this.buffer = buffer; - this.view = new DataView(buffer); - this.offset += diff; - if (this.markedOffset >= 0) this.markedOffset += diff; - this.limit += diff; - offset += diff; - } else { - arrayView = new Uint8Array(this.buffer); - } - arrayView.set(new Uint8Array(source.buffer).subarray(source.offset, source.limit), offset - len); - source.offset = source.limit; - if (relative) - this.offset -= len; - return this; - }; - - /** - * Prepends this ByteBuffer to another ByteBuffer. This will overwrite any contents before the specified offset up to the - * prepended data's length. If there is not enough space available before the specified `offset`, the backing buffer - * will be resized and its contents moved accordingly. - * @param {!ByteBuffer} target Target ByteBuffer - * @param {number=} offset Offset to prepend at. Will use and decrease {@link ByteBuffer#offset} by the number of bytes - * prepended if omitted. - * @returns {!ByteBuffer} this - * @expose - * @see ByteBuffer#prepend - */ - ByteBufferPrototype.prependTo = function(target, offset) { - target.prepend(this, offset); - return this; - }; - /** - * Prints debug information about this ByteBuffer's contents. - * @param {function(string)=} out Output function to call, defaults to console.log - * @expose - */ - ByteBufferPrototype.printDebug = function(out) { - if (typeof out !== 'function') out = console.log.bind(console); - out( - this.toString()+"\n"+ - "-------------------------------------------------------------------\n"+ - this.toDebug(/* columns */ true) - ); - }; - - /** - * Gets the number of remaining readable bytes. Contents are the bytes between {@link ByteBuffer#offset} and - * {@link ByteBuffer#limit}, so this returns `limit - offset`. - * @returns {number} Remaining readable bytes. May be negative if `offset > limit`. - * @expose - */ - ByteBufferPrototype.remaining = function() { - return this.limit - this.offset; - }; - /** - * Resets this ByteBuffer's {@link ByteBuffer#offset}. If an offset has been marked through {@link ByteBuffer#mark} - * before, `offset` will be set to {@link ByteBuffer#markedOffset}, which will then be discarded. If no offset has been - * marked, sets `offset = 0`. - * @returns {!ByteBuffer} this - * @see ByteBuffer#mark - * @expose - */ - ByteBufferPrototype.reset = function() { - if (this.markedOffset >= 0) { - this.offset = this.markedOffset; - this.markedOffset = -1; - } else { - this.offset = 0; - } - return this; - }; - /** - * Resizes this ByteBuffer to be backed by a buffer of at least the given capacity. Will do nothing if already that - * large or larger. - * @param {number} capacity Capacity required - * @returns {!ByteBuffer} this - * @throws {TypeError} If `capacity` is not a number - * @throws {RangeError} If `capacity < 0` - * @expose - */ - ByteBufferPrototype.resize = function(capacity) { - if (!this.noAssert) { + } + if (!(source instanceof ByteBuffer)) + source = ByteBuffer.wrap(source, encoding); + var len = source.limit - source.offset; + if (len <= 0) return this; // Nothing to prepend + var diff = len - offset; + var arrayView; + if (diff > 0) { // Not enough space before offset, so resize + move + var buffer = new ArrayBuffer(this.buffer.byteLength + diff); + arrayView = new Uint8Array(buffer); + arrayView.set(new Uint8Array(this.buffer).subarray(offset, this.buffer.byteLength), len); + this.buffer = buffer; + this.view = new DataView(buffer); + this.offset += diff; + if (this.markedOffset >= 0) this.markedOffset += diff; + this.limit += diff; + offset += diff; + } else { + arrayView = new Uint8Array(this.buffer); + } + arrayView.set(new Uint8Array(source.buffer).subarray(source.offset, source.limit), offset - len); + source.offset = source.limit; + if (relative) + this.offset -= len; + return this; + }; + + /** + * Prepends this ByteBuffer to another ByteBuffer. This will overwrite any contents before the specified offset up to the + * prepended data's length. If there is not enough space available before the specified `offset`, the backing buffer + * will be resized and its contents moved accordingly. + * @param {!ByteBuffer} target Target ByteBuffer + * @param {number=} offset Offset to prepend at. Will use and decrease {@link ByteBuffer#offset} by the number of bytes + * prepended if omitted. + * @returns {!ByteBuffer} this + * @expose + * @see ByteBuffer#prepend + */ + ByteBufferPrototype.prependTo = function(target, offset) { + target.prepend(this, offset); + return this; + }; + /** + * Prints debug information about this ByteBuffer's contents. + * @param {function(string)=} out Output function to call, defaults to console.log + * @expose + */ + ByteBufferPrototype.printDebug = function(out) { + if (typeof out !== 'function') out = console.log.bind(console); + out( + this.toString()+"\n"+ + "-------------------------------------------------------------------\n"+ + this.toDebug(/* columns */ true) + ); + }; + + /** + * Gets the number of remaining readable bytes. Contents are the bytes between {@link ByteBuffer#offset} and + * {@link ByteBuffer#limit}, so this returns `limit - offset`. + * @returns {number} Remaining readable bytes. May be negative if `offset > limit`. + * @expose + */ + ByteBufferPrototype.remaining = function() { + return this.limit - this.offset; + }; + /** + * Resets this ByteBuffer's {@link ByteBuffer#offset}. If an offset has been marked through {@link ByteBuffer#mark} + * before, `offset` will be set to {@link ByteBuffer#markedOffset}, which will then be discarded. If no offset has been + * marked, sets `offset = 0`. + * @returns {!ByteBuffer} this + * @see ByteBuffer#mark + * @expose + */ + ByteBufferPrototype.reset = function() { + if (this.markedOffset >= 0) { + this.offset = this.markedOffset; + this.markedOffset = -1; + } else { + this.offset = 0; + } + return this; + }; + /** + * Resizes this ByteBuffer to be backed by a buffer of at least the given capacity. Will do nothing if already that + * large or larger. + * @param {number} capacity Capacity required + * @returns {!ByteBuffer} this + * @throws {TypeError} If `capacity` is not a number + * @throws {RangeError} If `capacity < 0` + * @expose + */ + ByteBufferPrototype.resize = function(capacity) { + if (!this.noAssert) { if (typeof capacity !== 'number' || capacity % 1 !== 0) throw TypeError("Illegal capacity: "+capacity+" (not an integer)"); capacity |= 0; - if (capacity < 0) - throw RangeError("Illegal capacity: 0 <= "+capacity); - } - if (this.buffer.byteLength < capacity) { - var buffer = new ArrayBuffer(capacity); - new Uint8Array(buffer).set(new Uint8Array(this.buffer)); - this.buffer = buffer; - this.view = new DataView(buffer); - } - return this; - }; - /** - * Reverses this ByteBuffer's contents. - * @param {number=} begin Offset to start at, defaults to {@link ByteBuffer#offset} - * @param {number=} end Offset to end at, defaults to {@link ByteBuffer#limit} - * @returns {!ByteBuffer} this - * @expose - */ - ByteBufferPrototype.reverse = function(begin, end) { - if (typeof begin === 'undefined') begin = this.offset; - if (typeof end === 'undefined') end = this.limit; - if (!this.noAssert) { + if (capacity < 0) + throw RangeError("Illegal capacity: 0 <= "+capacity); + } + if (this.buffer.byteLength < capacity) { + var buffer = new ArrayBuffer(capacity); + new Uint8Array(buffer).set(new Uint8Array(this.buffer)); + this.buffer = buffer; + this.view = new DataView(buffer); + } + return this; + }; + /** + * Reverses this ByteBuffer's contents. + * @param {number=} begin Offset to start at, defaults to {@link ByteBuffer#offset} + * @param {number=} end Offset to end at, defaults to {@link ByteBuffer#limit} + * @returns {!ByteBuffer} this + * @expose + */ + ByteBufferPrototype.reverse = function(begin, end) { + if (typeof begin === 'undefined') begin = this.offset; + if (typeof end === 'undefined') end = this.limit; + if (!this.noAssert) { if (typeof begin !== 'number' || begin % 1 !== 0) throw TypeError("Illegal begin: Not an integer"); begin >>>= 0; @@ -29102,45 +29088,45 @@ Curve25519Worker.prototype = { end >>>= 0; if (begin < 0 || begin > end || end > this.buffer.byteLength) throw RangeError("Illegal range: 0 <= "+begin+" <= "+end+" <= "+this.buffer.byteLength); - } - if (begin === end) - return this; // Nothing to reverse - Array.prototype.reverse.call(new Uint8Array(this.buffer).subarray(begin, end)); - this.view = new DataView(this.buffer); // FIXME: Why exactly is this necessary? - return this; - }; - /** - * Skips the next `length` bytes. This will just advance - * @param {number} length Number of bytes to skip. May also be negative to move the offset back. - * @returns {!ByteBuffer} this - * @expose - */ - ByteBufferPrototype.skip = function(length) { - if (!this.noAssert) { + } + if (begin === end) + return this; // Nothing to reverse + Array.prototype.reverse.call(new Uint8Array(this.buffer).subarray(begin, end)); + this.view = new DataView(this.buffer); // FIXME: Why exactly is this necessary? + return this; + }; + /** + * Skips the next `length` bytes. This will just advance + * @param {number} length Number of bytes to skip. May also be negative to move the offset back. + * @returns {!ByteBuffer} this + * @expose + */ + ByteBufferPrototype.skip = function(length) { + if (!this.noAssert) { if (typeof length !== 'number' || length % 1 !== 0) throw TypeError("Illegal length: "+length+" (not an integer)"); length |= 0; - } - var offset = this.offset + length; - if (!this.noAssert) { - if (offset < 0 || offset > this.buffer.byteLength) - throw RangeError("Illegal length: 0 <= "+this.offset+" + "+length+" <= "+this.buffer.byteLength); - } - this.offset = offset; - return this; - }; - - /** - * Slices this ByteBuffer by creating a cloned instance with `offset = begin` and `limit = end`. - * @param {number=} begin Begin offset, defaults to {@link ByteBuffer#offset}. - * @param {number=} end End offset, defaults to {@link ByteBuffer#limit}. - * @returns {!ByteBuffer} Clone of this ByteBuffer with slicing applied, backed by the same {@link ByteBuffer#buffer} - * @expose - */ - ByteBufferPrototype.slice = function(begin, end) { - if (typeof begin === 'undefined') begin = this.offset; - if (typeof end === 'undefined') end = this.limit; - if (!this.noAssert) { + } + var offset = this.offset + length; + if (!this.noAssert) { + if (offset < 0 || offset > this.buffer.byteLength) + throw RangeError("Illegal length: 0 <= "+this.offset+" + "+length+" <= "+this.buffer.byteLength); + } + this.offset = offset; + return this; + }; + + /** + * Slices this ByteBuffer by creating a cloned instance with `offset = begin` and `limit = end`. + * @param {number=} begin Begin offset, defaults to {@link ByteBuffer#offset}. + * @param {number=} end End offset, defaults to {@link ByteBuffer#limit}. + * @returns {!ByteBuffer} Clone of this ByteBuffer with slicing applied, backed by the same {@link ByteBuffer#buffer} + * @expose + */ + ByteBufferPrototype.slice = function(begin, end) { + if (typeof begin === 'undefined') begin = this.offset; + if (typeof end === 'undefined') end = this.limit; + if (!this.noAssert) { if (typeof begin !== 'number' || begin % 1 !== 0) throw TypeError("Illegal begin: Not an integer"); begin >>>= 0; @@ -29149,30 +29135,30 @@ Curve25519Worker.prototype = { end >>>= 0; if (begin < 0 || begin > end || end > this.buffer.byteLength) throw RangeError("Illegal range: 0 <= "+begin+" <= "+end+" <= "+this.buffer.byteLength); - } - var bb = this.clone(); - bb.offset = begin; - bb.limit = end; - return bb; - }; - /** - * Returns a copy of the backing buffer that contains this ByteBuffer's contents. Contents are the bytes between - * {@link ByteBuffer#offset} and {@link ByteBuffer#limit}. Will transparently {@link ByteBuffer#flip} this - * ByteBuffer if `offset > limit` but the actual offsets remain untouched. - * @param {boolean=} forceCopy If `true` returns a copy, otherwise returns a view referencing the same memory if - * possible. Defaults to `false` - * @returns {!ArrayBuffer} Contents as an ArrayBuffer - * @expose - */ - ByteBufferPrototype.toBuffer = function(forceCopy) { - var offset = this.offset, - limit = this.limit; - if (offset > limit) { - var t = offset; - offset = limit; - limit = t; - } - if (!this.noAssert) { + } + var bb = this.clone(); + bb.offset = begin; + bb.limit = end; + return bb; + }; + /** + * Returns a copy of the backing buffer that contains this ByteBuffer's contents. Contents are the bytes between + * {@link ByteBuffer#offset} and {@link ByteBuffer#limit}. Will transparently {@link ByteBuffer#flip} this + * ByteBuffer if `offset > limit` but the actual offsets remain untouched. + * @param {boolean=} forceCopy If `true` returns a copy, otherwise returns a view referencing the same memory if + * possible. Defaults to `false` + * @returns {!ArrayBuffer} Contents as an ArrayBuffer + * @expose + */ + ByteBufferPrototype.toBuffer = function(forceCopy) { + var offset = this.offset, + limit = this.limit; + if (offset > limit) { + var t = offset; + offset = limit; + limit = t; + } + if (!this.noAssert) { if (typeof offset !== 'number' || offset % 1 !== 0) throw TypeError("Illegal offset: Not an integer"); offset >>>= 0; @@ -29181,199 +29167,199 @@ Curve25519Worker.prototype = { limit >>>= 0; if (offset < 0 || offset > limit || limit > this.buffer.byteLength) throw RangeError("Illegal range: 0 <= "+offset+" <= "+limit+" <= "+this.buffer.byteLength); - } - // NOTE: It's not possible to have another ArrayBuffer reference the same memory as the backing buffer. This is - // possible with Uint8Array#subarray only, but we have to return an ArrayBuffer by contract. So: - if (!forceCopy && offset === 0 && limit === this.buffer.byteLength) { - return this.buffer; - } - if (offset === limit) { - return EMPTY_BUFFER; - } - var buffer = new ArrayBuffer(limit - offset); - new Uint8Array(buffer).set(new Uint8Array(this.buffer).subarray(offset, limit), 0); - return buffer; - }; - - /** - * Returns a raw buffer compacted to contain this ByteBuffer's contents. Contents are the bytes between - * {@link ByteBuffer#offset} and {@link ByteBuffer#limit}. Will transparently {@link ByteBuffer#flip} this - * ByteBuffer if `offset > limit` but the actual offsets remain untouched. This is an alias of - * {@link ByteBuffer#toBuffer}. - * @function - * @param {boolean=} forceCopy If `true` returns a copy, otherwise returns a view referencing the same memory. - * Defaults to `false` - * @returns {!ArrayBuffer} Contents as an ArrayBuffer - * @expose - */ - ByteBufferPrototype.toArrayBuffer = ByteBufferPrototype.toBuffer; - - - /** - * Converts the ByteBuffer's contents to a string. - * @param {string=} encoding Output encoding. Returns an informative string representation if omitted but also allows - * direct conversion to "utf8", "hex", "base64" and "binary" encoding. "debug" returns a hex representation with - * highlighted offsets. - * @param {number=} begin Offset to begin at, defaults to {@link ByteBuffer#offset} - * @param {number=} end Offset to end at, defaults to {@link ByteBuffer#limit} - * @returns {string} String representation - * @throws {Error} If `encoding` is invalid - * @expose - */ - ByteBufferPrototype.toString = function(encoding, begin, end) { - if (typeof encoding === 'undefined') - return "ByteBufferAB(offset="+this.offset+",markedOffset="+this.markedOffset+",limit="+this.limit+",capacity="+this.capacity()+")"; - if (typeof encoding === 'number') - encoding = "utf8", - begin = encoding, - end = begin; - switch (encoding) { - case "utf8": - return this.toUTF8(begin, end); - case "base64": - return this.toBase64(begin, end); - case "hex": - return this.toHex(begin, end); - case "binary": - return this.toBinary(begin, end); - case "debug": - return this.toDebug(); - case "columns": - return this.toColumns(); - default: - throw Error("Unsupported encoding: "+encoding); - } - }; - - // lxiv-embeddable - - /** - * lxiv-embeddable (c) 2014 Daniel Wirtz - * Released under the Apache License, Version 2.0 - * see: https://github.com/dcodeIO/lxiv for details - */ - var lxiv = function() { - "use strict"; - - /** - * lxiv namespace. - * @type {!Object.} - * @exports lxiv - */ - var lxiv = {}; - - /** - * Character codes for output. - * @type {!Array.} - * @inner - */ - var aout = [ - 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, - 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 97, 98, 99, 100, 101, 102, - 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, - 119, 120, 121, 122, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 43, 47 - ]; - - /** - * Character codes for input. - * @type {!Array.} - * @inner - */ - var ain = []; - for (var i=0, k=aout.length; i>2)&0x3f]); - t = (b&0x3)<<4; - if ((b = src()) !== null) { - t |= (b>>4)&0xf; - dst(aout[(t|((b>>4)&0xf))&0x3f]); - t = (b&0xf)<<2; - if ((b = src()) !== null) - dst(aout[(t|((b>>6)&0x3))&0x3f]), - dst(aout[b&0x3f]); - else - dst(aout[t&0x3f]), - dst(61); - } else - dst(aout[t&0x3f]), - dst(61), - dst(61); - } - }; - - /** - * Decodes base64 char codes to bytes. - * @param {!function():number|null} src Characters source as a function returning the next char code respectively - * `null` if there are no more characters left. - * @param {!function(number)} dst Bytes destination as a function successively called with the next byte. - * @throws {Error} If a character code is invalid - */ - lxiv.decode = function(src, dst) { - var c, t1, t2; - function fail(c) { - throw Error("Illegal character code: "+c); - } - while ((c = src()) !== null) { - t1 = ain[c]; - if (typeof t1 === 'undefined') fail(c); - if ((c = src()) !== null) { - t2 = ain[c]; - if (typeof t2 === 'undefined') fail(c); - dst((t1<<2)>>>0|(t2&0x30)>>4); - if ((c = src()) !== null) { - t1 = ain[c]; - if (typeof t1 === 'undefined') - if (c === 61) break; else fail(c); - dst(((t2&0xf)<<4)>>>0|(t1&0x3c)>>2); - if ((c = src()) !== null) { - t2 = ain[c]; - if (typeof t2 === 'undefined') - if (c === 61) break; else fail(c); - dst(((t1&0x3)<<6)>>>0|t2); - } - } - } - } - }; - - /** - * Tests if a string is valid base64. - * @param {string} str String to test - * @returns {boolean} `true` if valid, otherwise `false` - */ - lxiv.test = function(str) { - return /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(str); - }; - - return lxiv; - }(); - - // encodings/base64 - - /** - * Encodes this ByteBuffer's contents to a base64 encoded string. - * @param {number=} begin Offset to begin at, defaults to {@link ByteBuffer#offset}. - * @param {number=} end Offset to end at, defaults to {@link ByteBuffer#limit}. - * @returns {string} Base64 encoded string - * @expose - */ - ByteBufferPrototype.toBase64 = function(begin, end) { - if (typeof begin === 'undefined') - begin = this.offset; - if (typeof end === 'undefined') - end = this.limit; - if (!this.noAssert) { + } + // NOTE: It's not possible to have another ArrayBuffer reference the same memory as the backing buffer. This is + // possible with Uint8Array#subarray only, but we have to return an ArrayBuffer by contract. So: + if (!forceCopy && offset === 0 && limit === this.buffer.byteLength) { + return this.buffer; + } + if (offset === limit) { + return EMPTY_BUFFER; + } + var buffer = new ArrayBuffer(limit - offset); + new Uint8Array(buffer).set(new Uint8Array(this.buffer).subarray(offset, limit), 0); + return buffer; + }; + + /** + * Returns a raw buffer compacted to contain this ByteBuffer's contents. Contents are the bytes between + * {@link ByteBuffer#offset} and {@link ByteBuffer#limit}. Will transparently {@link ByteBuffer#flip} this + * ByteBuffer if `offset > limit` but the actual offsets remain untouched. This is an alias of + * {@link ByteBuffer#toBuffer}. + * @function + * @param {boolean=} forceCopy If `true` returns a copy, otherwise returns a view referencing the same memory. + * Defaults to `false` + * @returns {!ArrayBuffer} Contents as an ArrayBuffer + * @expose + */ + ByteBufferPrototype.toArrayBuffer = ByteBufferPrototype.toBuffer; + + + /** + * Converts the ByteBuffer's contents to a string. + * @param {string=} encoding Output encoding. Returns an informative string representation if omitted but also allows + * direct conversion to "utf8", "hex", "base64" and "binary" encoding. "debug" returns a hex representation with + * highlighted offsets. + * @param {number=} begin Offset to begin at, defaults to {@link ByteBuffer#offset} + * @param {number=} end Offset to end at, defaults to {@link ByteBuffer#limit} + * @returns {string} String representation + * @throws {Error} If `encoding` is invalid + * @expose + */ + ByteBufferPrototype.toString = function(encoding, begin, end) { + if (typeof encoding === 'undefined') + return "ByteBufferAB(offset="+this.offset+",markedOffset="+this.markedOffset+",limit="+this.limit+",capacity="+this.capacity()+")"; + if (typeof encoding === 'number') + encoding = "utf8", + begin = encoding, + end = begin; + switch (encoding) { + case "utf8": + return this.toUTF8(begin, end); + case "base64": + return this.toBase64(begin, end); + case "hex": + return this.toHex(begin, end); + case "binary": + return this.toBinary(begin, end); + case "debug": + return this.toDebug(); + case "columns": + return this.toColumns(); + default: + throw Error("Unsupported encoding: "+encoding); + } + }; + + // lxiv-embeddable + + /** + * lxiv-embeddable (c) 2014 Daniel Wirtz + * Released under the Apache License, Version 2.0 + * see: https://github.com/dcodeIO/lxiv for details + */ + var lxiv = function() { + "use strict"; + + /** + * lxiv namespace. + * @type {!Object.} + * @exports lxiv + */ + var lxiv = {}; + + /** + * Character codes for output. + * @type {!Array.} + * @inner + */ + var aout = [ + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, + 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 97, 98, 99, 100, 101, 102, + 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, + 119, 120, 121, 122, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 43, 47 + ]; + + /** + * Character codes for input. + * @type {!Array.} + * @inner + */ + var ain = []; + for (var i=0, k=aout.length; i>2)&0x3f]); + t = (b&0x3)<<4; + if ((b = src()) !== null) { + t |= (b>>4)&0xf; + dst(aout[(t|((b>>4)&0xf))&0x3f]); + t = (b&0xf)<<2; + if ((b = src()) !== null) + dst(aout[(t|((b>>6)&0x3))&0x3f]), + dst(aout[b&0x3f]); + else + dst(aout[t&0x3f]), + dst(61); + } else + dst(aout[t&0x3f]), + dst(61), + dst(61); + } + }; + + /** + * Decodes base64 char codes to bytes. + * @param {!function():number|null} src Characters source as a function returning the next char code respectively + * `null` if there are no more characters left. + * @param {!function(number)} dst Bytes destination as a function successively called with the next byte. + * @throws {Error} If a character code is invalid + */ + lxiv.decode = function(src, dst) { + var c, t1, t2; + function fail(c) { + throw Error("Illegal character code: "+c); + } + while ((c = src()) !== null) { + t1 = ain[c]; + if (typeof t1 === 'undefined') fail(c); + if ((c = src()) !== null) { + t2 = ain[c]; + if (typeof t2 === 'undefined') fail(c); + dst((t1<<2)>>>0|(t2&0x30)>>4); + if ((c = src()) !== null) { + t1 = ain[c]; + if (typeof t1 === 'undefined') + if (c === 61) break; else fail(c); + dst(((t2&0xf)<<4)>>>0|(t1&0x3c)>>2); + if ((c = src()) !== null) { + t2 = ain[c]; + if (typeof t2 === 'undefined') + if (c === 61) break; else fail(c); + dst(((t1&0x3)<<6)>>>0|t2); + } + } + } + } + }; + + /** + * Tests if a string is valid base64. + * @param {string} str String to test + * @returns {boolean} `true` if valid, otherwise `false` + */ + lxiv.test = function(str) { + return /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(str); + }; + + return lxiv; + }(); + + // encodings/base64 + + /** + * Encodes this ByteBuffer's contents to a base64 encoded string. + * @param {number=} begin Offset to begin at, defaults to {@link ByteBuffer#offset}. + * @param {number=} end Offset to end at, defaults to {@link ByteBuffer#limit}. + * @returns {string} Base64 encoded string + * @expose + */ + ByteBufferPrototype.toBase64 = function(begin, end) { + if (typeof begin === 'undefined') + begin = this.offset; + if (typeof end === 'undefined') + end = this.limit; + if (!this.noAssert) { if (typeof begin !== 'number' || begin % 1 !== 0) throw TypeError("Illegal begin: Not an integer"); begin >>>= 0; @@ -29382,75 +29368,75 @@ Curve25519Worker.prototype = { end >>>= 0; if (begin < 0 || begin > end || end > this.buffer.byteLength) throw RangeError("Illegal range: 0 <= "+begin+" <= "+end+" <= "+this.buffer.byteLength); - } - var sd; lxiv.encode(function() { - return begin < end ? this.view.getUint8(begin++) : null; - }.bind(this), sd = stringDestination()); - return sd(); - }; - - /** - * Decodes a base64 encoded string to a ByteBuffer. - * @param {string} str String to decode - * @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} ByteBuffer - * @expose - */ - ByteBuffer.fromBase64 = function(str, littleEndian, noAssert) { - if (!noAssert) { - if (typeof str !== 'string') - throw TypeError("Illegal str: Not a string"); - if (str.length % 4 !== 0) - throw TypeError("Illegal str: Length not a multiple of 4"); - } - var bb = new ByteBuffer(str.length/4*3, littleEndian, noAssert), - i = 0; - lxiv.decode(stringSource(str), function(b) { - bb.view.setUint8(i++, b); - }); - bb.limit = i; - return bb; - }; - - /** - * Encodes a binary string to base64 like `window.btoa` does. - * @param {string} str Binary string - * @returns {string} Base64 encoded string - * @see https://developer.mozilla.org/en-US/docs/Web/API/Window.btoa - * @expose - */ - ByteBuffer.btoa = function(str) { - return ByteBuffer.fromBinary(str).toBase64(); - }; - - /** - * Decodes a base64 encoded string to binary like `window.atob` does. - * @param {string} b64 Base64 encoded string - * @returns {string} Binary string - * @see https://developer.mozilla.org/en-US/docs/Web/API/Window.atob - * @expose - */ - ByteBuffer.atob = function(b64) { - return ByteBuffer.fromBase64(b64).toBinary(); - }; - - // encodings/binary - - /** - * Encodes this ByteBuffer to a binary encoded string, that is using only characters 0x00-0xFF as bytes. - * @param {number=} begin Offset to begin at. Defaults to {@link ByteBuffer#offset}. - * @param {number=} end Offset to end at. Defaults to {@link ByteBuffer#limit}. - * @returns {string} Binary encoded string - * @throws {RangeError} If `offset > limit` - * @expose - */ - ByteBufferPrototype.toBinary = function(begin, end) { - begin = typeof begin === 'undefined' ? this.offset : begin; - end = typeof end === 'undefined' ? this.limit : end; - if (!this.noAssert) { + } + var sd; lxiv.encode(function() { + return begin < end ? this.view.getUint8(begin++) : null; + }.bind(this), sd = stringDestination()); + return sd(); + }; + + /** + * Decodes a base64 encoded string to a ByteBuffer. + * @param {string} str String to decode + * @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} ByteBuffer + * @expose + */ + ByteBuffer.fromBase64 = function(str, littleEndian, noAssert) { + if (!noAssert) { + if (typeof str !== 'string') + throw TypeError("Illegal str: Not a string"); + if (str.length % 4 !== 0) + throw TypeError("Illegal str: Length not a multiple of 4"); + } + var bb = new ByteBuffer(str.length/4*3, littleEndian, noAssert), + i = 0; + lxiv.decode(stringSource(str), function(b) { + bb.view.setUint8(i++, b); + }); + bb.limit = i; + return bb; + }; + + /** + * Encodes a binary string to base64 like `window.btoa` does. + * @param {string} str Binary string + * @returns {string} Base64 encoded string + * @see https://developer.mozilla.org/en-US/docs/Web/API/Window.btoa + * @expose + */ + ByteBuffer.btoa = function(str) { + return ByteBuffer.fromBinary(str).toBase64(); + }; + + /** + * Decodes a base64 encoded string to binary like `window.atob` does. + * @param {string} b64 Base64 encoded string + * @returns {string} Binary string + * @see https://developer.mozilla.org/en-US/docs/Web/API/Window.atob + * @expose + */ + ByteBuffer.atob = function(b64) { + return ByteBuffer.fromBase64(b64).toBinary(); + }; + + // encodings/binary + + /** + * Encodes this ByteBuffer to a binary encoded string, that is using only characters 0x00-0xFF as bytes. + * @param {number=} begin Offset to begin at. Defaults to {@link ByteBuffer#offset}. + * @param {number=} end Offset to end at. Defaults to {@link ByteBuffer#limit}. + * @returns {string} Binary encoded string + * @throws {RangeError} If `offset > limit` + * @expose + */ + ByteBufferPrototype.toBinary = function(begin, end) { + begin = typeof begin === 'undefined' ? this.offset : begin; + end = typeof end === 'undefined' ? this.limit : end; + if (!this.noAssert) { if (typeof begin !== 'number' || begin % 1 !== 0) throw TypeError("Illegal begin: Not an integer"); begin >>>= 0; @@ -29459,237 +29445,237 @@ Curve25519Worker.prototype = { end >>>= 0; if (begin < 0 || begin > end || end > this.buffer.byteLength) throw RangeError("Illegal range: 0 <= "+begin+" <= "+end+" <= "+this.buffer.byteLength); - } - if (begin === end) - return ""; - var cc = [], pt = []; - while (begin < end) { - cc.push(this.view.getUint8(begin++)); - if (cc.length >= 1024) - pt.push(String.fromCharCode.apply(String, cc)), - cc = []; - } - return pt.join('') + String.fromCharCode.apply(String, cc); - }; - - /** - * Decodes a binary encoded string, that is using only characters 0x00-0xFF as bytes, to a ByteBuffer. - * @param {string} str String to decode - * @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} ByteBuffer - * @expose - */ - ByteBuffer.fromBinary = function(str, littleEndian, noAssert) { - if (!noAssert) { - if (typeof str !== 'string') - throw TypeError("Illegal str: Not a string"); - } - var i = 0, k = str.length, charCode, - bb = new ByteBuffer(k, littleEndian, noAssert); - while (i 255) - throw RangeError("Illegal charCode at "+i+": 0 <= "+charCode+" <= 255"); - bb.view.setUint8(i++, charCode); - } - bb.limit = k; - return bb; - }; - - // encodings/debug - - /** - * Encodes this ByteBuffer to a hex encoded string with marked offsets. Offset symbols are: - * * `<` : offset, - * * `'` : markedOffset, - * * `>` : limit, - * * `|` : offset and limit, - * * `[` : offset and markedOffset, - * * `]` : markedOffset and limit, - * * `!` : offset, markedOffset and limit - * @param {boolean=} columns If `true` returns two columns hex + ascii, defaults to `false` - * @returns {string|!Array.} Debug string or array of lines if `asArray = true` - * @expose - * @example `>00'01 02<03` contains four bytes with `limit=0, markedOffset=1, offset=3` - * @example `00[01 02 03>` contains four bytes with `offset=markedOffset=1, limit=4` - * @example `00|01 02 03` contains four bytes with `offset=limit=1, markedOffset=-1` - * @example `|` contains zero bytes with `offset=limit=0, markedOffset=-1` - */ - ByteBufferPrototype.toDebug = function(columns) { - var i = -1, - k = this.buffer.byteLength, - b, - hex = "", - asc = "", - out = ""; - while (i 32 && b < 127 ? String.fromCharCode(b) : '.'; - } - } - ++i; - if (columns) { - if (i > 0 && i % 16 === 0 && i !== k) { - while (hex.length < 3*16+3) hex += " "; - out += hex+asc+"\n"; - hex = asc = ""; - } - } - if (i === this.offset && i === this.limit) - hex += i === this.markedOffset ? "!" : "|"; - else if (i === this.offset) - hex += i === this.markedOffset ? "[" : "<"; - else if (i === this.limit) - hex += i === this.markedOffset ? "]" : ">"; - else - hex += i === this.markedOffset ? "'" : (columns || (i !== 0 && i !== k) ? " " : ""); - } - if (columns && hex !== " ") { - while (hex.length < 3*16+3) hex += " "; - out += hex+asc+"\n"; - } - return columns ? out : hex; - }; - - /** - * Decodes a hex encoded string with marked offsets to a ByteBuffer. - * @param {string} str Debug string to decode (not be generated with `columns = true`) - * @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} ByteBuffer - * @expose - * @see ByteBuffer#toDebug - */ - ByteBuffer.fromDebug = function(str, littleEndian, noAssert) { - var k = str.length, - bb = new ByteBuffer(((k+1)/3)|0, littleEndian, noAssert); - var i = 0, j = 0, ch, b, - rs = false, // Require symbol next - ho = false, hm = false, hl = false, // Already has offset, markedOffset, limit? - fail = false; - while (i': - if (!noAssert) { - if (hl) { - fail = true; break; - } - hl = true; - } - bb.limit = j; - rs = false; - break; - case "'": - if (!noAssert) { - if (hm) { - fail = true; break; - } - hm = true; - } - bb.markedOffset = j; - rs = false; - break; - case ' ': - rs = false; - break; - default: - if (!noAssert) { - if (rs) { - fail = true; break; - } - } - b = parseInt(ch+str.charAt(i++), 16); - if (!noAssert) { - if (isNaN(b) || b < 0 || b > 255) - throw TypeError("Illegal str: Not a debug encoded string"); - } - bb.view.setUint8(j++, b); - rs = true; - } - if (fail) - throw TypeError("Illegal str: Invalid symbol at "+i); - } - if (!noAssert) { - if (!ho || !hl) - throw TypeError("Illegal str: Missing offset or limit"); - if (j= 1024) + pt.push(String.fromCharCode.apply(String, cc)), + cc = []; + } + return pt.join('') + String.fromCharCode.apply(String, cc); + }; + + /** + * Decodes a binary encoded string, that is using only characters 0x00-0xFF as bytes, to a ByteBuffer. + * @param {string} str String to decode + * @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} ByteBuffer + * @expose + */ + ByteBuffer.fromBinary = function(str, littleEndian, noAssert) { + if (!noAssert) { + if (typeof str !== 'string') + throw TypeError("Illegal str: Not a string"); + } + var i = 0, k = str.length, charCode, + bb = new ByteBuffer(k, littleEndian, noAssert); + while (i 255) + throw RangeError("Illegal charCode at "+i+": 0 <= "+charCode+" <= 255"); + bb.view.setUint8(i++, charCode); + } + bb.limit = k; + return bb; + }; + + // encodings/debug + + /** + * Encodes this ByteBuffer to a hex encoded string with marked offsets. Offset symbols are: + * * `<` : offset, + * * `'` : markedOffset, + * * `>` : limit, + * * `|` : offset and limit, + * * `[` : offset and markedOffset, + * * `]` : markedOffset and limit, + * * `!` : offset, markedOffset and limit + * @param {boolean=} columns If `true` returns two columns hex + ascii, defaults to `false` + * @returns {string|!Array.} Debug string or array of lines if `asArray = true` + * @expose + * @example `>00'01 02<03` contains four bytes with `limit=0, markedOffset=1, offset=3` + * @example `00[01 02 03>` contains four bytes with `offset=markedOffset=1, limit=4` + * @example `00|01 02 03` contains four bytes with `offset=limit=1, markedOffset=-1` + * @example `|` contains zero bytes with `offset=limit=0, markedOffset=-1` + */ + ByteBufferPrototype.toDebug = function(columns) { + var i = -1, + k = this.buffer.byteLength, + b, + hex = "", + asc = "", + out = ""; + while (i 32 && b < 127 ? String.fromCharCode(b) : '.'; + } + } + ++i; + if (columns) { + if (i > 0 && i % 16 === 0 && i !== k) { + while (hex.length < 3*16+3) hex += " "; + out += hex+asc+"\n"; + hex = asc = ""; + } + } + if (i === this.offset && i === this.limit) + hex += i === this.markedOffset ? "!" : "|"; + else if (i === this.offset) + hex += i === this.markedOffset ? "[" : "<"; + else if (i === this.limit) + hex += i === this.markedOffset ? "]" : ">"; + else + hex += i === this.markedOffset ? "'" : (columns || (i !== 0 && i !== k) ? " " : ""); + } + if (columns && hex !== " ") { + while (hex.length < 3*16+3) hex += " "; + out += hex+asc+"\n"; + } + return columns ? out : hex; + }; + + /** + * Decodes a hex encoded string with marked offsets to a ByteBuffer. + * @param {string} str Debug string to decode (not be generated with `columns = true`) + * @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} ByteBuffer + * @expose + * @see ByteBuffer#toDebug + */ + ByteBuffer.fromDebug = function(str, littleEndian, noAssert) { + var k = str.length, + bb = new ByteBuffer(((k+1)/3)|0, littleEndian, noAssert); + var i = 0, j = 0, ch, b, + rs = false, // Require symbol next + ho = false, hm = false, hl = false, // Already has offset, markedOffset, limit? + fail = false; + while (i': + if (!noAssert) { + if (hl) { + fail = true; break; + } + hl = true; + } + bb.limit = j; + rs = false; + break; + case "'": + if (!noAssert) { + if (hm) { + fail = true; break; + } + hm = true; + } + bb.markedOffset = j; + rs = false; + break; + case ' ': + rs = false; + break; + default: + if (!noAssert) { + if (rs) { + fail = true; break; + } + } + b = parseInt(ch+str.charAt(i++), 16); + if (!noAssert) { + if (isNaN(b) || b < 0 || b > 255) + throw TypeError("Illegal str: Not a debug encoded string"); + } + bb.view.setUint8(j++, b); + rs = true; + } + if (fail) + throw TypeError("Illegal str: Invalid symbol at "+i); + } + if (!noAssert) { + if (!ho || !hl) + throw TypeError("Illegal str: Missing offset or limit"); + if (j>>= 0; @@ -29698,261 +29684,261 @@ Curve25519Worker.prototype = { end >>>= 0; if (begin < 0 || begin > end || end > this.buffer.byteLength) throw RangeError("Illegal range: 0 <= "+begin+" <= "+end+" <= "+this.buffer.byteLength); - } - var out = new Array(end - begin), - b; - while (begin < end) { - b = this.view.getUint8(begin++); - if (b < 0x10) - out.push("0", b.toString(16)); - else out.push(b.toString(16)); - } - return out.join(''); - }; - - /** - * Decodes a hex encoded string to a ByteBuffer. - * @param {string} str String to decode - * @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} ByteBuffer - * @expose - */ - ByteBuffer.fromHex = function(str, littleEndian, noAssert) { - if (!noAssert) { - if (typeof str !== 'string') - throw TypeError("Illegal str: Not a string"); - if (str.length % 2 !== 0) - throw TypeError("Illegal str: Length not a multiple of 2"); - } - var k = str.length, - bb = new ByteBuffer((k / 2) | 0, littleEndian), - b; - for (var i=0, j=0; i 255) - throw TypeError("Illegal str: Contains non-hex characters"); - bb.view.setUint8(j++, b); - } - bb.limit = j; - return bb; - }; - - // utfx-embeddable - - /** - * utfx-embeddable (c) 2014 Daniel Wirtz - * Released under the Apache License, Version 2.0 - * see: https://github.com/dcodeIO/utfx for details - */ - var utfx = function() { - "use strict"; - - /** - * utfx namespace. - * @inner - * @type {!Object.} - */ - var utfx = {}; - - /** - * Maximum valid code point. - * @type {number} - * @const - */ - utfx.MAX_CODEPOINT = 0x10FFFF; - - /** - * Encodes UTF8 code points to UTF8 bytes. - * @param {(!function():number|null) | number} src Code points source, either as a function returning the next code point - * respectively `null` if there are no more code points left or a single numeric code point. - * @param {!function(number)} dst Bytes destination as a function successively called with the next byte - */ - utfx.encodeUTF8 = function(src, dst) { - var cp = null; - if (typeof src === 'number') - cp = src, - src = function() { return null; }; - while (cp !== null || (cp = src()) !== null) { - if (cp < 0x80) - dst(cp&0x7F); - else if (cp < 0x800) - dst(((cp>>6)&0x1F)|0xC0), - dst((cp&0x3F)|0x80); - else if (cp < 0x10000) - dst(((cp>>12)&0x0F)|0xE0), - dst(((cp>>6)&0x3F)|0x80), - dst((cp&0x3F)|0x80); - else - dst(((cp>>18)&0x07)|0xF0), - dst(((cp>>12)&0x3F)|0x80), - dst(((cp>>6)&0x3F)|0x80), - dst((cp&0x3F)|0x80); - cp = null; - } - }; - - /** - * Decodes UTF8 bytes to UTF8 code points. - * @param {!function():number|null} src Bytes source as a function returning the next byte respectively `null` if there - * are no more bytes left. - * @param {!function(number)} dst Code points destination as a function successively called with each decoded code point. - * @throws {RangeError} If a starting byte is invalid in UTF8 - * @throws {Error} If the last sequence is truncated. Has an array property `bytes` holding the - * remaining bytes. - */ - utfx.decodeUTF8 = function(src, dst) { - var a, b, c, d, fail = function(b) { - b = b.slice(0, b.indexOf(null)); - var err = Error(b.toString()); - err.name = "TruncatedError"; - err['bytes'] = b; - throw err; - }; - while ((a = src()) !== null) { - if ((a&0x80) === 0) - dst(a); - else if ((a&0xE0) === 0xC0) - ((b = src()) === null) && fail([a, b]), - dst(((a&0x1F)<<6) | (b&0x3F)); - else if ((a&0xF0) === 0xE0) - ((b=src()) === null || (c=src()) === null) && fail([a, b, c]), - dst(((a&0x0F)<<12) | ((b&0x3F)<<6) | (c&0x3F)); - else if ((a&0xF8) === 0xF0) - ((b=src()) === null || (c=src()) === null || (d=src()) === null) && fail([a, b, c ,d]), - dst(((a&0x07)<<18) | ((b&0x3F)<<12) | ((c&0x3F)<<6) | (d&0x3F)); - else throw RangeError("Illegal starting byte: "+a); - } - }; - - /** - * Converts UTF16 characters to UTF8 code points. - * @param {!function():number|null} src Characters source as a function returning the next char code respectively - * `null` if there are no more characters left. - * @param {!function(number)} dst Code points destination as a function successively called with each converted code - * point. - */ - utfx.UTF16toUTF8 = function(src, dst) { - var c1, c2 = null; - while (true) { - if ((c1 = c2 !== null ? c2 : src()) === null) - break; - if (c1 >= 0xD800 && c1 <= 0xDFFF) { - if ((c2 = src()) !== null) { - if (c2 >= 0xDC00 && c2 <= 0xDFFF) { - dst((c1-0xD800)*0x400+c2-0xDC00+0x10000); - c2 = null; continue; - } - } - } - dst(c1); - } - if (c2 !== null) dst(c2); - }; - - /** - * Converts UTF8 code points to UTF16 characters. - * @param {(!function():number|null) | number} src Code points source, either as a function returning the next code point - * respectively `null` if there are no more code points left or a single numeric code point. - * @param {!function(number)} dst Characters destination as a function successively called with each converted char code. - * @throws {RangeError} If a code point is out of range - */ - utfx.UTF8toUTF16 = function(src, dst) { - var cp = null; - if (typeof src === 'number') - cp = src, src = function() { return null; }; - while (cp !== null || (cp = src()) !== null) { - if (cp <= 0xFFFF) - dst(cp); - else - cp -= 0x10000, - dst((cp>>10)+0xD800), - dst((cp%0x400)+0xDC00); - cp = null; - } - }; - - /** - * Converts and encodes UTF16 characters to UTF8 bytes. - * @param {!function():number|null} src Characters source as a function returning the next char code respectively `null` - * if there are no more characters left. - * @param {!function(number)} dst Bytes destination as a function successively called with the next byte. - */ - utfx.encodeUTF16toUTF8 = function(src, dst) { - utfx.UTF16toUTF8(src, function(cp) { - utfx.encodeUTF8(cp, dst); - }); - }; - - /** - * Decodes and converts UTF8 bytes to UTF16 characters. - * @param {!function():number|null} src Bytes source as a function returning the next byte respectively `null` if there - * are no more bytes left. - * @param {!function(number)} dst Characters destination as a function successively called with each converted char code. - * @throws {RangeError} If a starting byte is invalid in UTF8 - * @throws {Error} If the last sequence is truncated. Has an array property `bytes` holding the remaining bytes. - */ - utfx.decodeUTF8toUTF16 = function(src, dst) { - utfx.decodeUTF8(src, function(cp) { - utfx.UTF8toUTF16(cp, dst); - }); - }; - - /** - * Calculates the byte length of an UTF8 code point. - * @param {number} cp UTF8 code point - * @returns {number} Byte length - */ - utfx.calculateCodePoint = function(cp) { - return (cp < 0x80) ? 1 : (cp < 0x800) ? 2 : (cp < 0x10000) ? 3 : 4; - }; - - /** - * Calculates the number of UTF8 bytes required to store UTF8 code points. - * @param {(!function():number|null)} src Code points source as a function returning the next code point respectively - * `null` if there are no more code points left. - * @returns {number} The number of UTF8 bytes required - */ - utfx.calculateUTF8 = function(src) { - var cp, l=0; - while ((cp = src()) !== null) - l += utfx.calculateCodePoint(cp); - return l; - }; - - /** - * Calculates the number of UTF8 code points respectively UTF8 bytes required to store UTF16 char codes. - * @param {(!function():number|null)} src Characters source as a function returning the next char code respectively - * `null` if there are no more characters left. - * @returns {!Array.} The number of UTF8 code points at index 0 and the number of UTF8 bytes required at index 1. - */ - utfx.calculateUTF16asUTF8 = function(src) { - var n=0, l=0; - utfx.UTF16toUTF8(src, function(cp) { - ++n; l += utfx.calculateCodePoint(cp); - }); - return [n,l]; - }; - - return utfx; - }(); - - // encodings/utf8 - - /** - * Encodes this ByteBuffer's contents between {@link ByteBuffer#offset} and {@link ByteBuffer#limit} to an UTF8 encoded - * string. - * @returns {string} Hex encoded string - * @throws {RangeError} If `offset > limit` - * @expose - */ - ByteBufferPrototype.toUTF8 = function(begin, end) { - if (typeof begin === 'undefined') begin = this.offset; - if (typeof end === 'undefined') end = this.limit; - if (!this.noAssert) { + } + var out = new Array(end - begin), + b; + while (begin < end) { + b = this.view.getUint8(begin++); + if (b < 0x10) + out.push("0", b.toString(16)); + else out.push(b.toString(16)); + } + return out.join(''); + }; + + /** + * Decodes a hex encoded string to a ByteBuffer. + * @param {string} str String to decode + * @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} ByteBuffer + * @expose + */ + ByteBuffer.fromHex = function(str, littleEndian, noAssert) { + if (!noAssert) { + if (typeof str !== 'string') + throw TypeError("Illegal str: Not a string"); + if (str.length % 2 !== 0) + throw TypeError("Illegal str: Length not a multiple of 2"); + } + var k = str.length, + bb = new ByteBuffer((k / 2) | 0, littleEndian), + b; + for (var i=0, j=0; i 255) + throw TypeError("Illegal str: Contains non-hex characters"); + bb.view.setUint8(j++, b); + } + bb.limit = j; + return bb; + }; + + // utfx-embeddable + + /** + * utfx-embeddable (c) 2014 Daniel Wirtz + * Released under the Apache License, Version 2.0 + * see: https://github.com/dcodeIO/utfx for details + */ + var utfx = function() { + "use strict"; + + /** + * utfx namespace. + * @inner + * @type {!Object.} + */ + var utfx = {}; + + /** + * Maximum valid code point. + * @type {number} + * @const + */ + utfx.MAX_CODEPOINT = 0x10FFFF; + + /** + * Encodes UTF8 code points to UTF8 bytes. + * @param {(!function():number|null) | number} src Code points source, either as a function returning the next code point + * respectively `null` if there are no more code points left or a single numeric code point. + * @param {!function(number)} dst Bytes destination as a function successively called with the next byte + */ + utfx.encodeUTF8 = function(src, dst) { + var cp = null; + if (typeof src === 'number') + cp = src, + src = function() { return null; }; + while (cp !== null || (cp = src()) !== null) { + if (cp < 0x80) + dst(cp&0x7F); + else if (cp < 0x800) + dst(((cp>>6)&0x1F)|0xC0), + dst((cp&0x3F)|0x80); + else if (cp < 0x10000) + dst(((cp>>12)&0x0F)|0xE0), + dst(((cp>>6)&0x3F)|0x80), + dst((cp&0x3F)|0x80); + else + dst(((cp>>18)&0x07)|0xF0), + dst(((cp>>12)&0x3F)|0x80), + dst(((cp>>6)&0x3F)|0x80), + dst((cp&0x3F)|0x80); + cp = null; + } + }; + + /** + * Decodes UTF8 bytes to UTF8 code points. + * @param {!function():number|null} src Bytes source as a function returning the next byte respectively `null` if there + * are no more bytes left. + * @param {!function(number)} dst Code points destination as a function successively called with each decoded code point. + * @throws {RangeError} If a starting byte is invalid in UTF8 + * @throws {Error} If the last sequence is truncated. Has an array property `bytes` holding the + * remaining bytes. + */ + utfx.decodeUTF8 = function(src, dst) { + var a, b, c, d, fail = function(b) { + b = b.slice(0, b.indexOf(null)); + var err = Error(b.toString()); + err.name = "TruncatedError"; + err['bytes'] = b; + throw err; + }; + while ((a = src()) !== null) { + if ((a&0x80) === 0) + dst(a); + else if ((a&0xE0) === 0xC0) + ((b = src()) === null) && fail([a, b]), + dst(((a&0x1F)<<6) | (b&0x3F)); + else if ((a&0xF0) === 0xE0) + ((b=src()) === null || (c=src()) === null) && fail([a, b, c]), + dst(((a&0x0F)<<12) | ((b&0x3F)<<6) | (c&0x3F)); + else if ((a&0xF8) === 0xF0) + ((b=src()) === null || (c=src()) === null || (d=src()) === null) && fail([a, b, c ,d]), + dst(((a&0x07)<<18) | ((b&0x3F)<<12) | ((c&0x3F)<<6) | (d&0x3F)); + else throw RangeError("Illegal starting byte: "+a); + } + }; + + /** + * Converts UTF16 characters to UTF8 code points. + * @param {!function():number|null} src Characters source as a function returning the next char code respectively + * `null` if there are no more characters left. + * @param {!function(number)} dst Code points destination as a function successively called with each converted code + * point. + */ + utfx.UTF16toUTF8 = function(src, dst) { + var c1, c2 = null; + while (true) { + if ((c1 = c2 !== null ? c2 : src()) === null) + break; + if (c1 >= 0xD800 && c1 <= 0xDFFF) { + if ((c2 = src()) !== null) { + if (c2 >= 0xDC00 && c2 <= 0xDFFF) { + dst((c1-0xD800)*0x400+c2-0xDC00+0x10000); + c2 = null; continue; + } + } + } + dst(c1); + } + if (c2 !== null) dst(c2); + }; + + /** + * Converts UTF8 code points to UTF16 characters. + * @param {(!function():number|null) | number} src Code points source, either as a function returning the next code point + * respectively `null` if there are no more code points left or a single numeric code point. + * @param {!function(number)} dst Characters destination as a function successively called with each converted char code. + * @throws {RangeError} If a code point is out of range + */ + utfx.UTF8toUTF16 = function(src, dst) { + var cp = null; + if (typeof src === 'number') + cp = src, src = function() { return null; }; + while (cp !== null || (cp = src()) !== null) { + if (cp <= 0xFFFF) + dst(cp); + else + cp -= 0x10000, + dst((cp>>10)+0xD800), + dst((cp%0x400)+0xDC00); + cp = null; + } + }; + + /** + * Converts and encodes UTF16 characters to UTF8 bytes. + * @param {!function():number|null} src Characters source as a function returning the next char code respectively `null` + * if there are no more characters left. + * @param {!function(number)} dst Bytes destination as a function successively called with the next byte. + */ + utfx.encodeUTF16toUTF8 = function(src, dst) { + utfx.UTF16toUTF8(src, function(cp) { + utfx.encodeUTF8(cp, dst); + }); + }; + + /** + * Decodes and converts UTF8 bytes to UTF16 characters. + * @param {!function():number|null} src Bytes source as a function returning the next byte respectively `null` if there + * are no more bytes left. + * @param {!function(number)} dst Characters destination as a function successively called with each converted char code. + * @throws {RangeError} If a starting byte is invalid in UTF8 + * @throws {Error} If the last sequence is truncated. Has an array property `bytes` holding the remaining bytes. + */ + utfx.decodeUTF8toUTF16 = function(src, dst) { + utfx.decodeUTF8(src, function(cp) { + utfx.UTF8toUTF16(cp, dst); + }); + }; + + /** + * Calculates the byte length of an UTF8 code point. + * @param {number} cp UTF8 code point + * @returns {number} Byte length + */ + utfx.calculateCodePoint = function(cp) { + return (cp < 0x80) ? 1 : (cp < 0x800) ? 2 : (cp < 0x10000) ? 3 : 4; + }; + + /** + * Calculates the number of UTF8 bytes required to store UTF8 code points. + * @param {(!function():number|null)} src Code points source as a function returning the next code point respectively + * `null` if there are no more code points left. + * @returns {number} The number of UTF8 bytes required + */ + utfx.calculateUTF8 = function(src) { + var cp, l=0; + while ((cp = src()) !== null) + l += utfx.calculateCodePoint(cp); + return l; + }; + + /** + * Calculates the number of UTF8 code points respectively UTF8 bytes required to store UTF16 char codes. + * @param {(!function():number|null)} src Characters source as a function returning the next char code respectively + * `null` if there are no more characters left. + * @returns {!Array.} The number of UTF8 code points at index 0 and the number of UTF8 bytes required at index 1. + */ + utfx.calculateUTF16asUTF8 = function(src) { + var n=0, l=0; + utfx.UTF16toUTF8(src, function(cp) { + ++n; l += utfx.calculateCodePoint(cp); + }); + return [n,l]; + }; + + return utfx; + }(); + + // encodings/utf8 + + /** + * Encodes this ByteBuffer's contents between {@link ByteBuffer#offset} and {@link ByteBuffer#limit} to an UTF8 encoded + * string. + * @returns {string} Hex encoded string + * @throws {RangeError} If `offset > limit` + * @expose + */ + ByteBufferPrototype.toUTF8 = function(begin, end) { + if (typeof begin === 'undefined') begin = this.offset; + if (typeof end === 'undefined') end = this.limit; + if (!this.noAssert) { if (typeof begin !== 'number' || begin % 1 !== 0) throw TypeError("Illegal begin: Not an integer"); begin >>>= 0; @@ -29961,348 +29947,348 @@ Curve25519Worker.prototype = { end >>>= 0; if (begin < 0 || begin > end || end > this.buffer.byteLength) throw RangeError("Illegal range: 0 <= "+begin+" <= "+end+" <= "+this.buffer.byteLength); - } - var sd; try { - utfx.decodeUTF8toUTF16(function() { - return begin < end ? this.view.getUint8(begin++) : null; - }.bind(this), sd = stringDestination()); - } catch (e) { - if (begin !== end) - throw RangeError("Illegal range: Truncated data, "+begin+" != "+end); - } - return sd(); - }; - - /** - * Decodes an UTF8 encoded string to a ByteBuffer. - * @param {string} str String to decode - * @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} ByteBuffer - * @expose - */ - ByteBuffer.fromUTF8 = function(str, littleEndian, noAssert) { - if (!noAssert) - if (typeof str !== 'string') - throw TypeError("Illegal str: Not a string"); - var bb = new ByteBuffer(utfx.calculateUTF16asUTF8(stringSource(str), true)[1], littleEndian, noAssert), - i = 0; - utfx.encodeUTF16toUTF8(stringSource(str), function(b) { - bb.view.setUint8(i++, b); - }); - bb.limit = i; - return bb; - }; - - - return ByteBuffer; - } - - /* CommonJS */ if (typeof require === 'function' && typeof module === 'object' && module && typeof exports === 'object' && exports) - module['exports'] = (function() { - var Long; try { Long = require("long"); } catch (e) {} - return loadByteBuffer(Long); - })(); - /* AMD */ else if (typeof define === 'function' && define["amd"]) - define("ByteBuffer", ["Long"], function(Long) { return loadByteBuffer(Long); }); - /* Global */ else - (global["dcodeIO"] = global["dcodeIO"] || {})["ByteBuffer"] = loadByteBuffer(global["dcodeIO"]["Long"]); - -})(this); - -/* - Copyright 2013 Daniel Wirtz - - 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 protobuf.js (c) 2013 Daniel Wirtz - * Released under the Apache License, Version 2.0 - * see: https://github.com/dcodeIO/protobuf.js for details - */ -(function(global, factory) { - - /* AMD */ if (typeof define === 'function' && define["amd"]) - define(["bytebuffer"], factory); - /* CommonJS */ else if (typeof require === "function" && typeof module === "object" && module && module["exports"]) - module["exports"] = factory(require("bytebuffer"), true); - /* Global */ else - (global["dcodeIO"] = global["dcodeIO"] || {})["ProtoBuf"] = factory(global["dcodeIO"]["ByteBuffer"]); - -})(this, function(ByteBuffer, isCommonJS) { - "use strict"; - - /** - * The ProtoBuf namespace. - * @exports ProtoBuf - * @namespace - * @expose - */ - var ProtoBuf = {}; - - /** - * @type {!function(new: ByteBuffer, ...[*])} - * @expose - */ - ProtoBuf.ByteBuffer = ByteBuffer; - - /** - * @type {?function(new: Long, ...[*])} - * @expose - */ - ProtoBuf.Long = ByteBuffer.Long || null; - - /** - * ProtoBuf.js version. - * @type {string} - * @const - * @expose - */ - ProtoBuf.VERSION = "5.0.1"; - - /** - * Wire types. - * @type {Object.} - * @const - * @expose - */ - ProtoBuf.WIRE_TYPES = {}; - - /** - * Varint wire type. - * @type {number} - * @expose - */ - ProtoBuf.WIRE_TYPES.VARINT = 0; - - /** - * Fixed 64 bits wire type. - * @type {number} - * @const - * @expose - */ - ProtoBuf.WIRE_TYPES.BITS64 = 1; - - /** - * Length delimited wire type. - * @type {number} - * @const - * @expose - */ - ProtoBuf.WIRE_TYPES.LDELIM = 2; - - /** - * Start group wire type. - * @type {number} - * @const - * @expose - */ - ProtoBuf.WIRE_TYPES.STARTGROUP = 3; - - /** - * End group wire type. - * @type {number} - * @const - * @expose - */ - ProtoBuf.WIRE_TYPES.ENDGROUP = 4; - - /** - * Fixed 32 bits wire type. - * @type {number} - * @const - * @expose - */ - ProtoBuf.WIRE_TYPES.BITS32 = 5; - - /** - * Packable wire types. - * @type {!Array.} - * @const - * @expose - */ - ProtoBuf.PACKABLE_WIRE_TYPES = [ - ProtoBuf.WIRE_TYPES.VARINT, - ProtoBuf.WIRE_TYPES.BITS64, - ProtoBuf.WIRE_TYPES.BITS32 - ]; - - /** - * Types. - * @dict - * @type {!Object.} - * @const - * @expose - */ - ProtoBuf.TYPES = { - // According to the protobuf spec. - "int32": { - name: "int32", - wireType: ProtoBuf.WIRE_TYPES.VARINT, - defaultValue: 0 - }, - "uint32": { - name: "uint32", - wireType: ProtoBuf.WIRE_TYPES.VARINT, - defaultValue: 0 - }, - "sint32": { - name: "sint32", - wireType: ProtoBuf.WIRE_TYPES.VARINT, - defaultValue: 0 - }, - "int64": { - name: "int64", - wireType: ProtoBuf.WIRE_TYPES.VARINT, - defaultValue: ProtoBuf.Long ? ProtoBuf.Long.ZERO : undefined - }, - "uint64": { - name: "uint64", - wireType: ProtoBuf.WIRE_TYPES.VARINT, - defaultValue: ProtoBuf.Long ? ProtoBuf.Long.UZERO : undefined - }, - "sint64": { - name: "sint64", - wireType: ProtoBuf.WIRE_TYPES.VARINT, - defaultValue: ProtoBuf.Long ? ProtoBuf.Long.ZERO : undefined - }, - "bool": { - name: "bool", - wireType: ProtoBuf.WIRE_TYPES.VARINT, - defaultValue: false - }, - "double": { - name: "double", - wireType: ProtoBuf.WIRE_TYPES.BITS64, - defaultValue: 0 - }, - "string": { - name: "string", - wireType: ProtoBuf.WIRE_TYPES.LDELIM, - defaultValue: "" - }, - "bytes": { - name: "bytes", - wireType: ProtoBuf.WIRE_TYPES.LDELIM, - defaultValue: null // overridden in the code, must be a unique instance - }, - "fixed32": { - name: "fixed32", - wireType: ProtoBuf.WIRE_TYPES.BITS32, - defaultValue: 0 - }, - "sfixed32": { - name: "sfixed32", - wireType: ProtoBuf.WIRE_TYPES.BITS32, - defaultValue: 0 - }, - "fixed64": { - name: "fixed64", - wireType: ProtoBuf.WIRE_TYPES.BITS64, - defaultValue: ProtoBuf.Long ? ProtoBuf.Long.UZERO : undefined - }, - "sfixed64": { - name: "sfixed64", - wireType: ProtoBuf.WIRE_TYPES.BITS64, - defaultValue: ProtoBuf.Long ? ProtoBuf.Long.ZERO : undefined - }, - "float": { - name: "float", - wireType: ProtoBuf.WIRE_TYPES.BITS32, - defaultValue: 0 - }, - "enum": { - name: "enum", - wireType: ProtoBuf.WIRE_TYPES.VARINT, - defaultValue: 0 - }, - "message": { - name: "message", - wireType: ProtoBuf.WIRE_TYPES.LDELIM, - defaultValue: null - }, - "group": { - name: "group", - wireType: ProtoBuf.WIRE_TYPES.STARTGROUP, - defaultValue: null - } - }; - - /** - * Valid map key types. - * @type {!Array.>} - * @const - * @expose - */ - ProtoBuf.MAP_KEY_TYPES = [ - ProtoBuf.TYPES["int32"], - ProtoBuf.TYPES["sint32"], - ProtoBuf.TYPES["sfixed32"], - ProtoBuf.TYPES["uint32"], - ProtoBuf.TYPES["fixed32"], - ProtoBuf.TYPES["int64"], - ProtoBuf.TYPES["sint64"], - ProtoBuf.TYPES["sfixed64"], - ProtoBuf.TYPES["uint64"], - ProtoBuf.TYPES["fixed64"], - ProtoBuf.TYPES["bool"], - ProtoBuf.TYPES["string"], - ProtoBuf.TYPES["bytes"] - ]; - - /** - * Minimum field id. - * @type {number} - * @const - * @expose - */ - ProtoBuf.ID_MIN = 1; - - /** - * Maximum field id. - * @type {number} - * @const - * @expose - */ - ProtoBuf.ID_MAX = 0x1FFFFFFF; - - /** - * If set to `true`, field names will be converted from underscore notation to camel case. Defaults to `false`. - * Must be set prior to parsing. - * @type {boolean} - * @expose - */ - ProtoBuf.convertFieldsToCamelCase = false; - - /** - * By default, messages are populated with (setX, set_x) accessors for each field. This can be disabled by - * setting this to `false` prior to building messages. - * @type {boolean} - * @expose - */ - ProtoBuf.populateAccessors = true; - - /** - * By default, messages are populated with default values if a field is not present on the wire. To disable - * this behavior, set this setting to `false`. - * @type {boolean} - * @expose - */ - ProtoBuf.populateDefaults = true; + } + var sd; try { + utfx.decodeUTF8toUTF16(function() { + return begin < end ? this.view.getUint8(begin++) : null; + }.bind(this), sd = stringDestination()); + } catch (e) { + if (begin !== end) + throw RangeError("Illegal range: Truncated data, "+begin+" != "+end); + } + return sd(); + }; + + /** + * Decodes an UTF8 encoded string to a ByteBuffer. + * @param {string} str String to decode + * @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} ByteBuffer + * @expose + */ + ByteBuffer.fromUTF8 = function(str, littleEndian, noAssert) { + if (!noAssert) + if (typeof str !== 'string') + throw TypeError("Illegal str: Not a string"); + var bb = new ByteBuffer(utfx.calculateUTF16asUTF8(stringSource(str), true)[1], littleEndian, noAssert), + i = 0; + utfx.encodeUTF16toUTF8(stringSource(str), function(b) { + bb.view.setUint8(i++, b); + }); + bb.limit = i; + return bb; + }; + + + return ByteBuffer; + } + + /* CommonJS */ if (typeof require === 'function' && typeof module === 'object' && module && typeof exports === 'object' && exports) + module['exports'] = (function() { + var Long; try { Long = require("long"); } catch (e) {} + return loadByteBuffer(Long); + })(); + /* AMD */ else if (typeof define === 'function' && define["amd"]) + define("ByteBuffer", ["Long"], function(Long) { return loadByteBuffer(Long); }); + /* Global */ else + (global["dcodeIO"] = global["dcodeIO"] || {})["ByteBuffer"] = loadByteBuffer(global["dcodeIO"]["Long"]); + +})(this); +/* + Copyright 2013 Daniel Wirtz + + 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 protobuf.js (c) 2013 Daniel Wirtz + * Released under the Apache License, Version 2.0 + * see: https://github.com/dcodeIO/protobuf.js for details + */ +(function(global, factory) { + + /* AMD */ if (typeof define === 'function' && define["amd"]) + define(["bytebuffer"], factory); + /* CommonJS */ else if (typeof require === "function" && typeof module === "object" && module && module["exports"]) + module["exports"] = factory(require("bytebuffer"), true); + /* Global */ else + (global["dcodeIO"] = global["dcodeIO"] || {})["ProtoBuf"] = factory(global["dcodeIO"]["ByteBuffer"]); + +})(this, function(ByteBuffer, isCommonJS) { + "use strict"; + + /** + * The ProtoBuf namespace. + * @exports ProtoBuf + * @namespace + * @expose + */ + var ProtoBuf = {}; + + /** + * @type {!function(new: ByteBuffer, ...[*])} + * @expose + */ + ProtoBuf.ByteBuffer = ByteBuffer; + + /** + * @type {?function(new: Long, ...[*])} + * @expose + */ + ProtoBuf.Long = ByteBuffer.Long || null; + + /** + * ProtoBuf.js version. + * @type {string} + * @const + * @expose + */ + ProtoBuf.VERSION = "5.0.1"; + + /** + * Wire types. + * @type {Object.} + * @const + * @expose + */ + ProtoBuf.WIRE_TYPES = {}; + + /** + * Varint wire type. + * @type {number} + * @expose + */ + ProtoBuf.WIRE_TYPES.VARINT = 0; + + /** + * Fixed 64 bits wire type. + * @type {number} + * @const + * @expose + */ + ProtoBuf.WIRE_TYPES.BITS64 = 1; + + /** + * Length delimited wire type. + * @type {number} + * @const + * @expose + */ + ProtoBuf.WIRE_TYPES.LDELIM = 2; + + /** + * Start group wire type. + * @type {number} + * @const + * @expose + */ + ProtoBuf.WIRE_TYPES.STARTGROUP = 3; + + /** + * End group wire type. + * @type {number} + * @const + * @expose + */ + ProtoBuf.WIRE_TYPES.ENDGROUP = 4; + + /** + * Fixed 32 bits wire type. + * @type {number} + * @const + * @expose + */ + ProtoBuf.WIRE_TYPES.BITS32 = 5; + + /** + * Packable wire types. + * @type {!Array.} + * @const + * @expose + */ + ProtoBuf.PACKABLE_WIRE_TYPES = [ + ProtoBuf.WIRE_TYPES.VARINT, + ProtoBuf.WIRE_TYPES.BITS64, + ProtoBuf.WIRE_TYPES.BITS32 + ]; + + /** + * Types. + * @dict + * @type {!Object.} + * @const + * @expose + */ + ProtoBuf.TYPES = { + // According to the protobuf spec. + "int32": { + name: "int32", + wireType: ProtoBuf.WIRE_TYPES.VARINT, + defaultValue: 0 + }, + "uint32": { + name: "uint32", + wireType: ProtoBuf.WIRE_TYPES.VARINT, + defaultValue: 0 + }, + "sint32": { + name: "sint32", + wireType: ProtoBuf.WIRE_TYPES.VARINT, + defaultValue: 0 + }, + "int64": { + name: "int64", + wireType: ProtoBuf.WIRE_TYPES.VARINT, + defaultValue: ProtoBuf.Long ? ProtoBuf.Long.ZERO : undefined + }, + "uint64": { + name: "uint64", + wireType: ProtoBuf.WIRE_TYPES.VARINT, + defaultValue: ProtoBuf.Long ? ProtoBuf.Long.UZERO : undefined + }, + "sint64": { + name: "sint64", + wireType: ProtoBuf.WIRE_TYPES.VARINT, + defaultValue: ProtoBuf.Long ? ProtoBuf.Long.ZERO : undefined + }, + "bool": { + name: "bool", + wireType: ProtoBuf.WIRE_TYPES.VARINT, + defaultValue: false + }, + "double": { + name: "double", + wireType: ProtoBuf.WIRE_TYPES.BITS64, + defaultValue: 0 + }, + "string": { + name: "string", + wireType: ProtoBuf.WIRE_TYPES.LDELIM, + defaultValue: "" + }, + "bytes": { + name: "bytes", + wireType: ProtoBuf.WIRE_TYPES.LDELIM, + defaultValue: null // overridden in the code, must be a unique instance + }, + "fixed32": { + name: "fixed32", + wireType: ProtoBuf.WIRE_TYPES.BITS32, + defaultValue: 0 + }, + "sfixed32": { + name: "sfixed32", + wireType: ProtoBuf.WIRE_TYPES.BITS32, + defaultValue: 0 + }, + "fixed64": { + name: "fixed64", + wireType: ProtoBuf.WIRE_TYPES.BITS64, + defaultValue: ProtoBuf.Long ? ProtoBuf.Long.UZERO : undefined + }, + "sfixed64": { + name: "sfixed64", + wireType: ProtoBuf.WIRE_TYPES.BITS64, + defaultValue: ProtoBuf.Long ? ProtoBuf.Long.ZERO : undefined + }, + "float": { + name: "float", + wireType: ProtoBuf.WIRE_TYPES.BITS32, + defaultValue: 0 + }, + "enum": { + name: "enum", + wireType: ProtoBuf.WIRE_TYPES.VARINT, + defaultValue: 0 + }, + "message": { + name: "message", + wireType: ProtoBuf.WIRE_TYPES.LDELIM, + defaultValue: null + }, + "group": { + name: "group", + wireType: ProtoBuf.WIRE_TYPES.STARTGROUP, + defaultValue: null + } + }; + + /** + * Valid map key types. + * @type {!Array.>} + * @const + * @expose + */ + ProtoBuf.MAP_KEY_TYPES = [ + ProtoBuf.TYPES["int32"], + ProtoBuf.TYPES["sint32"], + ProtoBuf.TYPES["sfixed32"], + ProtoBuf.TYPES["uint32"], + ProtoBuf.TYPES["fixed32"], + ProtoBuf.TYPES["int64"], + ProtoBuf.TYPES["sint64"], + ProtoBuf.TYPES["sfixed64"], + ProtoBuf.TYPES["uint64"], + ProtoBuf.TYPES["fixed64"], + ProtoBuf.TYPES["bool"], + ProtoBuf.TYPES["string"], + ProtoBuf.TYPES["bytes"] + ]; + + /** + * Minimum field id. + * @type {number} + * @const + * @expose + */ + ProtoBuf.ID_MIN = 1; + + /** + * Maximum field id. + * @type {number} + * @const + * @expose + */ + ProtoBuf.ID_MAX = 0x1FFFFFFF; + + /** + * If set to `true`, field names will be converted from underscore notation to camel case. Defaults to `false`. + * Must be set prior to parsing. + * @type {boolean} + * @expose + */ + ProtoBuf.convertFieldsToCamelCase = false; + + /** + * By default, messages are populated with (setX, set_x) accessors for each field. This can be disabled by + * setting this to `false` prior to building messages. + * @type {boolean} + * @expose + */ + ProtoBuf.populateAccessors = true; + + /** + * By default, messages are populated with default values if a field is not present on the wire. To disable + * this behavior, set this setting to `false`. + * @type {boolean} + * @expose + */ + ProtoBuf.populateDefaults = true; + /** * @alias ProtoBuf.Util * @expose @@ -30419,4822 +30405,4822 @@ Curve25519Worker.prototype = { return Util; })(); - - /** - * Language expressions. - * @type {!Object.} - * @expose - */ - ProtoBuf.Lang = { - - // Characters always ending a statement - DELIM: /[\s\{\}=;:\[\],'"\(\)<>]/g, - - // Field rules - RULE: /^(?:required|optional|repeated|map)$/, - - // Field types - TYPE: /^(?:double|float|int32|uint32|sint32|int64|uint64|sint64|fixed32|sfixed32|fixed64|sfixed64|bool|string|bytes)$/, - - // Names - NAME: /^[a-zA-Z_][a-zA-Z_0-9]*$/, - - // Type definitions - TYPEDEF: /^[a-zA-Z][a-zA-Z_0-9]*$/, - - // Type references - TYPEREF: /^(?:\.?[a-zA-Z_][a-zA-Z_0-9]*)+$/, - - // Fully qualified type references - FQTYPEREF: /^(?:\.[a-zA-Z][a-zA-Z_0-9]*)+$/, - - // All numbers - NUMBER: /^-?(?:[1-9][0-9]*|0|0[xX][0-9a-fA-F]+|0[0-7]+|([0-9]*(\.[0-9]*)?([Ee][+-]?[0-9]+)?)|inf|nan)$/, - - // Decimal numbers - NUMBER_DEC: /^(?:[1-9][0-9]*|0)$/, - - // Hexadecimal numbers - NUMBER_HEX: /^0[xX][0-9a-fA-F]+$/, - - // Octal numbers - NUMBER_OCT: /^0[0-7]+$/, - - // Floating point numbers - NUMBER_FLT: /^([0-9]*(\.[0-9]*)?([Ee][+-]?[0-9]+)?|inf|nan)$/, - - // Booleans - BOOL: /^(?:true|false)$/i, - - // Id numbers - ID: /^(?:[1-9][0-9]*|0|0[xX][0-9a-fA-F]+|0[0-7]+)$/, - - // Negative id numbers (enum values) - NEGID: /^\-?(?:[1-9][0-9]*|0|0[xX][0-9a-fA-F]+|0[0-7]+)$/, - - // Whitespaces - WHITESPACE: /\s/, - - // All strings - STRING: /(?:"([^"\\]*(?:\\.[^"\\]*)*)")|(?:'([^'\\]*(?:\\.[^'\\]*)*)')/g, - - // Double quoted strings - STRING_DQ: /(?:"([^"\\]*(?:\\.[^"\\]*)*)")/g, - - // Single quoted strings - STRING_SQ: /(?:'([^'\\]*(?:\\.[^'\\]*)*)')/g - }; - - /** - * @alias ProtoBuf.DotProto - * @expose - */ - ProtoBuf.DotProto = (function(ProtoBuf, Lang) { - "use strict"; - - /** - * Utilities to parse .proto files. - * @exports ProtoBuf.DotProto - * @namespace - */ - var DotProto = {}; - - /** - * Constructs a new Tokenizer. - * @exports ProtoBuf.DotProto.Tokenizer - * @class prototype tokenizer - * @param {string} proto Proto to tokenize - * @constructor - */ - var Tokenizer = function(proto) { - - /** - * Source to parse. - * @type {string} - * @expose - */ - this.source = proto+""; - - /** - * Current index. - * @type {number} - * @expose - */ - this.index = 0; - - /** - * Current line. - * @type {number} - * @expose - */ - this.line = 1; - - /** - * Token stack. - * @type {!Array.} - * @expose - */ - this.stack = []; - - /** - * Opening character of the current string read, if any. - * @type {?string} - * @private - */ - this._stringOpen = null; - }; - - /** - * @alias ProtoBuf.DotProto.Tokenizer.prototype - * @inner - */ - var TokenizerPrototype = Tokenizer.prototype; - - /** - * Reads a string beginning at the current index. - * @return {string} - * @private - */ - TokenizerPrototype._readString = function() { - var re = this._stringOpen === '"' - ? Lang.STRING_DQ - : Lang.STRING_SQ; - re.lastIndex = this.index - 1; // Include the open quote - var match = re.exec(this.source); - if (!match) - throw Error("unterminated string"); - this.index = re.lastIndex; - this.stack.push(this._stringOpen); - this._stringOpen = null; - return match[1]; - }; - - /** - * Gets the next token and advances by one. - * @return {?string} Token or `null` on EOF - * @expose - */ - TokenizerPrototype.next = function() { - if (this.stack.length > 0) - return this.stack.shift(); - if (this.index >= this.source.length) - return null; - if (this._stringOpen !== null) - return this._readString(); - - var repeat, - prev, - next; - do { - repeat = false; - - // Strip white spaces - while (Lang.WHITESPACE.test(next = this.source.charAt(this.index))) { - if (next === '\n') - ++this.line; - if (++this.index === this.source.length) - return null; - } - - // Strip comments - if (this.source.charAt(this.index) === '/') { - ++this.index; - if (this.source.charAt(this.index) === '/') { // Line - while (this.source.charAt(++this.index) !== '\n') - if (this.index == this.source.length) - return null; - ++this.index; - ++this.line; - repeat = true; - } else if ((next = this.source.charAt(this.index)) === '*') { /* Block */ - do { - if (next === '\n') - ++this.line; - if (++this.index === this.source.length) - return null; - prev = next; - next = this.source.charAt(this.index); - } while (prev !== '*' || next !== '/'); - ++this.index; - repeat = true; - } else - return '/'; - } - } while (repeat); - - if (this.index === this.source.length) - return null; - - // Read the next token - var end = this.index; - Lang.DELIM.lastIndex = 0; - var delim = Lang.DELIM.test(this.source.charAt(end++)); - if (!delim) - while(end < this.source.length && !Lang.DELIM.test(this.source.charAt(end))) - ++end; - var token = this.source.substring(this.index, this.index = end); - if (token === '"' || token === "'") - this._stringOpen = token; - return token; - }; - - /** - * Peeks for the next token. - * @return {?string} Token or `null` on EOF - * @expose - */ - TokenizerPrototype.peek = function() { - if (this.stack.length === 0) { - var token = this.next(); - if (token === null) - return null; - this.stack.push(token); - } - return this.stack[0]; - }; - - /** - * Skips a specific token and throws if it differs. - * @param {string} expected Expected token - * @throws {Error} If the actual token differs - */ - TokenizerPrototype.skip = function(expected) { - var actual = this.next(); - if (actual !== expected) - throw Error("illegal '"+actual+"', '"+expected+"' expected"); - }; - - /** - * Omits an optional token. - * @param {string} expected Expected optional token - * @returns {boolean} `true` if the token exists - */ - TokenizerPrototype.omit = function(expected) { - if (this.peek() === expected) { - this.next(); - return true; - } - return false; - }; - - /** - * Returns a string representation of this object. - * @return {string} String representation as of "Tokenizer(index/length)" - * @expose - */ - TokenizerPrototype.toString = function() { - return "Tokenizer ("+this.index+"/"+this.source.length+" at line "+this.line+")"; - }; - - /** - * @alias ProtoBuf.DotProto.Tokenizer - * @expose - */ - DotProto.Tokenizer = Tokenizer; - - /** - * Constructs a new Parser. - * @exports ProtoBuf.DotProto.Parser - * @class prototype parser - * @param {string} source Source - * @constructor - */ - var Parser = function(source) { - - /** - * Tokenizer. - * @type {!ProtoBuf.DotProto.Tokenizer} - * @expose - */ - this.tn = new Tokenizer(source); - - /** - * Whether parsing proto3 or not. - * @type {boolean} - */ - this.proto3 = false; - }; - - /** - * @alias ProtoBuf.DotProto.Parser.prototype - * @inner - */ - var ParserPrototype = Parser.prototype; - - /** - * Parses the source. - * @returns {!Object} - * @throws {Error} If the source cannot be parsed - * @expose - */ - ParserPrototype.parse = function() { - var topLevel = { - "name": "[ROOT]", // temporary - "package": null, - "messages": [], - "enums": [], - "imports": [], - "options": {}, - "services": [] - // "syntax": undefined - }; - var token, - head = true, - weak; - try { - while (token = this.tn.next()) { - switch (token) { - case 'package': - if (!head || topLevel["package"] !== null) - throw Error("unexpected 'package'"); - token = this.tn.next(); - if (!Lang.TYPEREF.test(token)) - throw Error("illegal package name: " + token); - this.tn.skip(";"); - topLevel["package"] = token; - break; - case 'import': - if (!head) - throw Error("unexpected 'import'"); - token = this.tn.peek(); - if (token === "public" || (weak = token === "weak")) // token ignored - this.tn.next(); - token = this._readString(); - this.tn.skip(";"); - if (!weak) // import ignored - topLevel["imports"].push(token); - break; - case 'syntax': - if (!head) - throw Error("unexpected 'syntax'"); - this.tn.skip("="); - if ((topLevel["syntax"] = this._readString()) === "proto3") - this.proto3 = true; - this.tn.skip(";"); - break; - case 'message': - this._parseMessage(topLevel, null); - head = false; - break; - case 'enum': - this._parseEnum(topLevel); - head = false; - break; - case 'option': - this._parseOption(topLevel); - break; - case 'service': - this._parseService(topLevel); - break; - case 'extend': - this._parseExtend(topLevel); - break; - default: - throw Error("unexpected '" + token + "'"); - } - } - } catch (e) { - e.message = "Parse error at line "+this.tn.line+": " + e.message; - throw e; - } - delete topLevel["name"]; - return topLevel; - }; - - /** - * Parses the specified source. - * @returns {!Object} - * @throws {Error} If the source cannot be parsed - * @expose - */ - Parser.parse = function(source) { - return new Parser(source).parse(); - }; - - // ----- Conversion ------ - - /** - * Converts a numerical string to an id. - * @param {string} value - * @param {boolean=} mayBeNegative - * @returns {number} - * @inner - */ - function mkId(value, mayBeNegative) { - var id = -1, - sign = 1; - if (value.charAt(0) == '-') { - sign = -1; - value = value.substring(1); - } - if (Lang.NUMBER_DEC.test(value)) - id = parseInt(value); - else if (Lang.NUMBER_HEX.test(value)) - id = parseInt(value.substring(2), 16); - else if (Lang.NUMBER_OCT.test(value)) - id = parseInt(value.substring(1), 8); - else - throw Error("illegal id value: " + (sign < 0 ? '-' : '') + value); - id = (sign*id)|0; // Force to 32bit - if (!mayBeNegative && id < 0) - throw Error("illegal id value: " + (sign < 0 ? '-' : '') + value); - return id; - } - - /** - * Converts a numerical string to a number. - * @param {string} val - * @returns {number} - * @inner - */ - function mkNumber(val) { - var sign = 1; - if (val.charAt(0) == '-') { - sign = -1; - val = val.substring(1); - } - if (Lang.NUMBER_DEC.test(val)) - return sign * parseInt(val, 10); - else if (Lang.NUMBER_HEX.test(val)) - return sign * parseInt(val.substring(2), 16); - else if (Lang.NUMBER_OCT.test(val)) - return sign * parseInt(val.substring(1), 8); - else if (val === 'inf') - return sign * Infinity; - else if (val === 'nan') - return NaN; - else if (Lang.NUMBER_FLT.test(val)) - return sign * parseFloat(val); - throw Error("illegal number value: " + (sign < 0 ? '-' : '') + val); - } - - // ----- Reading ------ - - /** - * Reads a string. - * @returns {string} - * @private - */ - ParserPrototype._readString = function() { - var value = "", - token, - delim; - do { - delim = this.tn.next(); - if (delim !== "'" && delim !== '"') - throw Error("illegal string delimiter: "+delim); - value += this.tn.next(); - this.tn.skip(delim); - token = this.tn.peek(); - } while (token === '"' || token === '"'); // multi line? - return value; - }; - - /** - * Reads a value. - * @param {boolean=} mayBeTypeRef - * @returns {number|boolean|string} - * @private - */ - ParserPrototype._readValue = function(mayBeTypeRef) { - var token = this.tn.peek(), - value; - if (token === '"' || token === "'") - return this._readString(); - this.tn.next(); - if (Lang.NUMBER.test(token)) - return mkNumber(token); - if (Lang.BOOL.test(token)) - return (token.toLowerCase() === 'true'); - if (mayBeTypeRef && Lang.TYPEREF.test(token)) - return token; - throw Error("illegal value: "+token); - - }; - - // ----- Parsing constructs ----- - - /** - * Parses a namespace option. - * @param {!Object} parent Parent definition - * @param {boolean=} isList - * @private - */ - ParserPrototype._parseOption = function(parent, isList) { - var token = this.tn.next(), - custom = false; - if (token === '(') { - custom = true; - token = this.tn.next(); - } - if (!Lang.TYPEREF.test(token)) - // we can allow options of the form google.protobuf.* since they will just get ignored anyways - // if (!/google\.protobuf\./.test(token)) // FIXME: Why should that not be a valid typeref? - throw Error("illegal option name: "+token); - var name = token; - if (custom) { // (my_method_option).foo, (my_method_option), some_method_option, (foo.my_option).bar - this.tn.skip(')'); - name = '('+name+')'; - token = this.tn.peek(); - if (Lang.FQTYPEREF.test(token)) { - name += token; - this.tn.next(); - } - } - this.tn.skip('='); - this._parseOptionValue(parent, name); - if (!isList) - this.tn.skip(";"); - }; - - /** - * Sets an option on the specified options object. - * @param {!Object.} options - * @param {string} name - * @param {string|number|boolean} value - * @inner - */ - function setOption(options, name, value) { - if (typeof options[name] === 'undefined') - options[name] = value; - else { - if (!Array.isArray(options[name])) - options[name] = [ options[name] ]; - options[name].push(value); - } - } - - /** - * Parses an option value. - * @param {!Object} parent - * @param {string} name - * @private - */ - ParserPrototype._parseOptionValue = function(parent, name) { - var token = this.tn.peek(); - if (token !== '{') { // Plain value - setOption(parent["options"], name, this._readValue(true)); - } else { // Aggregate options - this.tn.skip("{"); - while ((token = this.tn.next()) !== '}') { - if (!Lang.NAME.test(token)) - throw Error("illegal option name: " + name + "." + token); - if (this.tn.omit(":")) - setOption(parent["options"], name + "." + token, this._readValue(true)); - else - this._parseOptionValue(parent, name + "." + token); - } - } - }; - - /** - * Parses a service definition. - * @param {!Object} parent Parent definition - * @private - */ - ParserPrototype._parseService = function(parent) { - var token = this.tn.next(); - if (!Lang.NAME.test(token)) - throw Error("illegal service name at line "+this.tn.line+": "+token); - var name = token; - var svc = { - "name": name, - "rpc": {}, - "options": {} - }; - this.tn.skip("{"); - while ((token = this.tn.next()) !== '}') { - if (token === "option") - this._parseOption(svc); - else if (token === 'rpc') - this._parseServiceRPC(svc); - else - throw Error("illegal service token: "+token); - } - this.tn.omit(";"); - parent["services"].push(svc); - }; - - /** - * Parses a RPC service definition of the form ['rpc', name, (request), 'returns', (response)]. - * @param {!Object} svc Service definition - * @private - */ - ParserPrototype._parseServiceRPC = function(svc) { - var type = "rpc", - token = this.tn.next(); - if (!Lang.NAME.test(token)) - throw Error("illegal rpc service method name: "+token); - var name = token; - var method = { - "request": null, - "response": null, - "request_stream": false, - "response_stream": false, - "options": {} - }; - this.tn.skip("("); - token = this.tn.next(); - if (token.toLowerCase() === "stream") { - method["request_stream"] = true; - token = this.tn.next(); - } - if (!Lang.TYPEREF.test(token)) - throw Error("illegal rpc service request type: "+token); - method["request"] = token; - this.tn.skip(")"); - token = this.tn.next(); - if (token.toLowerCase() !== "returns") - throw Error("illegal rpc service request type delimiter: "+token); - this.tn.skip("("); - token = this.tn.next(); - if (token.toLowerCase() === "stream") { - method["response_stream"] = true; - token = this.tn.next(); - } - method["response"] = token; - this.tn.skip(")"); - token = this.tn.peek(); - if (token === '{') { - this.tn.next(); - while ((token = this.tn.next()) !== '}') { - if (token === 'option') - this._parseOption(method); - else - throw Error("illegal rpc service token: " + token); - } - this.tn.omit(";"); - } else - this.tn.skip(";"); - if (typeof svc[type] === 'undefined') - svc[type] = {}; - svc[type][name] = method; - }; - - /** - * Parses a message definition. - * @param {!Object} parent Parent definition - * @param {!Object=} fld Field definition if this is a group - * @returns {!Object} - * @private - */ - ParserPrototype._parseMessage = function(parent, fld) { - var isGroup = !!fld, - token = this.tn.next(); - var msg = { - "name": "", - "fields": [], - "enums": [], - "messages": [], - "options": {}, - "services": [], - "oneofs": {} - // "extensions": undefined - }; - if (!Lang.NAME.test(token)) - throw Error("illegal "+(isGroup ? "group" : "message")+" name: "+token); - msg["name"] = token; - if (isGroup) { - this.tn.skip("="); - fld["id"] = mkId(this.tn.next()); - msg["isGroup"] = true; - } - token = this.tn.peek(); - if (token === '[' && fld) - this._parseFieldOptions(fld); - this.tn.skip("{"); - while ((token = this.tn.next()) !== '}') { - if (Lang.RULE.test(token)) - this._parseMessageField(msg, token); - else if (token === "oneof") - this._parseMessageOneOf(msg); - else if (token === "enum") - this._parseEnum(msg); - else if (token === "message") - this._parseMessage(msg); - else if (token === "option") - this._parseOption(msg); - else if (token === "service") - this._parseService(msg); - else if (token === "extensions") - msg["extensions"] = this._parseExtensionRanges(); - else if (token === "reserved") - this._parseIgnored(); // TODO - else if (token === "extend") - this._parseExtend(msg); - else if (Lang.TYPEREF.test(token)) { - if (!this.proto3) - throw Error("illegal field rule: "+token); - this._parseMessageField(msg, "optional", token); - } else - throw Error("illegal message token: "+token); - } - this.tn.omit(";"); - parent["messages"].push(msg); - return msg; - }; - - /** - * Parses an ignored statement. - * @private - */ - ParserPrototype._parseIgnored = function() { - while (this.tn.peek() !== ';') - this.tn.next(); - this.tn.skip(";"); - }; - - /** - * Parses a message field. - * @param {!Object} msg Message definition - * @param {string} rule Field rule - * @param {string=} type Field type if already known (never known for maps) - * @returns {!Object} Field descriptor - * @private - */ - ParserPrototype._parseMessageField = function(msg, rule, type) { - if (!Lang.RULE.test(rule)) - throw Error("illegal message field rule: "+rule); - var fld = { - "rule": rule, - "type": "", - "name": "", - "options": {}, - "id": 0 - }; - var token; - if (rule === "map") { - - if (type) - throw Error("illegal type: " + type); - this.tn.skip('<'); - token = this.tn.next(); - if (!Lang.TYPE.test(token) && !Lang.TYPEREF.test(token)) - throw Error("illegal message field type: " + token); - fld["keytype"] = token; - this.tn.skip(','); - token = this.tn.next(); - if (!Lang.TYPE.test(token) && !Lang.TYPEREF.test(token)) - throw Error("illegal message field: " + token); - fld["type"] = token; - this.tn.skip('>'); - token = this.tn.next(); - if (!Lang.NAME.test(token)) - throw Error("illegal message field name: " + token); - fld["name"] = token; - this.tn.skip("="); - fld["id"] = mkId(this.tn.next()); - token = this.tn.peek(); - if (token === '[') - this._parseFieldOptions(fld); - this.tn.skip(";"); - - } else { - - type = typeof type !== 'undefined' ? type : this.tn.next(); - - if (type === "group") { - - // "A [legacy] group simply combines a nested message type and a field into a single declaration. In your - // code, you can treat this message just as if it had a Result type field called result (the latter name is - // converted to lower-case so that it does not conflict with the former)." - var grp = this._parseMessage(msg, fld); - if (!/^[A-Z]/.test(grp["name"])) - throw Error('illegal group name: '+grp["name"]); - fld["type"] = grp["name"]; - fld["name"] = grp["name"].toLowerCase(); - this.tn.omit(";"); - - } else { - - if (!Lang.TYPE.test(type) && !Lang.TYPEREF.test(type)) - throw Error("illegal message field type: " + type); - fld["type"] = type; - token = this.tn.next(); - if (!Lang.NAME.test(token)) - throw Error("illegal message field name: " + token); - fld["name"] = token; - this.tn.skip("="); - fld["id"] = mkId(this.tn.next()); - token = this.tn.peek(); - if (token === "[") - this._parseFieldOptions(fld); - this.tn.skip(";"); - - } - } - msg["fields"].push(fld); - return fld; - }; - - /** - * Parses a message oneof. - * @param {!Object} msg Message definition - * @private - */ - ParserPrototype._parseMessageOneOf = function(msg) { - var token = this.tn.next(); - if (!Lang.NAME.test(token)) - throw Error("illegal oneof name: "+token); - var name = token, - fld; - var fields = []; - this.tn.skip("{"); - while ((token = this.tn.next()) !== "}") { - fld = this._parseMessageField(msg, "optional", token); - fld["oneof"] = name; - fields.push(fld["id"]); - } - this.tn.omit(";"); - msg["oneofs"][name] = fields; - }; - - /** - * Parses a set of field option definitions. - * @param {!Object} fld Field definition - * @private - */ - ParserPrototype._parseFieldOptions = function(fld) { - this.tn.skip("["); - var token, - first = true; - while ((token = this.tn.peek()) !== ']') { - if (!first) - this.tn.skip(","); - this._parseOption(fld, true); - first = false; - } - this.tn.next(); - }; - - /** - * Parses an enum. - * @param {!Object} msg Message definition - * @private - */ - ParserPrototype._parseEnum = function(msg) { - var enm = { - "name": "", - "values": [], - "options": {} - }; - var token = this.tn.next(); - if (!Lang.NAME.test(token)) - throw Error("illegal name: "+token); - enm["name"] = token; - this.tn.skip("{"); - while ((token = this.tn.next()) !== '}') { - if (token === "option") - this._parseOption(enm); - else { - if (!Lang.NAME.test(token)) - throw Error("illegal name: "+token); - this.tn.skip("="); - var val = { - "name": token, - "id": mkId(this.tn.next(), true) - }; - token = this.tn.peek(); - if (token === "[") - this._parseFieldOptions({ "options": {} }); - this.tn.skip(";"); - enm["values"].push(val); - } - } - this.tn.omit(";"); - msg["enums"].push(enm); - }; - - /** - * Parses extension / reserved ranges. - * @returns {!Array.>} - * @private - */ - ParserPrototype._parseExtensionRanges = function() { - var ranges = []; - var token, - range, - value; - do { - range = []; - while (true) { - token = this.tn.next(); - switch (token) { - case "min": - value = ProtoBuf.ID_MIN; - break; - case "max": - value = ProtoBuf.ID_MAX; - break; - default: - value = mkNumber(token); - break; - } - range.push(value); - if (range.length === 2) - break; - if (this.tn.peek() !== "to") { - range.push(value); - break; - } - this.tn.next(); - } - ranges.push(range); - } while (this.tn.omit(",")); - this.tn.skip(";"); - return ranges; - }; - - /** - * Parses an extend block. - * @param {!Object} parent Parent object - * @private - */ - ParserPrototype._parseExtend = function(parent) { - var token = this.tn.next(); - if (!Lang.TYPEREF.test(token)) - throw Error("illegal extend reference: "+token); - var ext = { - "ref": token, - "fields": [] - }; - this.tn.skip("{"); - while ((token = this.tn.next()) !== '}') { - if (Lang.RULE.test(token)) - this._parseMessageField(ext, token); - else if (Lang.TYPEREF.test(token)) { - if (!this.proto3) - throw Error("illegal field rule: "+token); - this._parseMessageField(ext, "optional", token); - } else - throw Error("illegal extend token: "+token); - } - this.tn.omit(";"); - parent["messages"].push(ext); - return ext; - }; - - // ----- General ----- - - /** - * Returns a string representation of this parser. - * @returns {string} - */ - ParserPrototype.toString = function() { - return "Parser at line "+this.tn.line; - }; - - /** - * @alias ProtoBuf.DotProto.Parser - * @expose - */ - DotProto.Parser = Parser; - - return DotProto; - - })(ProtoBuf, ProtoBuf.Lang); - - /** - * @alias ProtoBuf.Reflect - * @expose - */ - ProtoBuf.Reflect = (function(ProtoBuf) { - "use strict"; - - /** - * Reflection types. - * @exports ProtoBuf.Reflect - * @namespace - */ - var Reflect = {}; - - /** - * Constructs a Reflect base class. - * @exports ProtoBuf.Reflect.T - * @constructor - * @abstract - * @param {!ProtoBuf.Builder} builder Builder reference - * @param {?ProtoBuf.Reflect.T} parent Parent object - * @param {string} name Object name - */ - var T = function(builder, parent, name) { - - /** - * Builder reference. - * @type {!ProtoBuf.Builder} - * @expose - */ - this.builder = builder; - - /** - * Parent object. - * @type {?ProtoBuf.Reflect.T} - * @expose - */ - this.parent = parent; - - /** - * Object name in namespace. - * @type {string} - * @expose - */ - this.name = name; - - /** - * Fully qualified class name - * @type {string} - * @expose - */ - this.className; - }; - - /** - * @alias ProtoBuf.Reflect.T.prototype - * @inner - */ - var TPrototype = T.prototype; - - /** - * Returns the fully qualified name of this object. - * @returns {string} Fully qualified name as of ".PATH.TO.THIS" - * @expose - */ - TPrototype.fqn = function() { - var name = this.name, - ptr = this; - do { - ptr = ptr.parent; - if (ptr == null) - break; - name = ptr.name+"."+name; - } while (true); - return name; - }; - - /** - * Returns a string representation of this Reflect object (its fully qualified name). - * @param {boolean=} includeClass Set to true to include the class name. Defaults to false. - * @return String representation - * @expose - */ - TPrototype.toString = function(includeClass) { - return (includeClass ? this.className + " " : "") + this.fqn(); - }; - - /** - * Builds this type. - * @throws {Error} If this type cannot be built directly - * @expose - */ - TPrototype.build = function() { - throw Error(this.toString(true)+" cannot be built directly"); - }; - - /** - * @alias ProtoBuf.Reflect.T - * @expose - */ - Reflect.T = T; - - /** - * Constructs a new Namespace. - * @exports ProtoBuf.Reflect.Namespace - * @param {!ProtoBuf.Builder} builder Builder reference - * @param {?ProtoBuf.Reflect.Namespace} parent Namespace parent - * @param {string} name Namespace name - * @param {Object.=} options Namespace options - * @param {string?} syntax The syntax level of this definition (e.g., proto3) - * @constructor - * @extends ProtoBuf.Reflect.T - */ - var Namespace = function(builder, parent, name, options, syntax) { - T.call(this, builder, parent, name); - - /** - * @override - */ - this.className = "Namespace"; - - /** - * Children inside the namespace. - * @type {!Array.} - */ - this.children = []; - - /** - * Options. - * @type {!Object.} - */ - this.options = options || {}; - - /** - * Syntax level (e.g., proto2 or proto3). - * @type {!string} - */ - this.syntax = syntax || "proto2"; - }; - - /** - * @alias ProtoBuf.Reflect.Namespace.prototype - * @inner - */ - var NamespacePrototype = Namespace.prototype = Object.create(T.prototype); - - /** - * Returns an array of the namespace's children. - * @param {ProtoBuf.Reflect.T=} type Filter type (returns instances of this type only). Defaults to null (all children). - * @return {Array.} - * @expose - */ - NamespacePrototype.getChildren = function(type) { - type = type || null; - if (type == null) - return this.children.slice(); - var children = []; - for (var i=0, k=this.children.length; i} qn Qualified name to resolve - * @param {boolean=} excludeNonNamespace Excludes non-namespace types, defaults to `false` - * @return {?ProtoBuf.Reflect.Namespace} The resolved type or null if not found - * @expose - */ - NamespacePrototype.resolve = function(qn, excludeNonNamespace) { - var part = typeof qn === 'string' ? qn.split(".") : qn, - ptr = this, - i = 0; - if (part[i] === "") { // Fully qualified name, e.g. ".My.Message' - while (ptr.parent !== null) - ptr = ptr.parent; - i++; - } - var child; - do { - do { - if (!(ptr instanceof Reflect.Namespace)) { - ptr = null; - break; - } - child = ptr.getChild(part[i]); - if (!child || !(child instanceof Reflect.T) || (excludeNonNamespace && !(child instanceof Reflect.Namespace))) { - ptr = null; - break; - } - ptr = child; i++; - } while (i < part.length); - if (ptr != null) - break; // Found - // Else search the parent - if (this.parent !== null) - return this.parent.resolve(qn, excludeNonNamespace); - } while (ptr != null); - return ptr; - }; - - /** - * Determines the shortest qualified name of the specified type, if any, relative to this namespace. - * @param {!ProtoBuf.Reflect.T} t Reflection type - * @returns {string} The shortest qualified name or, if there is none, the fqn - * @expose - */ - NamespacePrototype.qn = function(t) { - var part = [], ptr = t; - do { - part.unshift(ptr.name); - ptr = ptr.parent; - } while (ptr !== null); - for (var len=1; len <= part.length; len++) { - var qn = part.slice(part.length-len); - if (t === this.resolve(qn, t instanceof Reflect.Namespace)) - return qn.join("."); - } - return t.fqn(); - }; - - /** - * Builds the namespace and returns the runtime counterpart. - * @return {Object.} Runtime namespace - * @expose - */ - NamespacePrototype.build = function() { - /** @dict */ - var ns = {}; - var children = this.children; - for (var i=0, k=children.length, child; i} - */ - NamespacePrototype.buildOpt = function() { - var opt = {}, - keys = Object.keys(this.options); - for (var i=0, k=keys.length; i}null} Option value or NULL if there is no such option - */ - NamespacePrototype.getOption = function(name) { - if (typeof name === 'undefined') - return this.options; - return typeof this.options[name] !== 'undefined' ? this.options[name] : null; - }; - - /** - * @alias ProtoBuf.Reflect.Namespace - * @expose - */ - Reflect.Namespace = Namespace; - - /** - * Constructs a new Element implementation that checks and converts values for a - * particular field type, as appropriate. - * - * An Element represents a single value: either the value of a singular field, - * or a value contained in one entry of a repeated field or map field. This - * class does not implement these higher-level concepts; it only encapsulates - * the low-level typechecking and conversion. - * - * @exports ProtoBuf.Reflect.Element - * @param {{name: string, wireType: number}} type Resolved data type - * @param {ProtoBuf.Reflect.T|null} resolvedType Resolved type, if relevant - * (e.g. submessage field). - * @param {boolean} isMapKey Is this element a Map key? The value will be - * converted to string form if so. - * @param {string} syntax Syntax level of defining message type, e.g., - * proto2 or proto3. - * @constructor - */ - var Element = function(type, resolvedType, isMapKey, syntax) { - - /** - * Element type, as a string (e.g., int32). - * @type {{name: string, wireType: number}} - */ - this.type = type; - - /** - * Element type reference to submessage or enum definition, if needed. - * @type {ProtoBuf.Reflect.T|null} - */ - this.resolvedType = resolvedType; - - /** - * Element is a map key. - * @type {boolean} - */ - this.isMapKey = isMapKey; - - /** - * Syntax level of defining message type, e.g., proto2 or proto3. - * @type {string} - */ - this.syntax = syntax; - - if (isMapKey && ProtoBuf.MAP_KEY_TYPES.indexOf(type) < 0) - throw Error("Invalid map key type: " + type.name); - }; - - var ElementPrototype = Element.prototype; - - /** - * Obtains a (new) default value for the specified type. - * @param type {string|{name: string, wireType: number}} Field type - * @returns {*} Default value - * @inner - */ - function mkDefault(type) { - if (typeof type === 'string') - type = ProtoBuf.TYPES[type]; - if (typeof type.defaultValue === 'undefined') - throw Error("default value for type "+type.name+" is not supported"); - if (type == ProtoBuf.TYPES["bytes"]) - return new ByteBuffer(0); - return type.defaultValue; - } - - /** - * Returns the default value for this field in proto3. - * @function - * @param type {string|{name: string, wireType: number}} the field type - * @returns {*} Default value - */ - Element.defaultFieldValue = mkDefault; - - /** - * Makes a Long from a value. - * @param {{low: number, high: number, unsigned: boolean}|string|number} value Value - * @param {boolean=} unsigned Whether unsigned or not, defaults to reuse it from Long-like objects or to signed for - * strings and numbers - * @returns {!Long} - * @throws {Error} If the value cannot be converted to a Long - * @inner - */ - function mkLong(value, unsigned) { - if (value && typeof value.low === 'number' && typeof value.high === 'number' && typeof value.unsigned === 'boolean' - && value.low === value.low && value.high === value.high) - return new ProtoBuf.Long(value.low, value.high, typeof unsigned === 'undefined' ? value.unsigned : unsigned); - if (typeof value === 'string') - return ProtoBuf.Long.fromString(value, unsigned || false, 10); - if (typeof value === 'number') - return ProtoBuf.Long.fromNumber(value, unsigned || false); - throw Error("not convertible to Long"); - } - - /** - * Checks if the given value can be set for an element of this type (singular - * field or one element of a repeated field or map). - * @param {*} value Value to check - * @return {*} Verified, maybe adjusted, value - * @throws {Error} If the value cannot be verified for this element slot - * @expose - */ - ElementPrototype.verifyValue = function(value) { - var self = this; - function fail(val, msg) { - throw Error("Illegal value for "+self.toString(true)+" of type "+self.type.name+": "+val+" ("+msg+")"); - } - switch (this.type) { - // Signed 32bit - case ProtoBuf.TYPES["int32"]: - case ProtoBuf.TYPES["sint32"]: - case ProtoBuf.TYPES["sfixed32"]: - // Account for !NaN: value === value - if (typeof value !== 'number' || (value === value && value % 1 !== 0)) - fail(typeof value, "not an integer"); - return value > 4294967295 ? value | 0 : value; - - // Unsigned 32bit - case ProtoBuf.TYPES["uint32"]: - case ProtoBuf.TYPES["fixed32"]: - if (typeof value !== 'number' || (value === value && value % 1 !== 0)) - fail(typeof value, "not an integer"); - return value < 0 ? value >>> 0 : value; - - // Signed 64bit - case ProtoBuf.TYPES["int64"]: - case ProtoBuf.TYPES["sint64"]: - case ProtoBuf.TYPES["sfixed64"]: { - if (ProtoBuf.Long) - try { - return mkLong(value, false); - } catch (e) { - fail(typeof value, e.message); - } - else - fail(typeof value, "requires Long.js"); - } - - // Unsigned 64bit - case ProtoBuf.TYPES["uint64"]: - case ProtoBuf.TYPES["fixed64"]: { - if (ProtoBuf.Long) - try { - return mkLong(value, true); - } catch (e) { - fail(typeof value, e.message); - } - else - fail(typeof value, "requires Long.js"); - } - - // Bool - case ProtoBuf.TYPES["bool"]: - if (typeof value !== 'boolean') - fail(typeof value, "not a boolean"); - return value; - - // Float - case ProtoBuf.TYPES["float"]: - case ProtoBuf.TYPES["double"]: - if (typeof value !== 'number') - fail(typeof value, "not a number"); - return value; - - // Length-delimited string - case ProtoBuf.TYPES["string"]: - if (typeof value !== 'string' && !(value && value instanceof String)) - fail(typeof value, "not a string"); - return ""+value; // Convert String object to string - - // Length-delimited bytes - case ProtoBuf.TYPES["bytes"]: - if (ByteBuffer.isByteBuffer(value)) - return value; - return ByteBuffer.wrap(value, "base64"); - - // Constant enum value - case ProtoBuf.TYPES["enum"]: { - var values = this.resolvedType.getChildren(ProtoBuf.Reflect.Enum.Value); - for (i=0; i 4294967295 || value < 0) - fail(typeof value, "not in range for uint32") - return value; - } else { - // proto2 requires enum values to be valid. - fail(value, "not a valid enum value"); - } - } - // Embedded message - case ProtoBuf.TYPES["group"]: - case ProtoBuf.TYPES["message"]: { - if (!value || typeof value !== 'object') - fail(typeof value, "object expected"); - if (value instanceof this.resolvedType.clazz) - return value; - if (value instanceof ProtoBuf.Builder.Message) { - // Mismatched type: Convert to object (see: https://github.com/dcodeIO/ProtoBuf.js/issues/180) - var obj = {}; - for (var i in value) - if (value.hasOwnProperty(i)) - obj[i] = value[i]; - value = obj; - } - // Else let's try to construct one from a key-value object - return new (this.resolvedType.clazz)(value); // May throw for a hundred of reasons - } - } - - // We should never end here - throw Error("[INTERNAL] Illegal value for "+this.toString(true)+": "+value+" (undefined type "+this.type+")"); - }; - - /** - * Calculates the byte length of an element on the wire. - * @param {number} id Field number - * @param {*} value Field value - * @returns {number} Byte length - * @throws {Error} If the value cannot be calculated - * @expose - */ - ElementPrototype.calculateLength = function(id, value) { - if (value === null) return 0; // Nothing to encode - // Tag has already been written - var n; - switch (this.type) { - case ProtoBuf.TYPES["int32"]: - return value < 0 ? ByteBuffer.calculateVarint64(value) : ByteBuffer.calculateVarint32(value); - case ProtoBuf.TYPES["uint32"]: - return ByteBuffer.calculateVarint32(value); - case ProtoBuf.TYPES["sint32"]: - return ByteBuffer.calculateVarint32(ByteBuffer.zigZagEncode32(value)); - case ProtoBuf.TYPES["fixed32"]: - case ProtoBuf.TYPES["sfixed32"]: - case ProtoBuf.TYPES["float"]: - return 4; - case ProtoBuf.TYPES["int64"]: - case ProtoBuf.TYPES["uint64"]: - return ByteBuffer.calculateVarint64(value); - case ProtoBuf.TYPES["sint64"]: - return ByteBuffer.calculateVarint64(ByteBuffer.zigZagEncode64(value)); - case ProtoBuf.TYPES["fixed64"]: - case ProtoBuf.TYPES["sfixed64"]: - return 8; - case ProtoBuf.TYPES["bool"]: - return 1; - case ProtoBuf.TYPES["enum"]: - return ByteBuffer.calculateVarint32(value); - case ProtoBuf.TYPES["double"]: - return 8; - case ProtoBuf.TYPES["string"]: - n = ByteBuffer.calculateUTF8Bytes(value); - return ByteBuffer.calculateVarint32(n) + n; - case ProtoBuf.TYPES["bytes"]: - if (value.remaining() < 0) - throw Error("Illegal value for "+this.toString(true)+": "+value.remaining()+" bytes remaining"); - return ByteBuffer.calculateVarint32(value.remaining()) + value.remaining(); - case ProtoBuf.TYPES["message"]: - n = this.resolvedType.calculate(value); - return ByteBuffer.calculateVarint32(n) + n; - case ProtoBuf.TYPES["group"]: - n = this.resolvedType.calculate(value); - return n + ByteBuffer.calculateVarint32((id << 3) | ProtoBuf.WIRE_TYPES.ENDGROUP); - } - // We should never end here - throw Error("[INTERNAL] Illegal value to encode in "+this.toString(true)+": "+value+" (unknown type)"); - }; - - /** - * Encodes a value to the specified buffer. Does not encode the key. - * @param {number} id Field number - * @param {*} value Field value - * @param {ByteBuffer} buffer ByteBuffer to encode to - * @return {ByteBuffer} The ByteBuffer for chaining - * @throws {Error} If the value cannot be encoded - * @expose - */ - ElementPrototype.encodeValue = function(id, value, buffer) { - if (value === null) return buffer; // Nothing to encode - // Tag has already been written - - switch (this.type) { - // 32bit signed varint - case ProtoBuf.TYPES["int32"]: - // "If you use int32 or int64 as the type for a negative number, the resulting varint is always ten bytes - // long – it is, effectively, treated like a very large unsigned integer." (see #122) - if (value < 0) - buffer.writeVarint64(value); - else - buffer.writeVarint32(value); - break; - - // 32bit unsigned varint - case ProtoBuf.TYPES["uint32"]: - buffer.writeVarint32(value); - break; - - // 32bit varint zig-zag - case ProtoBuf.TYPES["sint32"]: - buffer.writeVarint32ZigZag(value); - break; - - // Fixed unsigned 32bit - case ProtoBuf.TYPES["fixed32"]: - buffer.writeUint32(value); - break; - - // Fixed signed 32bit - case ProtoBuf.TYPES["sfixed32"]: - buffer.writeInt32(value); - break; - - // 64bit varint as-is - case ProtoBuf.TYPES["int64"]: - case ProtoBuf.TYPES["uint64"]: - buffer.writeVarint64(value); // throws - break; - - // 64bit varint zig-zag - case ProtoBuf.TYPES["sint64"]: - buffer.writeVarint64ZigZag(value); // throws - break; - - // Fixed unsigned 64bit - case ProtoBuf.TYPES["fixed64"]: - buffer.writeUint64(value); // throws - break; - - // Fixed signed 64bit - case ProtoBuf.TYPES["sfixed64"]: - buffer.writeInt64(value); // throws - break; - - // Bool - case ProtoBuf.TYPES["bool"]: - if (typeof value === 'string') - buffer.writeVarint32(value.toLowerCase() === 'false' ? 0 : !!value); - else - buffer.writeVarint32(value ? 1 : 0); - break; - - // Constant enum value - case ProtoBuf.TYPES["enum"]: - buffer.writeVarint32(value); - break; - - // 32bit float - case ProtoBuf.TYPES["float"]: - buffer.writeFloat32(value); - break; - - // 64bit float - case ProtoBuf.TYPES["double"]: - buffer.writeFloat64(value); - break; - - // Length-delimited string - case ProtoBuf.TYPES["string"]: - buffer.writeVString(value); - break; - - // Length-delimited bytes - case ProtoBuf.TYPES["bytes"]: - if (value.remaining() < 0) - throw Error("Illegal value for "+this.toString(true)+": "+value.remaining()+" bytes remaining"); - var prevOffset = value.offset; - buffer.writeVarint32(value.remaining()); - buffer.append(value); - value.offset = prevOffset; - break; - - // Embedded message - case ProtoBuf.TYPES["message"]: - var bb = new ByteBuffer().LE(); - this.resolvedType.encode(value, bb); - buffer.writeVarint32(bb.offset); - buffer.append(bb.flip()); - break; - - // Legacy group - case ProtoBuf.TYPES["group"]: - this.resolvedType.encode(value, buffer); - buffer.writeVarint32((id << 3) | ProtoBuf.WIRE_TYPES.ENDGROUP); - break; - - default: - // We should never end here - throw Error("[INTERNAL] Illegal value to encode in "+this.toString(true)+": "+value+" (unknown type)"); - } - return buffer; - }; - - /** - * Decode one element value from the specified buffer. - * @param {ByteBuffer} buffer ByteBuffer to decode from - * @param {number} wireType The field wire type - * @param {number} id The field number - * @return {*} Decoded value - * @throws {Error} If the field cannot be decoded - * @expose - */ - ElementPrototype.decode = function(buffer, wireType, id) { - if (wireType != this.type.wireType) - throw Error("Unexpected wire type for element"); - - var value, nBytes; - switch (this.type) { - // 32bit signed varint - case ProtoBuf.TYPES["int32"]: - return buffer.readVarint32() | 0; - - // 32bit unsigned varint - case ProtoBuf.TYPES["uint32"]: - return buffer.readVarint32() >>> 0; - - // 32bit signed varint zig-zag - case ProtoBuf.TYPES["sint32"]: - return buffer.readVarint32ZigZag() | 0; - - // Fixed 32bit unsigned - case ProtoBuf.TYPES["fixed32"]: - return buffer.readUint32() >>> 0; - - case ProtoBuf.TYPES["sfixed32"]: - return buffer.readInt32() | 0; - - // 64bit signed varint - case ProtoBuf.TYPES["int64"]: - return buffer.readVarint64(); - - // 64bit unsigned varint - case ProtoBuf.TYPES["uint64"]: - return buffer.readVarint64().toUnsigned(); - - // 64bit signed varint zig-zag - case ProtoBuf.TYPES["sint64"]: - return buffer.readVarint64ZigZag(); - - // Fixed 64bit unsigned - case ProtoBuf.TYPES["fixed64"]: - return buffer.readUint64(); - - // Fixed 64bit signed - case ProtoBuf.TYPES["sfixed64"]: - return buffer.readInt64(); - - // Bool varint - case ProtoBuf.TYPES["bool"]: - return !!buffer.readVarint32(); - - // Constant enum value (varint) - case ProtoBuf.TYPES["enum"]: - // The following Builder.Message#set will already throw - return buffer.readVarint32(); - - // 32bit float - case ProtoBuf.TYPES["float"]: - return buffer.readFloat(); - - // 64bit float - case ProtoBuf.TYPES["double"]: - return buffer.readDouble(); - - // Length-delimited string - case ProtoBuf.TYPES["string"]: - return buffer.readVString(); - - // Length-delimited bytes - case ProtoBuf.TYPES["bytes"]: { - nBytes = buffer.readVarint32(); - if (buffer.remaining() < nBytes) - throw Error("Illegal number of bytes for "+this.toString(true)+": "+nBytes+" required but got only "+buffer.remaining()); - value = buffer.clone(); // Offset already set - value.limit = value.offset+nBytes; - buffer.offset += nBytes; - return value; - } - - // Length-delimited embedded message - case ProtoBuf.TYPES["message"]: { - nBytes = buffer.readVarint32(); - return this.resolvedType.decode(buffer, nBytes); - } - - // Legacy group - case ProtoBuf.TYPES["group"]: - return this.resolvedType.decode(buffer, -1, id); - } - - // We should never end here - throw Error("[INTERNAL] Illegal decode type"); - }; - - /** - * Converts a value from a string to the canonical element type. - * - * Legal only when isMapKey is true. - * - * @param {string} str The string value - * @returns {*} The value - */ - ElementPrototype.valueFromString = function(str) { - if (!this.isMapKey) { - throw Error("valueFromString() called on non-map-key element"); - } - - switch (this.type) { - case ProtoBuf.TYPES["int32"]: - case ProtoBuf.TYPES["sint32"]: - case ProtoBuf.TYPES["sfixed32"]: - case ProtoBuf.TYPES["uint32"]: - case ProtoBuf.TYPES["fixed32"]: - return this.verifyValue(parseInt(str)); - - case ProtoBuf.TYPES["int64"]: - case ProtoBuf.TYPES["sint64"]: - case ProtoBuf.TYPES["sfixed64"]: - case ProtoBuf.TYPES["uint64"]: - case ProtoBuf.TYPES["fixed64"]: - // Long-based fields support conversions from string already. - return this.verifyValue(str); - - case ProtoBuf.TYPES["bool"]: - return str === "true"; - - case ProtoBuf.TYPES["string"]: - return this.verifyValue(str); - - case ProtoBuf.TYPES["bytes"]: - return ByteBuffer.fromBinary(str); - } - }; - - /** - * Converts a value from the canonical element type to a string. - * - * It should be the case that `valueFromString(valueToString(val))` returns - * a value equivalent to `verifyValue(val)` for every legal value of `val` - * according to this element type. - * - * This may be used when the element must be stored or used as a string, - * e.g., as a map key on an Object. - * - * Legal only when isMapKey is true. - * - * @param {*} val The value - * @returns {string} The string form of the value. - */ - ElementPrototype.valueToString = function(value) { - if (!this.isMapKey) { - throw Error("valueToString() called on non-map-key element"); - } - - if (this.type === ProtoBuf.TYPES["bytes"]) { - return value.toString("binary"); - } else { - return value.toString(); - } - }; - - /** - * @alias ProtoBuf.Reflect.Element - * @expose - */ - Reflect.Element = Element; - - /** - * Constructs a new Message. - * @exports ProtoBuf.Reflect.Message - * @param {!ProtoBuf.Builder} builder Builder reference - * @param {!ProtoBuf.Reflect.Namespace} parent Parent message or namespace - * @param {string} name Message name - * @param {Object.=} options Message options - * @param {boolean=} isGroup `true` if this is a legacy group - * @param {string?} syntax The syntax level of this definition (e.g., proto3) - * @constructor - * @extends ProtoBuf.Reflect.Namespace - */ - var Message = function(builder, parent, name, options, isGroup, syntax) { - Namespace.call(this, builder, parent, name, options, syntax); - - /** - * @override - */ - this.className = "Message"; - - /** - * Extensions range. - * @type {!Array.|undefined} - * @expose - */ - this.extensions = undefined; - - /** - * Runtime message class. - * @type {?function(new:ProtoBuf.Builder.Message)} - * @expose - */ - this.clazz = null; - - /** - * Whether this is a legacy group or not. - * @type {boolean} - * @expose - */ - this.isGroup = !!isGroup; - - // The following cached collections are used to efficiently iterate over or look up fields when decoding. - - /** - * Cached fields. - * @type {?Array.} - * @private - */ - this._fields = null; - - /** - * Cached fields by id. - * @type {?Object.} - * @private - */ - this._fieldsById = null; - - /** - * Cached fields by name. - * @type {?Object.} - * @private - */ - this._fieldsByName = null; - }; - - /** - * @alias ProtoBuf.Reflect.Message.prototype - * @inner - */ - var MessagePrototype = Message.prototype = Object.create(Namespace.prototype); - - /** - * Builds the message and returns the runtime counterpart, which is a fully functional class. - * @see ProtoBuf.Builder.Message - * @param {boolean=} rebuild Whether to rebuild or not, defaults to false - * @return {ProtoBuf.Reflect.Message} Message class - * @throws {Error} If the message cannot be built - * @expose - */ - MessagePrototype.build = function(rebuild) { - if (this.clazz && !rebuild) - return this.clazz; - - // Create the runtime Message class in its own scope - var clazz = (function(ProtoBuf, T) { - - var fields = T.getChildren(ProtoBuf.Reflect.Message.Field), - oneofs = T.getChildren(ProtoBuf.Reflect.Message.OneOf); - - /** - * Constructs a new runtime Message. - * @name ProtoBuf.Builder.Message - * @class Barebone of all runtime messages. - * @param {!Object.|string} values Preset values - * @param {...string} var_args - * @constructor - * @throws {Error} If the message cannot be created - */ - var Message = function(values, var_args) { - ProtoBuf.Builder.Message.call(this); - - // Create virtual oneof properties - for (var i=0, k=oneofs.length; i 0) { - var value; - // Set field values from a values object - if (arguments.length === 1 && values !== null && typeof values === 'object' && - /* not _another_ Message */ (typeof values.encode !== 'function' || values instanceof Message) && - /* not a repeated field */ !Array.isArray(values) && - /* not a Map */ !(values instanceof ProtoBuf.Map) && - /* not a ByteBuffer */ !ByteBuffer.isByteBuffer(values) && - /* not an ArrayBuffer */ !(values instanceof ArrayBuffer) && - /* not a Long */ !(ProtoBuf.Long && values instanceof ProtoBuf.Long)) { - this.$set(values); - } else // Set field values from arguments, in declaration order - for (i=0, k=arguments.length; i} keyOrObj String key or plain object holding multiple values - * @param {(*|boolean)=} value Value to set if key is a string, otherwise omitted - * @param {boolean=} noAssert Whether to not assert for an actual field / proper value type, defaults to `false` - * @returns {!ProtoBuf.Builder.Message} this - * @throws {Error} If the value cannot be set - * @expose - */ - MessagePrototype.set = function(keyOrObj, value, noAssert) { - if (keyOrObj && typeof keyOrObj === 'object') { - noAssert = value; - for (var ikey in keyOrObj) - if (keyOrObj.hasOwnProperty(ikey) && typeof (value = keyOrObj[ikey]) !== 'undefined') - this.$set(ikey, value, noAssert); - return this; - } - var field = T._fieldsByName[keyOrObj]; - if (!noAssert) { - if (!field) - throw Error(this+"#"+keyOrObj+" is not a field: undefined"); - if (!(field instanceof ProtoBuf.Reflect.Message.Field)) - throw Error(this+"#"+keyOrObj+" is not a field: "+field.toString(true)); - this[field.name] = (value = field.verifyValue(value)); // May throw - } else - this[keyOrObj] = value; - if (field && field.oneof) { // Field is part of an OneOf (not a virtual OneOf field) - var currentField = this[field.oneof.name]; // Virtual field references currently set field - if (value !== null) { - if (currentField !== null && currentField !== field.name) - this[currentField] = null; // Clear currently set field - this[field.oneof.name] = field.name; // Point virtual field at this field - } else if (/* value === null && */currentField === keyOrObj) - this[field.oneof.name] = null; // Clear virtual field (current field explicitly cleared) - } - return this; - }; - - /** - * Sets a field's value. This is an alias for [@link ProtoBuf.Builder.Message#set}. - * @name ProtoBuf.Builder.Message#$set - * @function - * @param {string|!Object.} keyOrObj String key or plain object holding multiple values - * @param {(*|boolean)=} value Value to set if key is a string, otherwise omitted - * @param {boolean=} noAssert Whether to not assert the value, defaults to `false` - * @throws {Error} If the value cannot be set - * @expose - */ - MessagePrototype.$set = MessagePrototype.set; - - /** - * Gets a field's value. - * @name ProtoBuf.Builder.Message#get - * @function - * @param {string} key Key - * @param {boolean=} noAssert Whether to not assert for an actual field, defaults to `false` - * @return {*} Value - * @throws {Error} If there is no such field - * @expose - */ - MessagePrototype.get = function(key, noAssert) { - if (noAssert) - return this[key]; - var field = T._fieldsByName[key]; - if (!field || !(field instanceof ProtoBuf.Reflect.Message.Field)) - throw Error(this+"#"+key+" is not a field: undefined"); - if (!(field instanceof ProtoBuf.Reflect.Message.Field)) - throw Error(this+"#"+key+" is not a field: "+field.toString(true)); - return this[field.name]; - }; - - /** - * Gets a field's value. This is an alias for {@link ProtoBuf.Builder.Message#$get}. - * @name ProtoBuf.Builder.Message#$get - * @function - * @param {string} key Key - * @return {*} Value - * @throws {Error} If there is no such field - * @expose - */ - MessagePrototype.$get = MessagePrototype.get; - - // Getters and setters - - for (var i=0; i} data Data payload - * @param {(!ByteBuffer|boolean)=} buffer ByteBuffer to encode to. Will create a new one and flip it if omitted. - * @param {boolean=} noVerify Whether to not verify field values, defaults to `false` - * @return {!ByteBuffer} Encoded message as a ByteBuffer - * @expose - */ - Message.encode = function(data, buffer, noVerify) { - return new Message(data).encode(buffer, noVerify); - }; - - /** - * Calculates the byte length of the message. - * @name ProtoBuf.Builder.Message#calculate - * @function - * @returns {number} Byte length - * @throws {Error} If the message cannot be calculated or if required fields are missing. - * @expose - */ - MessagePrototype.calculate = function() { - return T.calculate(this); - }; - - /** - * Encodes the varint32 length-delimited message. - * @name ProtoBuf.Builder.Message#encodeDelimited - * @function - * @param {(!ByteBuffer|boolean)=} buffer ByteBuffer to encode to. Will create a new one and flip it if omitted. - * @param {boolean=} noVerify Whether to not verify field values, defaults to `false` - * @return {!ByteBuffer} Encoded message as a ByteBuffer - * @throws {Error} If the message cannot be encoded or if required fields are missing. The later still - * returns the encoded ByteBuffer in the `encoded` property on the error. - * @expose - */ - MessagePrototype.encodeDelimited = function(buffer, noVerify) { - var isNew = false; - if (!buffer) - buffer = new ByteBuffer(), - isNew = true; - var enc = new ByteBuffer().LE(); - T.encode(this, enc, noVerify).flip(); - buffer.writeVarint32(enc.remaining()); - buffer.append(enc); - return isNew ? buffer.flip() : buffer; - }; - - /** - * Directly encodes the message to an ArrayBuffer. - * @name ProtoBuf.Builder.Message#encodeAB - * @function - * @return {ArrayBuffer} Encoded message as ArrayBuffer - * @throws {Error} If the message cannot be encoded or if required fields are missing. The later still - * returns the encoded ArrayBuffer in the `encoded` property on the error. - * @expose - */ - MessagePrototype.encodeAB = function() { - try { - return this.encode().toArrayBuffer(); - } catch (e) { - if (e["encoded"]) e["encoded"] = e["encoded"].toArrayBuffer(); - throw(e); - } - }; - - /** - * Returns the message as an ArrayBuffer. This is an alias for {@link ProtoBuf.Builder.Message#encodeAB}. - * @name ProtoBuf.Builder.Message#toArrayBuffer - * @function - * @return {ArrayBuffer} Encoded message as ArrayBuffer - * @throws {Error} If the message cannot be encoded or if required fields are missing. The later still - * returns the encoded ArrayBuffer in the `encoded` property on the error. - * @expose - */ - MessagePrototype.toArrayBuffer = MessagePrototype.encodeAB; - - /** - * Directly encodes the message to a node Buffer. - * @name ProtoBuf.Builder.Message#encodeNB - * @function - * @return {!Buffer} - * @throws {Error} If the message cannot be encoded, not running under node.js or if required fields are - * missing. The later still returns the encoded node Buffer in the `encoded` property on the error. - * @expose - */ - MessagePrototype.encodeNB = function() { - try { - return this.encode().toBuffer(); - } catch (e) { - if (e["encoded"]) e["encoded"] = e["encoded"].toBuffer(); - throw(e); - } - }; - - /** - * Returns the message as a node Buffer. This is an alias for {@link ProtoBuf.Builder.Message#encodeNB}. - * @name ProtoBuf.Builder.Message#toBuffer - * @function - * @return {!Buffer} - * @throws {Error} If the message cannot be encoded or if required fields are missing. The later still - * returns the encoded node Buffer in the `encoded` property on the error. - * @expose - */ - MessagePrototype.toBuffer = MessagePrototype.encodeNB; - - /** - * Directly encodes the message to a base64 encoded string. - * @name ProtoBuf.Builder.Message#encode64 - * @function - * @return {string} Base64 encoded string - * @throws {Error} If the underlying buffer cannot be encoded or if required fields are missing. The later - * still returns the encoded base64 string in the `encoded` property on the error. - * @expose - */ - MessagePrototype.encode64 = function() { - try { - return this.encode().toBase64(); - } catch (e) { - if (e["encoded"]) e["encoded"] = e["encoded"].toBase64(); - throw(e); - } - }; - - /** - * Returns the message as a base64 encoded string. This is an alias for {@link ProtoBuf.Builder.Message#encode64}. - * @name ProtoBuf.Builder.Message#toBase64 - * @function - * @return {string} Base64 encoded string - * @throws {Error} If the message cannot be encoded or if required fields are missing. The later still - * returns the encoded base64 string in the `encoded` property on the error. - * @expose - */ - MessagePrototype.toBase64 = MessagePrototype.encode64; - - /** - * Directly encodes the message to a hex encoded string. - * @name ProtoBuf.Builder.Message#encodeHex - * @function - * @return {string} Hex encoded string - * @throws {Error} If the underlying buffer cannot be encoded or if required fields are missing. The later - * still returns the encoded hex string in the `encoded` property on the error. - * @expose - */ - MessagePrototype.encodeHex = function() { - try { - return this.encode().toHex(); - } catch (e) { - if (e["encoded"]) e["encoded"] = e["encoded"].toHex(); - throw(e); - } - }; - - /** - * Returns the message as a hex encoded string. This is an alias for {@link ProtoBuf.Builder.Message#encodeHex}. - * @name ProtoBuf.Builder.Message#toHex - * @function - * @return {string} Hex encoded string - * @throws {Error} If the message cannot be encoded or if required fields are missing. The later still - * returns the encoded hex string in the `encoded` property on the error. - * @expose - */ - MessagePrototype.toHex = MessagePrototype.encodeHex; - - /** - * Clones a message object or field value to a raw object. - * @param {*} obj Object to clone - * @param {boolean} binaryAsBase64 Whether to include binary data as base64 strings or as a buffer otherwise - * @param {boolean} longsAsStrings Whether to encode longs as strings - * @param {!ProtoBuf.Reflect.T=} resolvedType The resolved field type if a field - * @returns {*} Cloned object - * @inner - */ - function cloneRaw(obj, binaryAsBase64, longsAsStrings, resolvedType) { - if (obj === null || typeof obj !== 'object') { - // Convert enum values to their respective names - if (resolvedType && resolvedType instanceof ProtoBuf.Reflect.Enum) { - var name = ProtoBuf.Reflect.Enum.getName(resolvedType.object, obj); - if (name !== null) - return name; - } - // Pass-through string, number, boolean, null... - return obj; - } - // Convert ByteBuffers to raw buffer or strings - if (ByteBuffer.isByteBuffer(obj)) - return binaryAsBase64 ? obj.toBase64() : obj.toBuffer(); - // Convert Longs to proper objects or strings - if (ProtoBuf.Long.isLong(obj)) - return longsAsStrings ? obj.toString() : ProtoBuf.Long.fromValue(obj); - var clone; - // Clone arrays - if (Array.isArray(obj)) { - clone = []; - obj.forEach(function(v, k) { - clone[k] = cloneRaw(v, binaryAsBase64, longsAsStrings, resolvedType); - }); - return clone; - } - clone = {}; - // Convert maps to objects - if (obj instanceof ProtoBuf.Map) { - var it = obj.entries(); - for (var e = it.next(); !e.done; e = it.next()) - clone[obj.keyElem.valueToString(e.value[0])] = cloneRaw(e.value[1], binaryAsBase64, longsAsStrings, obj.valueElem.resolvedType); - return clone; - } - // Everything else is a non-null object - var type = obj.$type, - field = undefined; - for (var i in obj) - if (obj.hasOwnProperty(i)) { - if (type && (field = type.getChild(i))) - clone[i] = cloneRaw(obj[i], binaryAsBase64, longsAsStrings, field.resolvedType); - else - clone[i] = cloneRaw(obj[i], binaryAsBase64, longsAsStrings); - } - return clone; - } - - /** - * Returns the message's raw payload. - * @param {boolean=} binaryAsBase64 Whether to include binary data as base64 strings instead of Buffers, defaults to `false` - * @param {boolean} longsAsStrings Whether to encode longs as strings - * @returns {Object.} Raw payload - * @expose - */ - MessagePrototype.toRaw = function(binaryAsBase64, longsAsStrings) { - return cloneRaw(this, !!binaryAsBase64, !!longsAsStrings, this.$type); - }; - - /** - * Encodes a message to JSON. - * @returns {string} JSON string - * @expose - */ - MessagePrototype.encodeJSON = function() { - return JSON.stringify( - cloneRaw(this, - /* binary-as-base64 */ true, - /* longs-as-strings */ true, - this.$type - ) - ); - }; - - /** - * Decodes a message from the specified buffer or string. - * @name ProtoBuf.Builder.Message.decode - * @function - * @param {!ByteBuffer|!ArrayBuffer|!Buffer|string} buffer Buffer to decode from - * @param {(number|string)=} length Message length. Defaults to decode all the remainig data. - * @param {string=} enc Encoding if buffer is a string: hex, utf8 (not recommended), defaults to base64 - * @return {!ProtoBuf.Builder.Message} Decoded message - * @throws {Error} If the message cannot be decoded or if required fields are missing. The later still - * returns the decoded message with missing fields in the `decoded` property on the error. - * @expose - * @see ProtoBuf.Builder.Message.decode64 - * @see ProtoBuf.Builder.Message.decodeHex - */ - Message.decode = function(buffer, length, enc) { - if (typeof length === 'string') - enc = length, - length = -1; - if (typeof buffer === 'string') - buffer = ByteBuffer.wrap(buffer, enc ? enc : "base64"); - buffer = ByteBuffer.isByteBuffer(buffer) ? buffer : ByteBuffer.wrap(buffer); // May throw - var le = buffer.littleEndian; - try { - var msg = T.decode(buffer.LE()); - buffer.LE(le); - return msg; - } catch (e) { - buffer.LE(le); - throw(e); - } - }; - - /** - * Decodes a varint32 length-delimited message from the specified buffer or string. - * @name ProtoBuf.Builder.Message.decodeDelimited - * @function - * @param {!ByteBuffer|!ArrayBuffer|!Buffer|string} buffer Buffer to decode from - * @param {string=} enc Encoding if buffer is a string: hex, utf8 (not recommended), defaults to base64 - * @return {ProtoBuf.Builder.Message} Decoded message or `null` if not enough bytes are available yet - * @throws {Error} If the message cannot be decoded or if required fields are missing. The later still - * returns the decoded message with missing fields in the `decoded` property on the error. - * @expose - */ - Message.decodeDelimited = function(buffer, enc) { - if (typeof buffer === 'string') - buffer = ByteBuffer.wrap(buffer, enc ? enc : "base64"); - buffer = ByteBuffer.isByteBuffer(buffer) ? buffer : ByteBuffer.wrap(buffer); // May throw - if (buffer.remaining() < 1) - return null; - var off = buffer.offset, - len = buffer.readVarint32(); - if (buffer.remaining() < len) { - buffer.offset = off; - return null; - } - try { - var msg = T.decode(buffer.slice(buffer.offset, buffer.offset + len).LE()); - buffer.offset += len; - return msg; - } catch (err) { - buffer.offset += len; - throw err; - } - }; - - /** - * Decodes the message from the specified base64 encoded string. - * @name ProtoBuf.Builder.Message.decode64 - * @function - * @param {string} str String to decode from - * @return {!ProtoBuf.Builder.Message} Decoded message - * @throws {Error} If the message cannot be decoded or if required fields are missing. The later still - * returns the decoded message with missing fields in the `decoded` property on the error. - * @expose - */ - Message.decode64 = function(str) { - return Message.decode(str, "base64"); - }; - - /** - * Decodes the message from the specified hex encoded string. - * @name ProtoBuf.Builder.Message.decodeHex - * @function - * @param {string} str String to decode from - * @return {!ProtoBuf.Builder.Message} Decoded message - * @throws {Error} If the message cannot be decoded or if required fields are missing. The later still - * returns the decoded message with missing fields in the `decoded` property on the error. - * @expose - */ - Message.decodeHex = function(str) { - return Message.decode(str, "hex"); - }; - - /** - * Decodes the message from a JSON string. - * @name ProtoBuf.Builder.Message.decodeJSON - * @function - * @param {string} str String to decode from - * @return {!ProtoBuf.Builder.Message} Decoded message - * @throws {Error} If the message cannot be decoded or if required fields are - * missing. - * @expose - */ - Message.decodeJSON = function(str) { - return new Message(JSON.parse(str)); - }; - - // Utility - - /** - * Returns a string representation of this Message. - * @name ProtoBuf.Builder.Message#toString - * @function - * @return {string} String representation as of ".Fully.Qualified.MessageName" - * @expose - */ - MessagePrototype.toString = function() { - return T.toString(); - }; - - // Properties - - /** - * Message options. - * @name ProtoBuf.Builder.Message.$options - * @type {Object.} - * @expose - */ - var $optionsS; // cc needs this - - /** - * Message options. - * @name ProtoBuf.Builder.Message#$options - * @type {Object.} - * @expose - */ - var $options; - - /** - * Reflection type. - * @name ProtoBuf.Builder.Message.$type - * @type {!ProtoBuf.Reflect.Message} - * @expose - */ - var $typeS; - - /** - * Reflection type. - * @name ProtoBuf.Builder.Message#$type - * @type {!ProtoBuf.Reflect.Message} - * @expose - */ - var $type; - - if (Object.defineProperty) - Object.defineProperty(Message, '$options', { "value": T.buildOpt() }), - Object.defineProperty(MessagePrototype, "$options", { "value": Message["$options"] }), - Object.defineProperty(Message, "$type", { "value": T }), - Object.defineProperty(MessagePrototype, "$type", { "value": T }); - - return Message; - - })(ProtoBuf, this); - - // Static enums and prototyped sub-messages / cached collections - this._fields = []; - this._fieldsById = {}; - this._fieldsByName = {}; - for (var i=0, k=this.children.length, child; i>> 3; - switch (wireType) { - case ProtoBuf.WIRE_TYPES.VARINT: - do tag = buf.readUint8(); - while ((tag & 0x80) === 0x80); - break; - case ProtoBuf.WIRE_TYPES.BITS64: - buf.offset += 8; - break; - case ProtoBuf.WIRE_TYPES.LDELIM: - tag = buf.readVarint32(); // reads the varint - buf.offset += tag; // skips n bytes - break; - case ProtoBuf.WIRE_TYPES.STARTGROUP: - skipTillGroupEnd(id, buf); - break; - case ProtoBuf.WIRE_TYPES.ENDGROUP: - if (id === expectedId) - return false; - else - throw Error("Illegal GROUPEND after unknown group: "+id+" ("+expectedId+" expected)"); - case ProtoBuf.WIRE_TYPES.BITS32: - buf.offset += 4; - break; - default: - throw Error("Illegal wire type in unknown group "+expectedId+": "+wireType); - } - return true; - } - - /** - * Decodes an encoded message and returns the decoded message. - * @param {ByteBuffer} buffer ByteBuffer to decode from - * @param {number=} length Message length. Defaults to decode all remaining data. - * @param {number=} expectedGroupEndId Expected GROUPEND id if this is a legacy group - * @return {ProtoBuf.Builder.Message} Decoded message - * @throws {Error} If the message cannot be decoded - * @expose - */ - MessagePrototype.decode = function(buffer, length, expectedGroupEndId) { - length = typeof length === 'number' ? length : -1; - var start = buffer.offset, - msg = new (this.clazz)(), - tag, wireType, id, field; - while (buffer.offset < start+length || (length === -1 && buffer.remaining() > 0)) { - tag = buffer.readVarint32(); - wireType = tag & 0x07; - id = tag >>> 3; - if (wireType === ProtoBuf.WIRE_TYPES.ENDGROUP) { - if (id !== expectedGroupEndId) - throw Error("Illegal group end indicator for "+this.toString(true)+": "+id+" ("+(expectedGroupEndId ? expectedGroupEndId+" expected" : "not a group")+")"); - break; - } - if (!(field = this._fieldsById[id])) { - // "messages created by your new code can be parsed by your old code: old binaries simply ignore the new field when parsing." - switch (wireType) { - case ProtoBuf.WIRE_TYPES.VARINT: - buffer.readVarint32(); - break; - case ProtoBuf.WIRE_TYPES.BITS32: - buffer.offset += 4; - break; - case ProtoBuf.WIRE_TYPES.BITS64: - buffer.offset += 8; - break; - case ProtoBuf.WIRE_TYPES.LDELIM: - var len = buffer.readVarint32(); - buffer.offset += len; - break; - case ProtoBuf.WIRE_TYPES.STARTGROUP: - while (skipTillGroupEnd(id, buffer)) {} - break; - default: - throw Error("Illegal wire type for unknown field "+id+" in "+this.toString(true)+"#decode: "+wireType); - } - continue; - } - if (field.repeated && !field.options["packed"]) { - msg[field.name].push(field.decode(wireType, buffer)); - } else if (field.map) { - var keyval = field.decode(wireType, buffer); - msg[field.name].set(keyval[0], keyval[1]); - } else { - msg[field.name] = field.decode(wireType, buffer); - if (field.oneof) { // Field is part of an OneOf (not a virtual OneOf field) - var currentField = msg[field.oneof.name]; // Virtual field references currently set field - if (currentField !== null && currentField !== field.name) - msg[currentField] = null; // Clear currently set field - msg[field.oneof.name] = field.name; // Point virtual field at this field - } - } - } - - // Check if all required fields are present and set default values for optional fields that are not - for (var i=0, k=this._fields.length; i=} options Options - * @param {!ProtoBuf.Reflect.Message.OneOf=} oneof Enclosing OneOf - * @param {string?} syntax The syntax level of this definition (e.g., proto3) - * @constructor - * @extends ProtoBuf.Reflect.T - */ - var Field = function(builder, message, rule, keytype, type, name, id, options, oneof, syntax) { - T.call(this, builder, message, name); - - /** - * @override - */ - this.className = "Message.Field"; - - /** - * Message field required flag. - * @type {boolean} - * @expose - */ - this.required = rule === "required"; - - /** - * Message field repeated flag. - * @type {boolean} - * @expose - */ - this.repeated = rule === "repeated"; - - /** - * Message field map flag. - * @type {boolean} - * @expose - */ - this.map = rule === "map"; - - /** - * Message field key type. Type reference string if unresolved, protobuf - * type if resolved. Valid only if this.map === true, null otherwise. - * @type {string|{name: string, wireType: number}|null} - * @expose - */ - this.keyType = keytype || null; - - /** - * Message field type. Type reference string if unresolved, protobuf type if - * resolved. In a map field, this is the value type. - * @type {string|{name: string, wireType: number}} - * @expose - */ - this.type = type; - - /** - * Resolved type reference inside the global namespace. - * @type {ProtoBuf.Reflect.T|null} - * @expose - */ - this.resolvedType = null; - - /** - * Unique message field id. - * @type {number} - * @expose - */ - this.id = id; - - /** - * Message field options. - * @type {!Object.} - * @dict - * @expose - */ - this.options = options || {}; - - /** - * Default value. - * @type {*} - * @expose - */ - this.defaultValue = null; - - /** - * Enclosing OneOf. - * @type {?ProtoBuf.Reflect.Message.OneOf} - * @expose - */ - this.oneof = oneof || null; - - /** - * Syntax level of this definition (e.g., proto3). - * @type {string} - * @expose - */ - this.syntax = syntax || 'proto2'; - - /** - * Original field name. - * @type {string} - * @expose - */ - this.originalName = this.name; // Used to revert camelcase transformation on naming collisions - - /** - * Element implementation. Created in build() after types are resolved. - * @type {ProtoBuf.Element} - * @expose - */ - this.element = null; - - /** - * Key element implementation, for map fields. Created in build() after - * types are resolved. - * @type {ProtoBuf.Element} - * @expose - */ - this.keyElement = null; - - // Convert field names to camel case notation if the override is set - if (this.builder.options['convertFieldsToCamelCase'] && !(this instanceof Message.ExtensionField)) - this.name = ProtoBuf.Util.toCamelCase(this.name); - }; - - /** - * @alias ProtoBuf.Reflect.Message.Field.prototype - * @inner - */ - var FieldPrototype = Field.prototype = Object.create(T.prototype); - - /** - * Builds the field. - * @override - * @expose - */ - FieldPrototype.build = function() { - this.element = new Element(this.type, this.resolvedType, false, this.syntax); - if (this.map) - this.keyElement = new Element(this.keyType, undefined, true, this.syntax); - - // In proto3, fields do not have field presence, and every field is set to - // its type's default value ("", 0, 0.0, or false). - if (this.syntax === 'proto3' && !this.repeated && !this.map) - this.defaultValue = Element.defaultFieldValue(this.type); - - // Otherwise, default values are present when explicitly specified - else if (typeof this.options['default'] !== 'undefined') - this.defaultValue = this.verifyValue(this.options['default']); - }; - - /** - * Checks if the given value can be set for this field. - * @param {*} value Value to check - * @param {boolean=} skipRepeated Whether to skip the repeated value check or not. Defaults to false. - * @return {*} Verified, maybe adjusted, value - * @throws {Error} If the value cannot be set for this field - * @expose - */ - FieldPrototype.verifyValue = function(value, skipRepeated) { - skipRepeated = skipRepeated || false; - var self = this; - function fail(val, msg) { - throw Error("Illegal value for "+self.toString(true)+" of type "+self.type.name+": "+val+" ("+msg+")"); - } - if (value === null) { // NULL values for optional fields - if (this.required) - fail(typeof value, "required"); - if (this.syntax === 'proto3' && this.type !== ProtoBuf.TYPES["message"]) - fail(typeof value, "proto3 field without field presence cannot be null"); - return null; - } - var i; - if (this.repeated && !skipRepeated) { // Repeated values as arrays - if (!Array.isArray(value)) - value = [value]; - var res = []; - for (i=0; i 0; - - case ProtoBuf.TYPES["bytes"]: - return value.remaining() > 0; - - case ProtoBuf.TYPES["enum"]: - return value !== 0; - - case ProtoBuf.TYPES["message"]: - return value !== null; - default: - return true; - } - }; - - /** - * Encodes the specified field value to the specified buffer. - * @param {*} value Verified field value - * @param {ByteBuffer} buffer ByteBuffer to encode to - * @param {!ProtoBuf.Builder.Message} message Runtime message - * @return {ByteBuffer} The ByteBuffer for chaining - * @throws {Error} If the field cannot be encoded - * @expose - */ - FieldPrototype.encode = function(value, buffer, message) { - if (this.type === null || typeof this.type !== 'object') - throw Error("[INTERNAL] Unresolved type in "+this.toString(true)+": "+this.type); - if (value === null || (this.repeated && value.length == 0)) - return buffer; // Optional omitted - try { - if (this.repeated) { - var i; - // "Only repeated fields of primitive numeric types (types which use the varint, 32-bit, or 64-bit wire - // types) can be declared 'packed'." - if (this.options["packed"] && ProtoBuf.PACKABLE_WIRE_TYPES.indexOf(this.type.wireType) >= 0) { - // "All of the elements of the field are packed into a single key-value pair with wire type 2 - // (length-delimited). Each element is encoded the same way it would be normally, except without a - // tag preceding it." - buffer.writeVarint32((this.id << 3) | ProtoBuf.WIRE_TYPES.LDELIM); - buffer.ensureCapacity(buffer.offset += 1); // We do not know the length yet, so let's assume a varint of length 1 - var start = buffer.offset; // Remember where the contents begin - for (i=0; i 1) { // We need to move the contents - var contents = buffer.slice(start, buffer.offset); - start += varintLen-1; - buffer.offset = start; - buffer.append(contents); - } - buffer.writeVarint32(len, start-varintLen); - } else { - // "If your message definition has repeated elements (without the [packed=true] option), the encoded - // message has zero or more key-value pairs with the same tag number" - for (i=0; i= 0) { - n += ByteBuffer.calculateVarint32((this.id << 3) | ProtoBuf.WIRE_TYPES.LDELIM); - ni = 0; - for (i=0; i= 0) { - if (!skipRepeated) { - nBytes = buffer.readVarint32(); - nBytes = buffer.offset + nBytes; // Limit - var values = []; - while (buffer.offset < nBytes) - values.push(this.decode(this.type.wireType, buffer, true)); - return values; - } - // Read the next value otherwise... - } - - // Handle maps. - if (this.map) { - // Read one (key, value) submessage, and return [key, value] - var key = Element.defaultFieldValue(this.keyType); - value = Element.defaultFieldValue(this.type); - - // Read the length - nBytes = buffer.readVarint32(); - if (buffer.remaining() < nBytes) - throw Error("Illegal number of bytes for "+this.toString(true)+": "+nBytes+" required but got only "+buffer.remaining()); - - // Get a sub-buffer of this key/value submessage - var msgbuf = buffer.clone(); - msgbuf.limit = msgbuf.offset + nBytes; - buffer.offset += nBytes; - - while (msgbuf.remaining() > 0) { - var tag = msgbuf.readVarint32(); - wireType = tag & 0x07; - var id = tag >>> 3; - if (id === 1) { - key = this.keyElement.decode(msgbuf, wireType, id); - } else if (id === 2) { - value = this.element.decode(msgbuf, wireType, id); - } else { - throw Error("Unexpected tag in map field key/value submessage"); - } - } - - return [key, value]; - } - - // Handle singular and non-packed repeated field values. - return this.element.decode(buffer, wireType, this.id); - }; - - /** - * @alias ProtoBuf.Reflect.Message.Field - * @expose - */ - Reflect.Message.Field = Field; - - /** - * Constructs a new Message ExtensionField. - * @exports ProtoBuf.Reflect.Message.ExtensionField - * @param {!ProtoBuf.Builder} builder Builder reference - * @param {!ProtoBuf.Reflect.Message} message Message reference - * @param {string} rule Rule, one of requried, optional, repeated - * @param {string} type Data type, e.g. int32 - * @param {string} name Field name - * @param {number} id Unique field id - * @param {!Object.=} options Options - * @constructor - * @extends ProtoBuf.Reflect.Message.Field - */ - var ExtensionField = function(builder, message, rule, type, name, id, options) { - Field.call(this, builder, message, rule, /* keytype = */ null, type, name, id, options); - - /** - * Extension reference. - * @type {!ProtoBuf.Reflect.Extension} - * @expose - */ - this.extension; - }; - - // Extends Field - ExtensionField.prototype = Object.create(Field.prototype); - - /** - * @alias ProtoBuf.Reflect.Message.ExtensionField - * @expose - */ - Reflect.Message.ExtensionField = ExtensionField; - - /** - * Constructs a new Message OneOf. - * @exports ProtoBuf.Reflect.Message.OneOf - * @param {!ProtoBuf.Builder} builder Builder reference - * @param {!ProtoBuf.Reflect.Message} message Message reference - * @param {string} name OneOf name - * @constructor - * @extends ProtoBuf.Reflect.T - */ - var OneOf = function(builder, message, name) { - T.call(this, builder, message, name); - - /** - * Enclosed fields. - * @type {!Array.} - * @expose - */ - this.fields = []; - }; - - /** - * @alias ProtoBuf.Reflect.Message.OneOf - * @expose - */ - Reflect.Message.OneOf = OneOf; - - /** - * Constructs a new Enum. - * @exports ProtoBuf.Reflect.Enum - * @param {!ProtoBuf.Builder} builder Builder reference - * @param {!ProtoBuf.Reflect.T} parent Parent Reflect object - * @param {string} name Enum name - * @param {Object.=} options Enum options - * @param {string?} syntax The syntax level (e.g., proto3) - * @constructor - * @extends ProtoBuf.Reflect.Namespace - */ - var Enum = function(builder, parent, name, options, syntax) { - Namespace.call(this, builder, parent, name, options, syntax); - - /** - * @override - */ - this.className = "Enum"; - - /** - * Runtime enum object. - * @type {Object.|null} - * @expose - */ - this.object = null; - }; - - /** - * Gets the string name of an enum value. - * @param {!ProtoBuf.Builder.Enum} enm Runtime enum - * @param {number} value Enum value - * @returns {?string} Name or `null` if not present - * @expose - */ - Enum.getName = function(enm, value) { - var keys = Object.keys(enm); - for (var i=0, key; i} - * @expose - */ - EnumPrototype.build = function(rebuild) { - if (this.object && !rebuild) - return this.object; - var enm = new ProtoBuf.Builder.Enum(), - values = this.getChildren(Enum.Value); - for (var i=0, k=values.length; i=} options Options - * @constructor - * @extends ProtoBuf.Reflect.Namespace - */ - var Service = function(builder, root, name, options) { - Namespace.call(this, builder, root, name, options); - - /** - * @override - */ - this.className = "Service"; - - /** - * Built runtime service class. - * @type {?function(new:ProtoBuf.Builder.Service)} - */ - this.clazz = null; - }; - - /** - * @alias ProtoBuf.Reflect.Service.prototype - * @inner - */ - var ServicePrototype = Service.prototype = Object.create(Namespace.prototype); - - /** - * Builds the service and returns the runtime counterpart, which is a fully functional class. - * @see ProtoBuf.Builder.Service - * @param {boolean=} rebuild Whether to rebuild or not - * @return {Function} Service class - * @throws {Error} If the message cannot be built - * @expose - */ - ServicePrototype.build = function(rebuild) { - if (this.clazz && !rebuild) - return this.clazz; - - // Create the runtime Service class in its own scope - return this.clazz = (function(ProtoBuf, T) { - - /** - * Constructs a new runtime Service. - * @name ProtoBuf.Builder.Service - * @param {function(string, ProtoBuf.Builder.Message, function(Error, ProtoBuf.Builder.Message=))=} rpcImpl RPC implementation receiving the method name and the message - * @class Barebone of all runtime services. - * @constructor - * @throws {Error} If the service cannot be created - */ - var Service = function(rpcImpl) { - ProtoBuf.Builder.Service.call(this); - - /** - * Service implementation. - * @name ProtoBuf.Builder.Service#rpcImpl - * @type {!function(string, ProtoBuf.Builder.Message, function(Error, ProtoBuf.Builder.Message=))} - * @expose - */ - this.rpcImpl = rpcImpl || function(name, msg, callback) { - // This is what a user has to implement: A function receiving the method name, the actual message to - // send (type checked) and the callback that's either provided with the error as its first - // argument or null and the actual response message. - setTimeout(callback.bind(this, Error("Not implemented, see: https://github.com/dcodeIO/ProtoBuf.js/wiki/Services")), 0); // Must be async! - }; - }; - - /** - * @alias ProtoBuf.Builder.Service.prototype - * @inner - */ - var ServicePrototype = Service.prototype = Object.create(ProtoBuf.Builder.Service.prototype); - - /** - * Asynchronously performs an RPC call using the given RPC implementation. - * @name ProtoBuf.Builder.Service.[Method] - * @function - * @param {!function(string, ProtoBuf.Builder.Message, function(Error, ProtoBuf.Builder.Message=))} rpcImpl RPC implementation - * @param {ProtoBuf.Builder.Message} req Request - * @param {function(Error, (ProtoBuf.Builder.Message|ByteBuffer|Buffer|string)=)} callback Callback receiving - * the error if any and the response either as a pre-parsed message or as its raw bytes - * @abstract - */ - - /** - * Asynchronously performs an RPC call using the instance's RPC implementation. - * @name ProtoBuf.Builder.Service#[Method] - * @function - * @param {ProtoBuf.Builder.Message} req Request - * @param {function(Error, (ProtoBuf.Builder.Message|ByteBuffer|Buffer|string)=)} callback Callback receiving - * the error if any and the response either as a pre-parsed message or as its raw bytes - * @abstract - */ - - var rpc = T.getChildren(ProtoBuf.Reflect.Service.RPCMethod); - for (var i=0; i} - * @expose - */ - var $optionsS; // cc needs this - - /** - * Service options. - * @name ProtoBuf.Builder.Service#$options - * @type {Object.} - * @expose - */ - var $options; - - /** - * Reflection type. - * @name ProtoBuf.Builder.Service.$type - * @type {!ProtoBuf.Reflect.Service} - * @expose - */ - var $typeS; - - /** - * Reflection type. - * @name ProtoBuf.Builder.Service#$type - * @type {!ProtoBuf.Reflect.Service} - * @expose - */ - var $type; - - if (Object.defineProperty) - Object.defineProperty(Service, "$options", { "value": T.buildOpt() }), - Object.defineProperty(ServicePrototype, "$options", { "value": Service["$options"] }), - Object.defineProperty(Service, "$type", { "value": T }), - Object.defineProperty(ServicePrototype, "$type", { "value": T }); - - return Service; - - })(ProtoBuf, this); - }; - - /** - * @alias ProtoBuf.Reflect.Service - * @expose - */ - Reflect.Service = Service; - - /** - * Abstract service method. - * @exports ProtoBuf.Reflect.Service.Method - * @param {!ProtoBuf.Builder} builder Builder reference - * @param {!ProtoBuf.Reflect.Service} svc Service - * @param {string} name Method name - * @param {Object.=} options Options - * @constructor - * @extends ProtoBuf.Reflect.T - */ - var Method = function(builder, svc, name, options) { - T.call(this, builder, svc, name); - - /** - * @override - */ - this.className = "Service.Method"; - - /** - * Options. - * @type {Object.} - * @expose - */ - this.options = options || {}; - }; - - /** - * @alias ProtoBuf.Reflect.Service.Method.prototype - * @inner - */ - var MethodPrototype = Method.prototype = Object.create(T.prototype); - - /** - * Builds the method's '$options' property. - * @name ProtoBuf.Reflect.Service.Method#buildOpt - * @function - * @return {Object.} - */ - MethodPrototype.buildOpt = NamespacePrototype.buildOpt; - - /** - * @alias ProtoBuf.Reflect.Service.Method - * @expose - */ - Reflect.Service.Method = Method; - - /** - * RPC service method. - * @exports ProtoBuf.Reflect.Service.RPCMethod - * @param {!ProtoBuf.Builder} builder Builder reference - * @param {!ProtoBuf.Reflect.Service} svc Service - * @param {string} name Method name - * @param {string} request Request message name - * @param {string} response Response message name - * @param {boolean} request_stream Whether requests are streamed - * @param {boolean} response_stream Whether responses are streamed - * @param {Object.=} options Options - * @constructor - * @extends ProtoBuf.Reflect.Service.Method - */ - var RPCMethod = function(builder, svc, name, request, response, request_stream, response_stream, options) { - Method.call(this, builder, svc, name, options); - - /** - * @override - */ - this.className = "Service.RPCMethod"; - - /** - * Request message name. - * @type {string} - * @expose - */ - this.requestName = request; - - /** - * Response message name. - * @type {string} - * @expose - */ - this.responseName = response; - - /** - * Whether requests are streamed - * @type {bool} - * @expose - */ - this.requestStream = request_stream; - - /** - * Whether responses are streamed - * @type {bool} - * @expose - */ - this.responseStream = response_stream; - - /** - * Resolved request message type. - * @type {ProtoBuf.Reflect.Message} - * @expose - */ - this.resolvedRequestType = null; - - /** - * Resolved response message type. - * @type {ProtoBuf.Reflect.Message} - * @expose - */ - this.resolvedResponseType = null; - }; - - // Extends Method - RPCMethod.prototype = Object.create(Method.prototype); - - /** - * @alias ProtoBuf.Reflect.Service.RPCMethod - * @expose - */ - Reflect.Service.RPCMethod = RPCMethod; - - return Reflect; - - })(ProtoBuf); - - /** - * @alias ProtoBuf.Builder - * @expose - */ - ProtoBuf.Builder = (function(ProtoBuf, Lang, Reflect) { - "use strict"; - - /** - * Constructs a new Builder. - * @exports ProtoBuf.Builder - * @class Provides the functionality to build protocol messages. - * @param {Object.=} options Options - * @constructor - */ - var Builder = function(options) { - - /** - * Namespace. - * @type {ProtoBuf.Reflect.Namespace} - * @expose - */ - this.ns = new Reflect.Namespace(this, null, ""); // Global namespace - - /** - * Namespace pointer. - * @type {ProtoBuf.Reflect.T} - * @expose - */ - this.ptr = this.ns; - - /** - * Resolved flag. - * @type {boolean} - * @expose - */ - this.resolved = false; - - /** - * The current building result. - * @type {Object.|null} - * @expose - */ - this.result = null; - - /** - * Imported files. - * @type {Array.} - * @expose - */ - this.files = {}; - - /** - * Import root override. - * @type {?string} - * @expose - */ - this.importRoot = null; - - /** - * Options. - * @type {!Object.} - * @expose - */ - this.options = options || {}; - }; - - /** - * @alias ProtoBuf.Builder.prototype - * @inner - */ - var BuilderPrototype = Builder.prototype; - - // ----- Definition tests ----- - - /** - * Tests if a definition most likely describes a message. - * @param {!Object} def - * @returns {boolean} - * @expose - */ - Builder.isMessage = function(def) { - // Messages require a string name - if (typeof def["name"] !== 'string') - return false; - // Messages do not contain values (enum) or rpc methods (service) - if (typeof def["values"] !== 'undefined' || typeof def["rpc"] !== 'undefined') - return false; - return true; - }; - - /** - * Tests if a definition most likely describes a message field. - * @param {!Object} def - * @returns {boolean} - * @expose - */ - Builder.isMessageField = function(def) { - // Message fields require a string rule, name and type and an id - if (typeof def["rule"] !== 'string' || typeof def["name"] !== 'string' || typeof def["type"] !== 'string' || typeof def["id"] === 'undefined') - return false; - return true; - }; - - /** - * Tests if a definition most likely describes an enum. - * @param {!Object} def - * @returns {boolean} - * @expose - */ - Builder.isEnum = function(def) { - // Enums require a string name - if (typeof def["name"] !== 'string') - return false; - // Enums require at least one value - if (typeof def["values"] === 'undefined' || !Array.isArray(def["values"]) || def["values"].length === 0) - return false; - return true; - }; - - /** - * Tests if a definition most likely describes a service. - * @param {!Object} def - * @returns {boolean} - * @expose - */ - Builder.isService = function(def) { - // Services require a string name and an rpc object - if (typeof def["name"] !== 'string' || typeof def["rpc"] !== 'object' || !def["rpc"]) - return false; - return true; - }; - - /** - * Tests if a definition most likely describes an extended message - * @param {!Object} def - * @returns {boolean} - * @expose - */ - Builder.isExtend = function(def) { - // Extends rquire a string ref - if (typeof def["ref"] !== 'string') - return false; - return true; - }; - - // ----- Building ----- - - /** - * Resets the pointer to the root namespace. - * @returns {!ProtoBuf.Builder} this - * @expose - */ - BuilderPrototype.reset = function() { - this.ptr = this.ns; - return this; - }; - - /** - * Defines a namespace on top of the current pointer position and places the pointer on it. - * @param {string} namespace - * @return {!ProtoBuf.Builder} this - * @expose - */ - BuilderPrototype.define = function(namespace) { - if (typeof namespace !== 'string' || !Lang.TYPEREF.test(namespace)) - throw Error("illegal namespace: "+namespace); - namespace.split(".").forEach(function(part) { - var ns = this.ptr.getChild(part); - if (ns === null) // Keep existing - this.ptr.addChild(ns = new Reflect.Namespace(this, this.ptr, part)); - this.ptr = ns; - }, this); - return this; - }; - - /** - * Creates the specified definitions at the current pointer position. - * @param {!Array.} defs Messages, enums or services to create - * @returns {!ProtoBuf.Builder} this - * @throws {Error} If a message definition is invalid - * @expose - */ - BuilderPrototype.create = function(defs) { - if (!defs) - return this; // Nothing to create - if (!Array.isArray(defs)) - defs = [defs]; - else { - if (defs.length === 0) - return this; - defs = defs.slice(); - } - - // It's quite hard to keep track of scopes and memory here, so let's do this iteratively. - var stack = [defs]; - while (stack.length > 0) { - defs = stack.pop(); - - if (!Array.isArray(defs)) // Stack always contains entire namespaces - throw Error("not a valid namespace: "+JSON.stringify(defs)); - - while (defs.length > 0) { - var def = defs.shift(); // Namespaces always contain an array of messages, enums and services - - if (Builder.isMessage(def)) { - var obj = new Reflect.Message(this, this.ptr, def["name"], def["options"], def["isGroup"], def["syntax"]); - - // Create OneOfs - var oneofs = {}; - if (def["oneofs"]) - Object.keys(def["oneofs"]).forEach(function(name) { - obj.addChild(oneofs[name] = new Reflect.Message.OneOf(this, obj, name)); - }, this); - - // Create fields - if (def["fields"]) - def["fields"].forEach(function(fld) { - if (obj.getChild(fld["id"]|0) !== null) - throw Error("duplicate or invalid field id in "+obj.name+": "+fld['id']); - if (fld["options"] && typeof fld["options"] !== 'object') - throw Error("illegal field options in "+obj.name+"#"+fld["name"]); - var oneof = null; - if (typeof fld["oneof"] === 'string' && !(oneof = oneofs[fld["oneof"]])) - throw Error("illegal oneof in "+obj.name+"#"+fld["name"]+": "+fld["oneof"]); - fld = new Reflect.Message.Field(this, obj, fld["rule"], fld["keytype"], fld["type"], fld["name"], fld["id"], fld["options"], oneof, def["syntax"]); - if (oneof) - oneof.fields.push(fld); - obj.addChild(fld); - }, this); - - // Push children to stack - var subObj = []; - if (def["enums"]) - def["enums"].forEach(function(enm) { - subObj.push(enm); - }); - if (def["messages"]) - def["messages"].forEach(function(msg) { - subObj.push(msg); - }); - if (def["services"]) - def["services"].forEach(function(svc) { - subObj.push(svc); - }); - - // Set extension ranges - if (def["extensions"]) { - if (typeof def["extensions"][0] === 'number') // pre 5.0.1 - obj.extensions = [ def["extensions"] ]; - else - obj.extensions = def["extensions"]; - } - - // Create on top of current namespace - this.ptr.addChild(obj); - if (subObj.length > 0) { - stack.push(defs); // Push the current level back - defs = subObj; // Continue processing sub level - subObj = null; - this.ptr = obj; // And move the pointer to this namespace - obj = null; - continue; - } - subObj = null; - - } else if (Builder.isEnum(def)) { - - obj = new Reflect.Enum(this, this.ptr, def["name"], def["options"], def["syntax"]); - def["values"].forEach(function(val) { - obj.addChild(new Reflect.Enum.Value(this, obj, val["name"], val["id"])); - }, this); - this.ptr.addChild(obj); - - } else if (Builder.isService(def)) { - - obj = new Reflect.Service(this, this.ptr, def["name"], def["options"]); - Object.keys(def["rpc"]).forEach(function(name) { - var mtd = def["rpc"][name]; - obj.addChild(new Reflect.Service.RPCMethod(this, obj, name, mtd["request"], mtd["response"], !!mtd["request_stream"], !!mtd["response_stream"], mtd["options"])); - }, this); - this.ptr.addChild(obj); - - } else if (Builder.isExtend(def)) { - - obj = this.ptr.resolve(def["ref"], true); - if (obj) { - def["fields"].forEach(function(fld) { - if (obj.getChild(fld['id']|0) !== null) - throw Error("duplicate extended field id in "+obj.name+": "+fld['id']); - // Check if field id is allowed to be extended - if (obj.extensions) { - var valid = false; - obj.extensions.forEach(function(range) { - if (fld["id"] >= range[0] && fld["id"] <= range[1]) - valid = true; - }); - if (!valid) - throw Error("illegal extended field id in "+obj.name+": "+fld['id']+" (not within valid ranges)"); - } - // Convert extension field names to camel case notation if the override is set - var name = fld["name"]; - if (this.options['convertFieldsToCamelCase']) - name = ProtoBuf.Util.toCamelCase(name); - // see #161: Extensions use their fully qualified name as their runtime key and... - var field = new Reflect.Message.ExtensionField(this, obj, fld["rule"], fld["type"], this.ptr.fqn()+'.'+name, fld["id"], fld["options"]); - // ...are added on top of the current namespace as an extension which is used for - // resolving their type later on (the extension always keeps the original name to - // prevent naming collisions) - var ext = new Reflect.Extension(this, this.ptr, fld["name"], field); - field.extension = ext; - this.ptr.addChild(ext); - obj.addChild(field); - }, this); - - } else if (!/\.?google\.protobuf\./.test(def["ref"])) // Silently skip internal extensions - throw Error("extended message "+def["ref"]+" is not defined"); - - } else - throw Error("not a valid definition: "+JSON.stringify(def)); - - def = null; - obj = null; - } - // Break goes here - defs = null; - this.ptr = this.ptr.parent; // Namespace done, continue at parent - } - this.resolved = false; // Require re-resolve - this.result = null; // Require re-build - return this; - }; - - /** - * Propagates syntax to all children. - * @param {!Object} parent - * @inner - */ - function propagateSyntax(parent) { - if (parent['messages']) { - parent['messages'].forEach(function(child) { - child["syntax"] = parent["syntax"]; - propagateSyntax(child); - }); - } - if (parent['enums']) { - parent['enums'].forEach(function(child) { - child["syntax"] = parent["syntax"]; - }); - } - } - - /** - * Imports another definition into this builder. - * @param {Object.} json Parsed import - * @param {(string|{root: string, file: string})=} filename Imported file name - * @returns {!ProtoBuf.Builder} this - * @throws {Error} If the definition or file cannot be imported - * @expose - */ - BuilderPrototype["import"] = function(json, filename) { - var delim = '/'; - - // Make sure to skip duplicate imports - - if (typeof filename === 'string') { - - if (ProtoBuf.Util.IS_NODE) - filename = require("path")['resolve'](filename); - if (this.files[filename] === true) - return this.reset(); - this.files[filename] = true; - - } else if (typeof filename === 'object') { // Object with root, file. - - var root = filename.root; - if (ProtoBuf.Util.IS_NODE) - root = require("path")['resolve'](root); - if (root.indexOf("\\") >= 0 || filename.file.indexOf("\\") >= 0) - delim = '\\'; - var fname = root + delim + filename.file; - if (this.files[fname] === true) - return this.reset(); - this.files[fname] = true; - } - - // Import imports - - if (json['imports'] && json['imports'].length > 0) { - var importRoot, - resetRoot = false; - - if (typeof filename === 'object') { // If an import root is specified, override - - this.importRoot = filename["root"]; resetRoot = true; // ... and reset afterwards - importRoot = this.importRoot; - filename = filename["file"]; - if (importRoot.indexOf("\\") >= 0 || filename.indexOf("\\") >= 0) - delim = '\\'; - - } else if (typeof filename === 'string') { - - if (this.importRoot) // If import root is overridden, use it - importRoot = this.importRoot; - else { // Otherwise compute from filename - if (filename.indexOf("/") >= 0) { // Unix - importRoot = filename.replace(/\/[^\/]*$/, ""); - if (/* /file.proto */ importRoot === "") - importRoot = "/"; - } else if (filename.indexOf("\\") >= 0) { // Windows - importRoot = filename.replace(/\\[^\\]*$/, ""); - delim = '\\'; - } else - importRoot = "."; - } - - } else - importRoot = null; - - for (var i=0; i)=} path Specifies what to return. If omitted, the entire namespace will be returned. - * @returns {!ProtoBuf.Builder.Message|!Object.} - * @throws {Error} If a type could not be resolved - * @expose - */ - BuilderPrototype.build = function(path) { - this.reset(); - if (!this.resolved) - this.resolveAll(), - this.resolved = true, - this.result = null; // Require re-build - if (this.result === null) // (Re-)Build - this.result = this.ns.build(); - if (!path) - return this.result; - var part = typeof path === 'string' ? path.split(".") : path, - ptr = this.result; // Build namespace pointer (no hasChild etc.) - for (var i=0; i=} contents Initial contents - * @constructor - */ - var Map = function(field, contents) { - if (!field.map) - throw Error("field is not a map"); - - /** - * The field corresponding to this map. - * @type {!ProtoBuf.Reflect.Field} - */ - this.field = field; - - /** - * Element instance corresponding to key type. - * @type {!ProtoBuf.Reflect.Element} - */ - this.keyElem = new Reflect.Element(field.keyType, null, true, field.syntax); - - /** - * Element instance corresponding to value type. - * @type {!ProtoBuf.Reflect.Element} - */ - this.valueElem = new Reflect.Element(field.type, field.resolvedType, false, field.syntax); - - /** - * Internal map: stores mapping of (string form of key) -> (key, value) - * pair. - * - * We provide map semantics for arbitrary key types, but we build on top - * of an Object, which has only string keys. In order to avoid the need - * to convert a string key back to its native type in many situations, - * we store the native key value alongside the value. Thus, we only need - * a one-way mapping from a key type to its string form that guarantees - * uniqueness and equality (i.e., str(K1) === str(K2) if and only if K1 - * === K2). - * - * @type {!Object} - */ - this.map = {}; - - /** - * Returns the number of elements in the map. - */ - Object.defineProperty(this, "size", { - get: function() { return Object.keys(this.map).length; } - }); - - // Fill initial contents from a raw object. - if (contents) { - var keys = Object.keys(contents); - for (var i = 0; i < keys.length; i++) { - var key = this.keyElem.valueFromString(keys[i]); - var val = this.valueElem.verifyValue(contents[keys[i]]); - this.map[this.keyElem.valueToString(key)] = - { key: key, value: val }; - } - } - }; - - var MapPrototype = Map.prototype; - - /** - * Helper: return an iterator over an array. - * @param {!Array<*>} arr the array - * @returns {!Object} an iterator - * @inner - */ - function arrayIterator(arr) { - var idx = 0; - return { - next: function() { - if (idx < arr.length) - return { done: false, value: arr[idx++] }; - return { done: true }; - } - } - } - - /** - * Clears the map. - */ - MapPrototype.clear = function() { - this.map = {}; - }; - - /** - * Deletes a particular key from the map. - * @returns {boolean} Whether any entry with this key was deleted. - */ - MapPrototype["delete"] = function(key) { - var keyValue = this.keyElem.valueToString(this.keyElem.verifyValue(key)); - var hadKey = keyValue in this.map; - delete this.map[keyValue]; - return hadKey; - }; - - /** - * Returns an iterator over [key, value] pairs in the map. - * @returns {Object} The iterator - */ - MapPrototype.entries = function() { - var entries = []; - var strKeys = Object.keys(this.map); - for (var i = 0, entry; i < strKeys.length; i++) - entries.push([(entry=this.map[strKeys[i]]).key, entry.value]); - return arrayIterator(entries); - }; - - /** - * Returns an iterator over keys in the map. - * @returns {Object} The iterator - */ - MapPrototype.keys = function() { - var keys = []; - var strKeys = Object.keys(this.map); - for (var i = 0; i < strKeys.length; i++) - keys.push(this.map[strKeys[i]].key); - return arrayIterator(keys); - }; - - /** - * Returns an iterator over values in the map. - * @returns {!Object} The iterator - */ - MapPrototype.values = function() { - var values = []; - var strKeys = Object.keys(this.map); - for (var i = 0; i < strKeys.length; i++) - values.push(this.map[strKeys[i]].value); - return arrayIterator(values); - }; - - /** - * Iterates over entries in the map, calling a function on each. - * @param {function(this:*, *, *, *)} cb The callback to invoke with value, key, and map arguments. - * @param {Object=} thisArg The `this` value for the callback - */ - MapPrototype.forEach = function(cb, thisArg) { - var strKeys = Object.keys(this.map); - for (var i = 0, entry; i < strKeys.length; i++) - cb.call(thisArg, (entry=this.map[strKeys[i]]).value, entry.key, this); - }; - - /** - * Sets a key in the map to the given value. - * @param {*} key The key - * @param {*} value The value - * @returns {!ProtoBuf.Map} The map instance - */ - MapPrototype.set = function(key, value) { - var keyValue = this.keyElem.verifyValue(key); - var valValue = this.valueElem.verifyValue(value); - this.map[this.keyElem.valueToString(keyValue)] = - { key: keyValue, value: valValue }; - return this; - }; - - /** - * Gets the value corresponding to a key in the map. - * @param {*} key The key - * @returns {*|undefined} The value, or `undefined` if key not present - */ - MapPrototype.get = function(key) { - var keyValue = this.keyElem.valueToString(this.keyElem.verifyValue(key)); - if (!(keyValue in this.map)) - return undefined; - return this.map[keyValue].value; - }; - - /** - * Determines whether the given key is present in the map. - * @param {*} key The key - * @returns {boolean} `true` if the key is present - */ - MapPrototype.has = function(key) { - var keyValue = this.keyElem.valueToString(this.keyElem.verifyValue(key)); - return (keyValue in this.map); - }; - - return Map; - })(ProtoBuf, ProtoBuf.Reflect); - - - /** - * Loads a .proto string and returns the Builder. - * @param {string} proto .proto file contents - * @param {(ProtoBuf.Builder|string|{root: string, file: string})=} builder Builder to append to. Will create a new one if omitted. - * @param {(string|{root: string, file: string})=} filename The corresponding file name if known. Must be specified for imports. - * @return {ProtoBuf.Builder} Builder to create new messages - * @throws {Error} If the definition cannot be parsed or built - * @expose - */ - ProtoBuf.loadProto = function(proto, builder, filename) { - if (typeof builder === 'string' || (builder && typeof builder["file"] === 'string' && typeof builder["root"] === 'string')) - filename = builder, - builder = undefined; - return ProtoBuf.loadJson(ProtoBuf.DotProto.Parser.parse(proto), builder, filename); - }; - - /** - * Loads a .proto string and returns the Builder. This is an alias of {@link ProtoBuf.loadProto}. - * @function - * @param {string} proto .proto file contents - * @param {(ProtoBuf.Builder|string)=} builder Builder to append to. Will create a new one if omitted. - * @param {(string|{root: string, file: string})=} filename The corresponding file name if known. Must be specified for imports. - * @return {ProtoBuf.Builder} Builder to create new messages - * @throws {Error} If the definition cannot be parsed or built - * @expose - */ - ProtoBuf.protoFromString = ProtoBuf.loadProto; // Legacy - - /** - * Loads a .proto file and returns the Builder. - * @param {string|{root: string, file: string}} filename Path to proto file or an object specifying 'file' with - * an overridden 'root' path for all imported files. - * @param {function(?Error, !ProtoBuf.Builder=)=} callback Callback that will receive `null` as the first and - * the Builder as its second argument on success, otherwise the error as its first argument. If omitted, the - * file will be read synchronously and this function will return the Builder. - * @param {ProtoBuf.Builder=} builder Builder to append to. Will create a new one if omitted. - * @return {?ProtoBuf.Builder|undefined} The Builder if synchronous (no callback specified, will be NULL if the - * request has failed), else undefined - * @expose - */ - ProtoBuf.loadProtoFile = function(filename, callback, builder) { - if (callback && typeof callback === 'object') - builder = callback, - callback = null; - else if (!callback || typeof callback !== 'function') - callback = null; - if (callback) - return ProtoBuf.Util.fetch(typeof filename === 'string' ? filename : filename["root"]+"/"+filename["file"], function(contents) { - if (contents === null) { - callback(Error("Failed to fetch file")); - return; - } - try { - callback(null, ProtoBuf.loadProto(contents, builder, filename)); - } catch (e) { - callback(e); - } - }); - var contents = ProtoBuf.Util.fetch(typeof filename === 'object' ? filename["root"]+"/"+filename["file"] : filename); - return contents === null ? null : ProtoBuf.loadProto(contents, builder, filename); - }; - - /** - * Loads a .proto file and returns the Builder. This is an alias of {@link ProtoBuf.loadProtoFile}. - * @function - * @param {string|{root: string, file: string}} filename Path to proto file or an object specifying 'file' with - * an overridden 'root' path for all imported files. - * @param {function(?Error, !ProtoBuf.Builder=)=} callback Callback that will receive `null` as the first and - * the Builder as its second argument on success, otherwise the error as its first argument. If omitted, the - * file will be read synchronously and this function will return the Builder. - * @param {ProtoBuf.Builder=} builder Builder to append to. Will create a new one if omitted. - * @return {!ProtoBuf.Builder|undefined} The Builder if synchronous (no callback specified, will be NULL if the - * request has failed), else undefined - * @expose - */ - ProtoBuf.protoFromFile = ProtoBuf.loadProtoFile; // Legacy - - - /** - * Constructs a new empty Builder. - * @param {Object.=} options Builder options, defaults to global options set on ProtoBuf - * @return {!ProtoBuf.Builder} Builder - * @expose - */ - ProtoBuf.newBuilder = function(options) { - options = options || {}; - if (typeof options['convertFieldsToCamelCase'] === 'undefined') - options['convertFieldsToCamelCase'] = ProtoBuf.convertFieldsToCamelCase; - if (typeof options['populateAccessors'] === 'undefined') - options['populateAccessors'] = ProtoBuf.populateAccessors; - return new ProtoBuf.Builder(options); - }; - - /** - * Loads a .json definition and returns the Builder. - * @param {!*|string} json JSON definition - * @param {(ProtoBuf.Builder|string|{root: string, file: string})=} builder Builder to append to. Will create a new one if omitted. - * @param {(string|{root: string, file: string})=} filename The corresponding file name if known. Must be specified for imports. - * @return {ProtoBuf.Builder} Builder to create new messages - * @throws {Error} If the definition cannot be parsed or built - * @expose - */ - ProtoBuf.loadJson = function(json, builder, filename) { - if (typeof builder === 'string' || (builder && typeof builder["file"] === 'string' && typeof builder["root"] === 'string')) - filename = builder, - builder = null; - if (!builder || typeof builder !== 'object') - builder = ProtoBuf.newBuilder(); - if (typeof json === 'string') - json = JSON.parse(json); - builder["import"](json, filename); - builder.resolveAll(); - return builder; - }; - - /** - * Loads a .json file and returns the Builder. - * @param {string|!{root: string, file: string}} filename Path to json file or an object specifying 'file' with - * an overridden 'root' path for all imported files. - * @param {function(?Error, !ProtoBuf.Builder=)=} callback Callback that will receive `null` as the first and - * the Builder as its second argument on success, otherwise the error as its first argument. If omitted, the - * file will be read synchronously and this function will return the Builder. - * @param {ProtoBuf.Builder=} builder Builder to append to. Will create a new one if omitted. - * @return {?ProtoBuf.Builder|undefined} The Builder if synchronous (no callback specified, will be NULL if the - * request has failed), else undefined - * @expose - */ - ProtoBuf.loadJsonFile = function(filename, callback, builder) { - if (callback && typeof callback === 'object') - builder = callback, - callback = null; - else if (!callback || typeof callback !== 'function') - callback = null; - if (callback) - return ProtoBuf.Util.fetch(typeof filename === 'string' ? filename : filename["root"]+"/"+filename["file"], function(contents) { - if (contents === null) { - callback(Error("Failed to fetch file")); - return; - } - try { - callback(null, ProtoBuf.loadJson(JSON.parse(contents), builder, filename)); - } catch (e) { - callback(e); - } - }); - var contents = ProtoBuf.Util.fetch(typeof filename === 'object' ? filename["root"]+"/"+filename["file"] : filename); - return contents === null ? null : ProtoBuf.loadJson(JSON.parse(contents), builder, filename); - }; - - return ProtoBuf; -}); + + /** + * Language expressions. + * @type {!Object.} + * @expose + */ + ProtoBuf.Lang = { + + // Characters always ending a statement + DELIM: /[\s\{\}=;:\[\],'"\(\)<>]/g, + + // Field rules + RULE: /^(?:required|optional|repeated|map)$/, + + // Field types + TYPE: /^(?:double|float|int32|uint32|sint32|int64|uint64|sint64|fixed32|sfixed32|fixed64|sfixed64|bool|string|bytes)$/, + + // Names + NAME: /^[a-zA-Z_][a-zA-Z_0-9]*$/, + + // Type definitions + TYPEDEF: /^[a-zA-Z][a-zA-Z_0-9]*$/, + + // Type references + TYPEREF: /^(?:\.?[a-zA-Z_][a-zA-Z_0-9]*)+$/, + + // Fully qualified type references + FQTYPEREF: /^(?:\.[a-zA-Z][a-zA-Z_0-9]*)+$/, + + // All numbers + NUMBER: /^-?(?:[1-9][0-9]*|0|0[xX][0-9a-fA-F]+|0[0-7]+|([0-9]*(\.[0-9]*)?([Ee][+-]?[0-9]+)?)|inf|nan)$/, + + // Decimal numbers + NUMBER_DEC: /^(?:[1-9][0-9]*|0)$/, + + // Hexadecimal numbers + NUMBER_HEX: /^0[xX][0-9a-fA-F]+$/, + + // Octal numbers + NUMBER_OCT: /^0[0-7]+$/, + + // Floating point numbers + NUMBER_FLT: /^([0-9]*(\.[0-9]*)?([Ee][+-]?[0-9]+)?|inf|nan)$/, + + // Booleans + BOOL: /^(?:true|false)$/i, + + // Id numbers + ID: /^(?:[1-9][0-9]*|0|0[xX][0-9a-fA-F]+|0[0-7]+)$/, + + // Negative id numbers (enum values) + NEGID: /^\-?(?:[1-9][0-9]*|0|0[xX][0-9a-fA-F]+|0[0-7]+)$/, + + // Whitespaces + WHITESPACE: /\s/, + + // All strings + STRING: /(?:"([^"\\]*(?:\\.[^"\\]*)*)")|(?:'([^'\\]*(?:\\.[^'\\]*)*)')/g, + + // Double quoted strings + STRING_DQ: /(?:"([^"\\]*(?:\\.[^"\\]*)*)")/g, + + // Single quoted strings + STRING_SQ: /(?:'([^'\\]*(?:\\.[^'\\]*)*)')/g + }; + + /** + * @alias ProtoBuf.DotProto + * @expose + */ + ProtoBuf.DotProto = (function(ProtoBuf, Lang) { + "use strict"; + + /** + * Utilities to parse .proto files. + * @exports ProtoBuf.DotProto + * @namespace + */ + var DotProto = {}; + + /** + * Constructs a new Tokenizer. + * @exports ProtoBuf.DotProto.Tokenizer + * @class prototype tokenizer + * @param {string} proto Proto to tokenize + * @constructor + */ + var Tokenizer = function(proto) { + + /** + * Source to parse. + * @type {string} + * @expose + */ + this.source = proto+""; + + /** + * Current index. + * @type {number} + * @expose + */ + this.index = 0; + + /** + * Current line. + * @type {number} + * @expose + */ + this.line = 1; + + /** + * Token stack. + * @type {!Array.} + * @expose + */ + this.stack = []; + + /** + * Opening character of the current string read, if any. + * @type {?string} + * @private + */ + this._stringOpen = null; + }; + + /** + * @alias ProtoBuf.DotProto.Tokenizer.prototype + * @inner + */ + var TokenizerPrototype = Tokenizer.prototype; + + /** + * Reads a string beginning at the current index. + * @return {string} + * @private + */ + TokenizerPrototype._readString = function() { + var re = this._stringOpen === '"' + ? Lang.STRING_DQ + : Lang.STRING_SQ; + re.lastIndex = this.index - 1; // Include the open quote + var match = re.exec(this.source); + if (!match) + throw Error("unterminated string"); + this.index = re.lastIndex; + this.stack.push(this._stringOpen); + this._stringOpen = null; + return match[1]; + }; + + /** + * Gets the next token and advances by one. + * @return {?string} Token or `null` on EOF + * @expose + */ + TokenizerPrototype.next = function() { + if (this.stack.length > 0) + return this.stack.shift(); + if (this.index >= this.source.length) + return null; + if (this._stringOpen !== null) + return this._readString(); + + var repeat, + prev, + next; + do { + repeat = false; + + // Strip white spaces + while (Lang.WHITESPACE.test(next = this.source.charAt(this.index))) { + if (next === '\n') + ++this.line; + if (++this.index === this.source.length) + return null; + } + + // Strip comments + if (this.source.charAt(this.index) === '/') { + ++this.index; + if (this.source.charAt(this.index) === '/') { // Line + while (this.source.charAt(++this.index) !== '\n') + if (this.index == this.source.length) + return null; + ++this.index; + ++this.line; + repeat = true; + } else if ((next = this.source.charAt(this.index)) === '*') { /* Block */ + do { + if (next === '\n') + ++this.line; + if (++this.index === this.source.length) + return null; + prev = next; + next = this.source.charAt(this.index); + } while (prev !== '*' || next !== '/'); + ++this.index; + repeat = true; + } else + return '/'; + } + } while (repeat); + + if (this.index === this.source.length) + return null; + + // Read the next token + var end = this.index; + Lang.DELIM.lastIndex = 0; + var delim = Lang.DELIM.test(this.source.charAt(end++)); + if (!delim) + while(end < this.source.length && !Lang.DELIM.test(this.source.charAt(end))) + ++end; + var token = this.source.substring(this.index, this.index = end); + if (token === '"' || token === "'") + this._stringOpen = token; + return token; + }; + + /** + * Peeks for the next token. + * @return {?string} Token or `null` on EOF + * @expose + */ + TokenizerPrototype.peek = function() { + if (this.stack.length === 0) { + var token = this.next(); + if (token === null) + return null; + this.stack.push(token); + } + return this.stack[0]; + }; + + /** + * Skips a specific token and throws if it differs. + * @param {string} expected Expected token + * @throws {Error} If the actual token differs + */ + TokenizerPrototype.skip = function(expected) { + var actual = this.next(); + if (actual !== expected) + throw Error("illegal '"+actual+"', '"+expected+"' expected"); + }; + + /** + * Omits an optional token. + * @param {string} expected Expected optional token + * @returns {boolean} `true` if the token exists + */ + TokenizerPrototype.omit = function(expected) { + if (this.peek() === expected) { + this.next(); + return true; + } + return false; + }; + + /** + * Returns a string representation of this object. + * @return {string} String representation as of "Tokenizer(index/length)" + * @expose + */ + TokenizerPrototype.toString = function() { + return "Tokenizer ("+this.index+"/"+this.source.length+" at line "+this.line+")"; + }; + + /** + * @alias ProtoBuf.DotProto.Tokenizer + * @expose + */ + DotProto.Tokenizer = Tokenizer; + + /** + * Constructs a new Parser. + * @exports ProtoBuf.DotProto.Parser + * @class prototype parser + * @param {string} source Source + * @constructor + */ + var Parser = function(source) { + + /** + * Tokenizer. + * @type {!ProtoBuf.DotProto.Tokenizer} + * @expose + */ + this.tn = new Tokenizer(source); + + /** + * Whether parsing proto3 or not. + * @type {boolean} + */ + this.proto3 = false; + }; + + /** + * @alias ProtoBuf.DotProto.Parser.prototype + * @inner + */ + var ParserPrototype = Parser.prototype; + + /** + * Parses the source. + * @returns {!Object} + * @throws {Error} If the source cannot be parsed + * @expose + */ + ParserPrototype.parse = function() { + var topLevel = { + "name": "[ROOT]", // temporary + "package": null, + "messages": [], + "enums": [], + "imports": [], + "options": {}, + "services": [] + // "syntax": undefined + }; + var token, + head = true, + weak; + try { + while (token = this.tn.next()) { + switch (token) { + case 'package': + if (!head || topLevel["package"] !== null) + throw Error("unexpected 'package'"); + token = this.tn.next(); + if (!Lang.TYPEREF.test(token)) + throw Error("illegal package name: " + token); + this.tn.skip(";"); + topLevel["package"] = token; + break; + case 'import': + if (!head) + throw Error("unexpected 'import'"); + token = this.tn.peek(); + if (token === "public" || (weak = token === "weak")) // token ignored + this.tn.next(); + token = this._readString(); + this.tn.skip(";"); + if (!weak) // import ignored + topLevel["imports"].push(token); + break; + case 'syntax': + if (!head) + throw Error("unexpected 'syntax'"); + this.tn.skip("="); + if ((topLevel["syntax"] = this._readString()) === "proto3") + this.proto3 = true; + this.tn.skip(";"); + break; + case 'message': + this._parseMessage(topLevel, null); + head = false; + break; + case 'enum': + this._parseEnum(topLevel); + head = false; + break; + case 'option': + this._parseOption(topLevel); + break; + case 'service': + this._parseService(topLevel); + break; + case 'extend': + this._parseExtend(topLevel); + break; + default: + throw Error("unexpected '" + token + "'"); + } + } + } catch (e) { + e.message = "Parse error at line "+this.tn.line+": " + e.message; + throw e; + } + delete topLevel["name"]; + return topLevel; + }; + + /** + * Parses the specified source. + * @returns {!Object} + * @throws {Error} If the source cannot be parsed + * @expose + */ + Parser.parse = function(source) { + return new Parser(source).parse(); + }; + + // ----- Conversion ------ + + /** + * Converts a numerical string to an id. + * @param {string} value + * @param {boolean=} mayBeNegative + * @returns {number} + * @inner + */ + function mkId(value, mayBeNegative) { + var id = -1, + sign = 1; + if (value.charAt(0) == '-') { + sign = -1; + value = value.substring(1); + } + if (Lang.NUMBER_DEC.test(value)) + id = parseInt(value); + else if (Lang.NUMBER_HEX.test(value)) + id = parseInt(value.substring(2), 16); + else if (Lang.NUMBER_OCT.test(value)) + id = parseInt(value.substring(1), 8); + else + throw Error("illegal id value: " + (sign < 0 ? '-' : '') + value); + id = (sign*id)|0; // Force to 32bit + if (!mayBeNegative && id < 0) + throw Error("illegal id value: " + (sign < 0 ? '-' : '') + value); + return id; + } + + /** + * Converts a numerical string to a number. + * @param {string} val + * @returns {number} + * @inner + */ + function mkNumber(val) { + var sign = 1; + if (val.charAt(0) == '-') { + sign = -1; + val = val.substring(1); + } + if (Lang.NUMBER_DEC.test(val)) + return sign * parseInt(val, 10); + else if (Lang.NUMBER_HEX.test(val)) + return sign * parseInt(val.substring(2), 16); + else if (Lang.NUMBER_OCT.test(val)) + return sign * parseInt(val.substring(1), 8); + else if (val === 'inf') + return sign * Infinity; + else if (val === 'nan') + return NaN; + else if (Lang.NUMBER_FLT.test(val)) + return sign * parseFloat(val); + throw Error("illegal number value: " + (sign < 0 ? '-' : '') + val); + } + + // ----- Reading ------ + + /** + * Reads a string. + * @returns {string} + * @private + */ + ParserPrototype._readString = function() { + var value = "", + token, + delim; + do { + delim = this.tn.next(); + if (delim !== "'" && delim !== '"') + throw Error("illegal string delimiter: "+delim); + value += this.tn.next(); + this.tn.skip(delim); + token = this.tn.peek(); + } while (token === '"' || token === '"'); // multi line? + return value; + }; + + /** + * Reads a value. + * @param {boolean=} mayBeTypeRef + * @returns {number|boolean|string} + * @private + */ + ParserPrototype._readValue = function(mayBeTypeRef) { + var token = this.tn.peek(), + value; + if (token === '"' || token === "'") + return this._readString(); + this.tn.next(); + if (Lang.NUMBER.test(token)) + return mkNumber(token); + if (Lang.BOOL.test(token)) + return (token.toLowerCase() === 'true'); + if (mayBeTypeRef && Lang.TYPEREF.test(token)) + return token; + throw Error("illegal value: "+token); + + }; + + // ----- Parsing constructs ----- + + /** + * Parses a namespace option. + * @param {!Object} parent Parent definition + * @param {boolean=} isList + * @private + */ + ParserPrototype._parseOption = function(parent, isList) { + var token = this.tn.next(), + custom = false; + if (token === '(') { + custom = true; + token = this.tn.next(); + } + if (!Lang.TYPEREF.test(token)) + // we can allow options of the form google.protobuf.* since they will just get ignored anyways + // if (!/google\.protobuf\./.test(token)) // FIXME: Why should that not be a valid typeref? + throw Error("illegal option name: "+token); + var name = token; + if (custom) { // (my_method_option).foo, (my_method_option), some_method_option, (foo.my_option).bar + this.tn.skip(')'); + name = '('+name+')'; + token = this.tn.peek(); + if (Lang.FQTYPEREF.test(token)) { + name += token; + this.tn.next(); + } + } + this.tn.skip('='); + this._parseOptionValue(parent, name); + if (!isList) + this.tn.skip(";"); + }; + + /** + * Sets an option on the specified options object. + * @param {!Object.} options + * @param {string} name + * @param {string|number|boolean} value + * @inner + */ + function setOption(options, name, value) { + if (typeof options[name] === 'undefined') + options[name] = value; + else { + if (!Array.isArray(options[name])) + options[name] = [ options[name] ]; + options[name].push(value); + } + } + + /** + * Parses an option value. + * @param {!Object} parent + * @param {string} name + * @private + */ + ParserPrototype._parseOptionValue = function(parent, name) { + var token = this.tn.peek(); + if (token !== '{') { // Plain value + setOption(parent["options"], name, this._readValue(true)); + } else { // Aggregate options + this.tn.skip("{"); + while ((token = this.tn.next()) !== '}') { + if (!Lang.NAME.test(token)) + throw Error("illegal option name: " + name + "." + token); + if (this.tn.omit(":")) + setOption(parent["options"], name + "." + token, this._readValue(true)); + else + this._parseOptionValue(parent, name + "." + token); + } + } + }; + + /** + * Parses a service definition. + * @param {!Object} parent Parent definition + * @private + */ + ParserPrototype._parseService = function(parent) { + var token = this.tn.next(); + if (!Lang.NAME.test(token)) + throw Error("illegal service name at line "+this.tn.line+": "+token); + var name = token; + var svc = { + "name": name, + "rpc": {}, + "options": {} + }; + this.tn.skip("{"); + while ((token = this.tn.next()) !== '}') { + if (token === "option") + this._parseOption(svc); + else if (token === 'rpc') + this._parseServiceRPC(svc); + else + throw Error("illegal service token: "+token); + } + this.tn.omit(";"); + parent["services"].push(svc); + }; + + /** + * Parses a RPC service definition of the form ['rpc', name, (request), 'returns', (response)]. + * @param {!Object} svc Service definition + * @private + */ + ParserPrototype._parseServiceRPC = function(svc) { + var type = "rpc", + token = this.tn.next(); + if (!Lang.NAME.test(token)) + throw Error("illegal rpc service method name: "+token); + var name = token; + var method = { + "request": null, + "response": null, + "request_stream": false, + "response_stream": false, + "options": {} + }; + this.tn.skip("("); + token = this.tn.next(); + if (token.toLowerCase() === "stream") { + method["request_stream"] = true; + token = this.tn.next(); + } + if (!Lang.TYPEREF.test(token)) + throw Error("illegal rpc service request type: "+token); + method["request"] = token; + this.tn.skip(")"); + token = this.tn.next(); + if (token.toLowerCase() !== "returns") + throw Error("illegal rpc service request type delimiter: "+token); + this.tn.skip("("); + token = this.tn.next(); + if (token.toLowerCase() === "stream") { + method["response_stream"] = true; + token = this.tn.next(); + } + method["response"] = token; + this.tn.skip(")"); + token = this.tn.peek(); + if (token === '{') { + this.tn.next(); + while ((token = this.tn.next()) !== '}') { + if (token === 'option') + this._parseOption(method); + else + throw Error("illegal rpc service token: " + token); + } + this.tn.omit(";"); + } else + this.tn.skip(";"); + if (typeof svc[type] === 'undefined') + svc[type] = {}; + svc[type][name] = method; + }; + + /** + * Parses a message definition. + * @param {!Object} parent Parent definition + * @param {!Object=} fld Field definition if this is a group + * @returns {!Object} + * @private + */ + ParserPrototype._parseMessage = function(parent, fld) { + var isGroup = !!fld, + token = this.tn.next(); + var msg = { + "name": "", + "fields": [], + "enums": [], + "messages": [], + "options": {}, + "services": [], + "oneofs": {} + // "extensions": undefined + }; + if (!Lang.NAME.test(token)) + throw Error("illegal "+(isGroup ? "group" : "message")+" name: "+token); + msg["name"] = token; + if (isGroup) { + this.tn.skip("="); + fld["id"] = mkId(this.tn.next()); + msg["isGroup"] = true; + } + token = this.tn.peek(); + if (token === '[' && fld) + this._parseFieldOptions(fld); + this.tn.skip("{"); + while ((token = this.tn.next()) !== '}') { + if (Lang.RULE.test(token)) + this._parseMessageField(msg, token); + else if (token === "oneof") + this._parseMessageOneOf(msg); + else if (token === "enum") + this._parseEnum(msg); + else if (token === "message") + this._parseMessage(msg); + else if (token === "option") + this._parseOption(msg); + else if (token === "service") + this._parseService(msg); + else if (token === "extensions") + msg["extensions"] = this._parseExtensionRanges(); + else if (token === "reserved") + this._parseIgnored(); // TODO + else if (token === "extend") + this._parseExtend(msg); + else if (Lang.TYPEREF.test(token)) { + if (!this.proto3) + throw Error("illegal field rule: "+token); + this._parseMessageField(msg, "optional", token); + } else + throw Error("illegal message token: "+token); + } + this.tn.omit(";"); + parent["messages"].push(msg); + return msg; + }; + + /** + * Parses an ignored statement. + * @private + */ + ParserPrototype._parseIgnored = function() { + while (this.tn.peek() !== ';') + this.tn.next(); + this.tn.skip(";"); + }; + + /** + * Parses a message field. + * @param {!Object} msg Message definition + * @param {string} rule Field rule + * @param {string=} type Field type if already known (never known for maps) + * @returns {!Object} Field descriptor + * @private + */ + ParserPrototype._parseMessageField = function(msg, rule, type) { + if (!Lang.RULE.test(rule)) + throw Error("illegal message field rule: "+rule); + var fld = { + "rule": rule, + "type": "", + "name": "", + "options": {}, + "id": 0 + }; + var token; + if (rule === "map") { + + if (type) + throw Error("illegal type: " + type); + this.tn.skip('<'); + token = this.tn.next(); + if (!Lang.TYPE.test(token) && !Lang.TYPEREF.test(token)) + throw Error("illegal message field type: " + token); + fld["keytype"] = token; + this.tn.skip(','); + token = this.tn.next(); + if (!Lang.TYPE.test(token) && !Lang.TYPEREF.test(token)) + throw Error("illegal message field: " + token); + fld["type"] = token; + this.tn.skip('>'); + token = this.tn.next(); + if (!Lang.NAME.test(token)) + throw Error("illegal message field name: " + token); + fld["name"] = token; + this.tn.skip("="); + fld["id"] = mkId(this.tn.next()); + token = this.tn.peek(); + if (token === '[') + this._parseFieldOptions(fld); + this.tn.skip(";"); + + } else { + + type = typeof type !== 'undefined' ? type : this.tn.next(); + + if (type === "group") { + + // "A [legacy] group simply combines a nested message type and a field into a single declaration. In your + // code, you can treat this message just as if it had a Result type field called result (the latter name is + // converted to lower-case so that it does not conflict with the former)." + var grp = this._parseMessage(msg, fld); + if (!/^[A-Z]/.test(grp["name"])) + throw Error('illegal group name: '+grp["name"]); + fld["type"] = grp["name"]; + fld["name"] = grp["name"].toLowerCase(); + this.tn.omit(";"); + + } else { + + if (!Lang.TYPE.test(type) && !Lang.TYPEREF.test(type)) + throw Error("illegal message field type: " + type); + fld["type"] = type; + token = this.tn.next(); + if (!Lang.NAME.test(token)) + throw Error("illegal message field name: " + token); + fld["name"] = token; + this.tn.skip("="); + fld["id"] = mkId(this.tn.next()); + token = this.tn.peek(); + if (token === "[") + this._parseFieldOptions(fld); + this.tn.skip(";"); + + } + } + msg["fields"].push(fld); + return fld; + }; + + /** + * Parses a message oneof. + * @param {!Object} msg Message definition + * @private + */ + ParserPrototype._parseMessageOneOf = function(msg) { + var token = this.tn.next(); + if (!Lang.NAME.test(token)) + throw Error("illegal oneof name: "+token); + var name = token, + fld; + var fields = []; + this.tn.skip("{"); + while ((token = this.tn.next()) !== "}") { + fld = this._parseMessageField(msg, "optional", token); + fld["oneof"] = name; + fields.push(fld["id"]); + } + this.tn.omit(";"); + msg["oneofs"][name] = fields; + }; + + /** + * Parses a set of field option definitions. + * @param {!Object} fld Field definition + * @private + */ + ParserPrototype._parseFieldOptions = function(fld) { + this.tn.skip("["); + var token, + first = true; + while ((token = this.tn.peek()) !== ']') { + if (!first) + this.tn.skip(","); + this._parseOption(fld, true); + first = false; + } + this.tn.next(); + }; + + /** + * Parses an enum. + * @param {!Object} msg Message definition + * @private + */ + ParserPrototype._parseEnum = function(msg) { + var enm = { + "name": "", + "values": [], + "options": {} + }; + var token = this.tn.next(); + if (!Lang.NAME.test(token)) + throw Error("illegal name: "+token); + enm["name"] = token; + this.tn.skip("{"); + while ((token = this.tn.next()) !== '}') { + if (token === "option") + this._parseOption(enm); + else { + if (!Lang.NAME.test(token)) + throw Error("illegal name: "+token); + this.tn.skip("="); + var val = { + "name": token, + "id": mkId(this.tn.next(), true) + }; + token = this.tn.peek(); + if (token === "[") + this._parseFieldOptions({ "options": {} }); + this.tn.skip(";"); + enm["values"].push(val); + } + } + this.tn.omit(";"); + msg["enums"].push(enm); + }; + + /** + * Parses extension / reserved ranges. + * @returns {!Array.>} + * @private + */ + ParserPrototype._parseExtensionRanges = function() { + var ranges = []; + var token, + range, + value; + do { + range = []; + while (true) { + token = this.tn.next(); + switch (token) { + case "min": + value = ProtoBuf.ID_MIN; + break; + case "max": + value = ProtoBuf.ID_MAX; + break; + default: + value = mkNumber(token); + break; + } + range.push(value); + if (range.length === 2) + break; + if (this.tn.peek() !== "to") { + range.push(value); + break; + } + this.tn.next(); + } + ranges.push(range); + } while (this.tn.omit(",")); + this.tn.skip(";"); + return ranges; + }; + + /** + * Parses an extend block. + * @param {!Object} parent Parent object + * @private + */ + ParserPrototype._parseExtend = function(parent) { + var token = this.tn.next(); + if (!Lang.TYPEREF.test(token)) + throw Error("illegal extend reference: "+token); + var ext = { + "ref": token, + "fields": [] + }; + this.tn.skip("{"); + while ((token = this.tn.next()) !== '}') { + if (Lang.RULE.test(token)) + this._parseMessageField(ext, token); + else if (Lang.TYPEREF.test(token)) { + if (!this.proto3) + throw Error("illegal field rule: "+token); + this._parseMessageField(ext, "optional", token); + } else + throw Error("illegal extend token: "+token); + } + this.tn.omit(";"); + parent["messages"].push(ext); + return ext; + }; + + // ----- General ----- + + /** + * Returns a string representation of this parser. + * @returns {string} + */ + ParserPrototype.toString = function() { + return "Parser at line "+this.tn.line; + }; + + /** + * @alias ProtoBuf.DotProto.Parser + * @expose + */ + DotProto.Parser = Parser; + + return DotProto; + + })(ProtoBuf, ProtoBuf.Lang); + + /** + * @alias ProtoBuf.Reflect + * @expose + */ + ProtoBuf.Reflect = (function(ProtoBuf) { + "use strict"; + + /** + * Reflection types. + * @exports ProtoBuf.Reflect + * @namespace + */ + var Reflect = {}; + + /** + * Constructs a Reflect base class. + * @exports ProtoBuf.Reflect.T + * @constructor + * @abstract + * @param {!ProtoBuf.Builder} builder Builder reference + * @param {?ProtoBuf.Reflect.T} parent Parent object + * @param {string} name Object name + */ + var T = function(builder, parent, name) { + + /** + * Builder reference. + * @type {!ProtoBuf.Builder} + * @expose + */ + this.builder = builder; + + /** + * Parent object. + * @type {?ProtoBuf.Reflect.T} + * @expose + */ + this.parent = parent; + + /** + * Object name in namespace. + * @type {string} + * @expose + */ + this.name = name; + + /** + * Fully qualified class name + * @type {string} + * @expose + */ + this.className; + }; + + /** + * @alias ProtoBuf.Reflect.T.prototype + * @inner + */ + var TPrototype = T.prototype; + + /** + * Returns the fully qualified name of this object. + * @returns {string} Fully qualified name as of ".PATH.TO.THIS" + * @expose + */ + TPrototype.fqn = function() { + var name = this.name, + ptr = this; + do { + ptr = ptr.parent; + if (ptr == null) + break; + name = ptr.name+"."+name; + } while (true); + return name; + }; + + /** + * Returns a string representation of this Reflect object (its fully qualified name). + * @param {boolean=} includeClass Set to true to include the class name. Defaults to false. + * @return String representation + * @expose + */ + TPrototype.toString = function(includeClass) { + return (includeClass ? this.className + " " : "") + this.fqn(); + }; + + /** + * Builds this type. + * @throws {Error} If this type cannot be built directly + * @expose + */ + TPrototype.build = function() { + throw Error(this.toString(true)+" cannot be built directly"); + }; + + /** + * @alias ProtoBuf.Reflect.T + * @expose + */ + Reflect.T = T; + + /** + * Constructs a new Namespace. + * @exports ProtoBuf.Reflect.Namespace + * @param {!ProtoBuf.Builder} builder Builder reference + * @param {?ProtoBuf.Reflect.Namespace} parent Namespace parent + * @param {string} name Namespace name + * @param {Object.=} options Namespace options + * @param {string?} syntax The syntax level of this definition (e.g., proto3) + * @constructor + * @extends ProtoBuf.Reflect.T + */ + var Namespace = function(builder, parent, name, options, syntax) { + T.call(this, builder, parent, name); + + /** + * @override + */ + this.className = "Namespace"; + + /** + * Children inside the namespace. + * @type {!Array.} + */ + this.children = []; + + /** + * Options. + * @type {!Object.} + */ + this.options = options || {}; + + /** + * Syntax level (e.g., proto2 or proto3). + * @type {!string} + */ + this.syntax = syntax || "proto2"; + }; + + /** + * @alias ProtoBuf.Reflect.Namespace.prototype + * @inner + */ + var NamespacePrototype = Namespace.prototype = Object.create(T.prototype); + + /** + * Returns an array of the namespace's children. + * @param {ProtoBuf.Reflect.T=} type Filter type (returns instances of this type only). Defaults to null (all children). + * @return {Array.} + * @expose + */ + NamespacePrototype.getChildren = function(type) { + type = type || null; + if (type == null) + return this.children.slice(); + var children = []; + for (var i=0, k=this.children.length; i} qn Qualified name to resolve + * @param {boolean=} excludeNonNamespace Excludes non-namespace types, defaults to `false` + * @return {?ProtoBuf.Reflect.Namespace} The resolved type or null if not found + * @expose + */ + NamespacePrototype.resolve = function(qn, excludeNonNamespace) { + var part = typeof qn === 'string' ? qn.split(".") : qn, + ptr = this, + i = 0; + if (part[i] === "") { // Fully qualified name, e.g. ".My.Message' + while (ptr.parent !== null) + ptr = ptr.parent; + i++; + } + var child; + do { + do { + if (!(ptr instanceof Reflect.Namespace)) { + ptr = null; + break; + } + child = ptr.getChild(part[i]); + if (!child || !(child instanceof Reflect.T) || (excludeNonNamespace && !(child instanceof Reflect.Namespace))) { + ptr = null; + break; + } + ptr = child; i++; + } while (i < part.length); + if (ptr != null) + break; // Found + // Else search the parent + if (this.parent !== null) + return this.parent.resolve(qn, excludeNonNamespace); + } while (ptr != null); + return ptr; + }; + + /** + * Determines the shortest qualified name of the specified type, if any, relative to this namespace. + * @param {!ProtoBuf.Reflect.T} t Reflection type + * @returns {string} The shortest qualified name or, if there is none, the fqn + * @expose + */ + NamespacePrototype.qn = function(t) { + var part = [], ptr = t; + do { + part.unshift(ptr.name); + ptr = ptr.parent; + } while (ptr !== null); + for (var len=1; len <= part.length; len++) { + var qn = part.slice(part.length-len); + if (t === this.resolve(qn, t instanceof Reflect.Namespace)) + return qn.join("."); + } + return t.fqn(); + }; + + /** + * Builds the namespace and returns the runtime counterpart. + * @return {Object.} Runtime namespace + * @expose + */ + NamespacePrototype.build = function() { + /** @dict */ + var ns = {}; + var children = this.children; + for (var i=0, k=children.length, child; i} + */ + NamespacePrototype.buildOpt = function() { + var opt = {}, + keys = Object.keys(this.options); + for (var i=0, k=keys.length; i}null} Option value or NULL if there is no such option + */ + NamespacePrototype.getOption = function(name) { + if (typeof name === 'undefined') + return this.options; + return typeof this.options[name] !== 'undefined' ? this.options[name] : null; + }; + + /** + * @alias ProtoBuf.Reflect.Namespace + * @expose + */ + Reflect.Namespace = Namespace; + + /** + * Constructs a new Element implementation that checks and converts values for a + * particular field type, as appropriate. + * + * An Element represents a single value: either the value of a singular field, + * or a value contained in one entry of a repeated field or map field. This + * class does not implement these higher-level concepts; it only encapsulates + * the low-level typechecking and conversion. + * + * @exports ProtoBuf.Reflect.Element + * @param {{name: string, wireType: number}} type Resolved data type + * @param {ProtoBuf.Reflect.T|null} resolvedType Resolved type, if relevant + * (e.g. submessage field). + * @param {boolean} isMapKey Is this element a Map key? The value will be + * converted to string form if so. + * @param {string} syntax Syntax level of defining message type, e.g., + * proto2 or proto3. + * @constructor + */ + var Element = function(type, resolvedType, isMapKey, syntax) { + + /** + * Element type, as a string (e.g., int32). + * @type {{name: string, wireType: number}} + */ + this.type = type; + + /** + * Element type reference to submessage or enum definition, if needed. + * @type {ProtoBuf.Reflect.T|null} + */ + this.resolvedType = resolvedType; + + /** + * Element is a map key. + * @type {boolean} + */ + this.isMapKey = isMapKey; + + /** + * Syntax level of defining message type, e.g., proto2 or proto3. + * @type {string} + */ + this.syntax = syntax; + + if (isMapKey && ProtoBuf.MAP_KEY_TYPES.indexOf(type) < 0) + throw Error("Invalid map key type: " + type.name); + }; + + var ElementPrototype = Element.prototype; + + /** + * Obtains a (new) default value for the specified type. + * @param type {string|{name: string, wireType: number}} Field type + * @returns {*} Default value + * @inner + */ + function mkDefault(type) { + if (typeof type === 'string') + type = ProtoBuf.TYPES[type]; + if (typeof type.defaultValue === 'undefined') + throw Error("default value for type "+type.name+" is not supported"); + if (type == ProtoBuf.TYPES["bytes"]) + return new ByteBuffer(0); + return type.defaultValue; + } + + /** + * Returns the default value for this field in proto3. + * @function + * @param type {string|{name: string, wireType: number}} the field type + * @returns {*} Default value + */ + Element.defaultFieldValue = mkDefault; + + /** + * Makes a Long from a value. + * @param {{low: number, high: number, unsigned: boolean}|string|number} value Value + * @param {boolean=} unsigned Whether unsigned or not, defaults to reuse it from Long-like objects or to signed for + * strings and numbers + * @returns {!Long} + * @throws {Error} If the value cannot be converted to a Long + * @inner + */ + function mkLong(value, unsigned) { + if (value && typeof value.low === 'number' && typeof value.high === 'number' && typeof value.unsigned === 'boolean' + && value.low === value.low && value.high === value.high) + return new ProtoBuf.Long(value.low, value.high, typeof unsigned === 'undefined' ? value.unsigned : unsigned); + if (typeof value === 'string') + return ProtoBuf.Long.fromString(value, unsigned || false, 10); + if (typeof value === 'number') + return ProtoBuf.Long.fromNumber(value, unsigned || false); + throw Error("not convertible to Long"); + } + + /** + * Checks if the given value can be set for an element of this type (singular + * field or one element of a repeated field or map). + * @param {*} value Value to check + * @return {*} Verified, maybe adjusted, value + * @throws {Error} If the value cannot be verified for this element slot + * @expose + */ + ElementPrototype.verifyValue = function(value) { + var self = this; + function fail(val, msg) { + throw Error("Illegal value for "+self.toString(true)+" of type "+self.type.name+": "+val+" ("+msg+")"); + } + switch (this.type) { + // Signed 32bit + case ProtoBuf.TYPES["int32"]: + case ProtoBuf.TYPES["sint32"]: + case ProtoBuf.TYPES["sfixed32"]: + // Account for !NaN: value === value + if (typeof value !== 'number' || (value === value && value % 1 !== 0)) + fail(typeof value, "not an integer"); + return value > 4294967295 ? value | 0 : value; + + // Unsigned 32bit + case ProtoBuf.TYPES["uint32"]: + case ProtoBuf.TYPES["fixed32"]: + if (typeof value !== 'number' || (value === value && value % 1 !== 0)) + fail(typeof value, "not an integer"); + return value < 0 ? value >>> 0 : value; + + // Signed 64bit + case ProtoBuf.TYPES["int64"]: + case ProtoBuf.TYPES["sint64"]: + case ProtoBuf.TYPES["sfixed64"]: { + if (ProtoBuf.Long) + try { + return mkLong(value, false); + } catch (e) { + fail(typeof value, e.message); + } + else + fail(typeof value, "requires Long.js"); + } + + // Unsigned 64bit + case ProtoBuf.TYPES["uint64"]: + case ProtoBuf.TYPES["fixed64"]: { + if (ProtoBuf.Long) + try { + return mkLong(value, true); + } catch (e) { + fail(typeof value, e.message); + } + else + fail(typeof value, "requires Long.js"); + } + + // Bool + case ProtoBuf.TYPES["bool"]: + if (typeof value !== 'boolean') + fail(typeof value, "not a boolean"); + return value; + + // Float + case ProtoBuf.TYPES["float"]: + case ProtoBuf.TYPES["double"]: + if (typeof value !== 'number') + fail(typeof value, "not a number"); + return value; + + // Length-delimited string + case ProtoBuf.TYPES["string"]: + if (typeof value !== 'string' && !(value && value instanceof String)) + fail(typeof value, "not a string"); + return ""+value; // Convert String object to string + + // Length-delimited bytes + case ProtoBuf.TYPES["bytes"]: + if (ByteBuffer.isByteBuffer(value)) + return value; + return ByteBuffer.wrap(value, "base64"); + + // Constant enum value + case ProtoBuf.TYPES["enum"]: { + var values = this.resolvedType.getChildren(ProtoBuf.Reflect.Enum.Value); + for (i=0; i 4294967295 || value < 0) + fail(typeof value, "not in range for uint32") + return value; + } else { + // proto2 requires enum values to be valid. + fail(value, "not a valid enum value"); + } + } + // Embedded message + case ProtoBuf.TYPES["group"]: + case ProtoBuf.TYPES["message"]: { + if (!value || typeof value !== 'object') + fail(typeof value, "object expected"); + if (value instanceof this.resolvedType.clazz) + return value; + if (value instanceof ProtoBuf.Builder.Message) { + // Mismatched type: Convert to object (see: https://github.com/dcodeIO/ProtoBuf.js/issues/180) + var obj = {}; + for (var i in value) + if (value.hasOwnProperty(i)) + obj[i] = value[i]; + value = obj; + } + // Else let's try to construct one from a key-value object + return new (this.resolvedType.clazz)(value); // May throw for a hundred of reasons + } + } + + // We should never end here + throw Error("[INTERNAL] Illegal value for "+this.toString(true)+": "+value+" (undefined type "+this.type+")"); + }; + + /** + * Calculates the byte length of an element on the wire. + * @param {number} id Field number + * @param {*} value Field value + * @returns {number} Byte length + * @throws {Error} If the value cannot be calculated + * @expose + */ + ElementPrototype.calculateLength = function(id, value) { + if (value === null) return 0; // Nothing to encode + // Tag has already been written + var n; + switch (this.type) { + case ProtoBuf.TYPES["int32"]: + return value < 0 ? ByteBuffer.calculateVarint64(value) : ByteBuffer.calculateVarint32(value); + case ProtoBuf.TYPES["uint32"]: + return ByteBuffer.calculateVarint32(value); + case ProtoBuf.TYPES["sint32"]: + return ByteBuffer.calculateVarint32(ByteBuffer.zigZagEncode32(value)); + case ProtoBuf.TYPES["fixed32"]: + case ProtoBuf.TYPES["sfixed32"]: + case ProtoBuf.TYPES["float"]: + return 4; + case ProtoBuf.TYPES["int64"]: + case ProtoBuf.TYPES["uint64"]: + return ByteBuffer.calculateVarint64(value); + case ProtoBuf.TYPES["sint64"]: + return ByteBuffer.calculateVarint64(ByteBuffer.zigZagEncode64(value)); + case ProtoBuf.TYPES["fixed64"]: + case ProtoBuf.TYPES["sfixed64"]: + return 8; + case ProtoBuf.TYPES["bool"]: + return 1; + case ProtoBuf.TYPES["enum"]: + return ByteBuffer.calculateVarint32(value); + case ProtoBuf.TYPES["double"]: + return 8; + case ProtoBuf.TYPES["string"]: + n = ByteBuffer.calculateUTF8Bytes(value); + return ByteBuffer.calculateVarint32(n) + n; + case ProtoBuf.TYPES["bytes"]: + if (value.remaining() < 0) + throw Error("Illegal value for "+this.toString(true)+": "+value.remaining()+" bytes remaining"); + return ByteBuffer.calculateVarint32(value.remaining()) + value.remaining(); + case ProtoBuf.TYPES["message"]: + n = this.resolvedType.calculate(value); + return ByteBuffer.calculateVarint32(n) + n; + case ProtoBuf.TYPES["group"]: + n = this.resolvedType.calculate(value); + return n + ByteBuffer.calculateVarint32((id << 3) | ProtoBuf.WIRE_TYPES.ENDGROUP); + } + // We should never end here + throw Error("[INTERNAL] Illegal value to encode in "+this.toString(true)+": "+value+" (unknown type)"); + }; + + /** + * Encodes a value to the specified buffer. Does not encode the key. + * @param {number} id Field number + * @param {*} value Field value + * @param {ByteBuffer} buffer ByteBuffer to encode to + * @return {ByteBuffer} The ByteBuffer for chaining + * @throws {Error} If the value cannot be encoded + * @expose + */ + ElementPrototype.encodeValue = function(id, value, buffer) { + if (value === null) return buffer; // Nothing to encode + // Tag has already been written + + switch (this.type) { + // 32bit signed varint + case ProtoBuf.TYPES["int32"]: + // "If you use int32 or int64 as the type for a negative number, the resulting varint is always ten bytes + // long – it is, effectively, treated like a very large unsigned integer." (see #122) + if (value < 0) + buffer.writeVarint64(value); + else + buffer.writeVarint32(value); + break; + + // 32bit unsigned varint + case ProtoBuf.TYPES["uint32"]: + buffer.writeVarint32(value); + break; + + // 32bit varint zig-zag + case ProtoBuf.TYPES["sint32"]: + buffer.writeVarint32ZigZag(value); + break; + + // Fixed unsigned 32bit + case ProtoBuf.TYPES["fixed32"]: + buffer.writeUint32(value); + break; + + // Fixed signed 32bit + case ProtoBuf.TYPES["sfixed32"]: + buffer.writeInt32(value); + break; + + // 64bit varint as-is + case ProtoBuf.TYPES["int64"]: + case ProtoBuf.TYPES["uint64"]: + buffer.writeVarint64(value); // throws + break; + + // 64bit varint zig-zag + case ProtoBuf.TYPES["sint64"]: + buffer.writeVarint64ZigZag(value); // throws + break; + + // Fixed unsigned 64bit + case ProtoBuf.TYPES["fixed64"]: + buffer.writeUint64(value); // throws + break; + + // Fixed signed 64bit + case ProtoBuf.TYPES["sfixed64"]: + buffer.writeInt64(value); // throws + break; + + // Bool + case ProtoBuf.TYPES["bool"]: + if (typeof value === 'string') + buffer.writeVarint32(value.toLowerCase() === 'false' ? 0 : !!value); + else + buffer.writeVarint32(value ? 1 : 0); + break; + + // Constant enum value + case ProtoBuf.TYPES["enum"]: + buffer.writeVarint32(value); + break; + + // 32bit float + case ProtoBuf.TYPES["float"]: + buffer.writeFloat32(value); + break; + + // 64bit float + case ProtoBuf.TYPES["double"]: + buffer.writeFloat64(value); + break; + + // Length-delimited string + case ProtoBuf.TYPES["string"]: + buffer.writeVString(value); + break; + + // Length-delimited bytes + case ProtoBuf.TYPES["bytes"]: + if (value.remaining() < 0) + throw Error("Illegal value for "+this.toString(true)+": "+value.remaining()+" bytes remaining"); + var prevOffset = value.offset; + buffer.writeVarint32(value.remaining()); + buffer.append(value); + value.offset = prevOffset; + break; + + // Embedded message + case ProtoBuf.TYPES["message"]: + var bb = new ByteBuffer().LE(); + this.resolvedType.encode(value, bb); + buffer.writeVarint32(bb.offset); + buffer.append(bb.flip()); + break; + + // Legacy group + case ProtoBuf.TYPES["group"]: + this.resolvedType.encode(value, buffer); + buffer.writeVarint32((id << 3) | ProtoBuf.WIRE_TYPES.ENDGROUP); + break; + + default: + // We should never end here + throw Error("[INTERNAL] Illegal value to encode in "+this.toString(true)+": "+value+" (unknown type)"); + } + return buffer; + }; + + /** + * Decode one element value from the specified buffer. + * @param {ByteBuffer} buffer ByteBuffer to decode from + * @param {number} wireType The field wire type + * @param {number} id The field number + * @return {*} Decoded value + * @throws {Error} If the field cannot be decoded + * @expose + */ + ElementPrototype.decode = function(buffer, wireType, id) { + if (wireType != this.type.wireType) + throw Error("Unexpected wire type for element"); + + var value, nBytes; + switch (this.type) { + // 32bit signed varint + case ProtoBuf.TYPES["int32"]: + return buffer.readVarint32() | 0; + + // 32bit unsigned varint + case ProtoBuf.TYPES["uint32"]: + return buffer.readVarint32() >>> 0; + + // 32bit signed varint zig-zag + case ProtoBuf.TYPES["sint32"]: + return buffer.readVarint32ZigZag() | 0; + + // Fixed 32bit unsigned + case ProtoBuf.TYPES["fixed32"]: + return buffer.readUint32() >>> 0; + + case ProtoBuf.TYPES["sfixed32"]: + return buffer.readInt32() | 0; + + // 64bit signed varint + case ProtoBuf.TYPES["int64"]: + return buffer.readVarint64(); + + // 64bit unsigned varint + case ProtoBuf.TYPES["uint64"]: + return buffer.readVarint64().toUnsigned(); + + // 64bit signed varint zig-zag + case ProtoBuf.TYPES["sint64"]: + return buffer.readVarint64ZigZag(); + + // Fixed 64bit unsigned + case ProtoBuf.TYPES["fixed64"]: + return buffer.readUint64(); + + // Fixed 64bit signed + case ProtoBuf.TYPES["sfixed64"]: + return buffer.readInt64(); + + // Bool varint + case ProtoBuf.TYPES["bool"]: + return !!buffer.readVarint32(); + + // Constant enum value (varint) + case ProtoBuf.TYPES["enum"]: + // The following Builder.Message#set will already throw + return buffer.readVarint32(); + + // 32bit float + case ProtoBuf.TYPES["float"]: + return buffer.readFloat(); + + // 64bit float + case ProtoBuf.TYPES["double"]: + return buffer.readDouble(); + + // Length-delimited string + case ProtoBuf.TYPES["string"]: + return buffer.readVString(); + + // Length-delimited bytes + case ProtoBuf.TYPES["bytes"]: { + nBytes = buffer.readVarint32(); + if (buffer.remaining() < nBytes) + throw Error("Illegal number of bytes for "+this.toString(true)+": "+nBytes+" required but got only "+buffer.remaining()); + value = buffer.clone(); // Offset already set + value.limit = value.offset+nBytes; + buffer.offset += nBytes; + return value; + } + + // Length-delimited embedded message + case ProtoBuf.TYPES["message"]: { + nBytes = buffer.readVarint32(); + return this.resolvedType.decode(buffer, nBytes); + } + + // Legacy group + case ProtoBuf.TYPES["group"]: + return this.resolvedType.decode(buffer, -1, id); + } + + // We should never end here + throw Error("[INTERNAL] Illegal decode type"); + }; + + /** + * Converts a value from a string to the canonical element type. + * + * Legal only when isMapKey is true. + * + * @param {string} str The string value + * @returns {*} The value + */ + ElementPrototype.valueFromString = function(str) { + if (!this.isMapKey) { + throw Error("valueFromString() called on non-map-key element"); + } + + switch (this.type) { + case ProtoBuf.TYPES["int32"]: + case ProtoBuf.TYPES["sint32"]: + case ProtoBuf.TYPES["sfixed32"]: + case ProtoBuf.TYPES["uint32"]: + case ProtoBuf.TYPES["fixed32"]: + return this.verifyValue(parseInt(str)); + + case ProtoBuf.TYPES["int64"]: + case ProtoBuf.TYPES["sint64"]: + case ProtoBuf.TYPES["sfixed64"]: + case ProtoBuf.TYPES["uint64"]: + case ProtoBuf.TYPES["fixed64"]: + // Long-based fields support conversions from string already. + return this.verifyValue(str); + + case ProtoBuf.TYPES["bool"]: + return str === "true"; + + case ProtoBuf.TYPES["string"]: + return this.verifyValue(str); + + case ProtoBuf.TYPES["bytes"]: + return ByteBuffer.fromBinary(str); + } + }; + + /** + * Converts a value from the canonical element type to a string. + * + * It should be the case that `valueFromString(valueToString(val))` returns + * a value equivalent to `verifyValue(val)` for every legal value of `val` + * according to this element type. + * + * This may be used when the element must be stored or used as a string, + * e.g., as a map key on an Object. + * + * Legal only when isMapKey is true. + * + * @param {*} val The value + * @returns {string} The string form of the value. + */ + ElementPrototype.valueToString = function(value) { + if (!this.isMapKey) { + throw Error("valueToString() called on non-map-key element"); + } + + if (this.type === ProtoBuf.TYPES["bytes"]) { + return value.toString("binary"); + } else { + return value.toString(); + } + }; + + /** + * @alias ProtoBuf.Reflect.Element + * @expose + */ + Reflect.Element = Element; + + /** + * Constructs a new Message. + * @exports ProtoBuf.Reflect.Message + * @param {!ProtoBuf.Builder} builder Builder reference + * @param {!ProtoBuf.Reflect.Namespace} parent Parent message or namespace + * @param {string} name Message name + * @param {Object.=} options Message options + * @param {boolean=} isGroup `true` if this is a legacy group + * @param {string?} syntax The syntax level of this definition (e.g., proto3) + * @constructor + * @extends ProtoBuf.Reflect.Namespace + */ + var Message = function(builder, parent, name, options, isGroup, syntax) { + Namespace.call(this, builder, parent, name, options, syntax); + + /** + * @override + */ + this.className = "Message"; + + /** + * Extensions range. + * @type {!Array.|undefined} + * @expose + */ + this.extensions = undefined; + + /** + * Runtime message class. + * @type {?function(new:ProtoBuf.Builder.Message)} + * @expose + */ + this.clazz = null; + + /** + * Whether this is a legacy group or not. + * @type {boolean} + * @expose + */ + this.isGroup = !!isGroup; + + // The following cached collections are used to efficiently iterate over or look up fields when decoding. + + /** + * Cached fields. + * @type {?Array.} + * @private + */ + this._fields = null; + + /** + * Cached fields by id. + * @type {?Object.} + * @private + */ + this._fieldsById = null; + + /** + * Cached fields by name. + * @type {?Object.} + * @private + */ + this._fieldsByName = null; + }; + + /** + * @alias ProtoBuf.Reflect.Message.prototype + * @inner + */ + var MessagePrototype = Message.prototype = Object.create(Namespace.prototype); + + /** + * Builds the message and returns the runtime counterpart, which is a fully functional class. + * @see ProtoBuf.Builder.Message + * @param {boolean=} rebuild Whether to rebuild or not, defaults to false + * @return {ProtoBuf.Reflect.Message} Message class + * @throws {Error} If the message cannot be built + * @expose + */ + MessagePrototype.build = function(rebuild) { + if (this.clazz && !rebuild) + return this.clazz; + + // Create the runtime Message class in its own scope + var clazz = (function(ProtoBuf, T) { + + var fields = T.getChildren(ProtoBuf.Reflect.Message.Field), + oneofs = T.getChildren(ProtoBuf.Reflect.Message.OneOf); + + /** + * Constructs a new runtime Message. + * @name ProtoBuf.Builder.Message + * @class Barebone of all runtime messages. + * @param {!Object.|string} values Preset values + * @param {...string} var_args + * @constructor + * @throws {Error} If the message cannot be created + */ + var Message = function(values, var_args) { + ProtoBuf.Builder.Message.call(this); + + // Create virtual oneof properties + for (var i=0, k=oneofs.length; i 0) { + var value; + // Set field values from a values object + if (arguments.length === 1 && values !== null && typeof values === 'object' && + /* not _another_ Message */ (typeof values.encode !== 'function' || values instanceof Message) && + /* not a repeated field */ !Array.isArray(values) && + /* not a Map */ !(values instanceof ProtoBuf.Map) && + /* not a ByteBuffer */ !ByteBuffer.isByteBuffer(values) && + /* not an ArrayBuffer */ !(values instanceof ArrayBuffer) && + /* not a Long */ !(ProtoBuf.Long && values instanceof ProtoBuf.Long)) { + this.$set(values); + } else // Set field values from arguments, in declaration order + for (i=0, k=arguments.length; i} keyOrObj String key or plain object holding multiple values + * @param {(*|boolean)=} value Value to set if key is a string, otherwise omitted + * @param {boolean=} noAssert Whether to not assert for an actual field / proper value type, defaults to `false` + * @returns {!ProtoBuf.Builder.Message} this + * @throws {Error} If the value cannot be set + * @expose + */ + MessagePrototype.set = function(keyOrObj, value, noAssert) { + if (keyOrObj && typeof keyOrObj === 'object') { + noAssert = value; + for (var ikey in keyOrObj) + if (keyOrObj.hasOwnProperty(ikey) && typeof (value = keyOrObj[ikey]) !== 'undefined') + this.$set(ikey, value, noAssert); + return this; + } + var field = T._fieldsByName[keyOrObj]; + if (!noAssert) { + if (!field) + throw Error(this+"#"+keyOrObj+" is not a field: undefined"); + if (!(field instanceof ProtoBuf.Reflect.Message.Field)) + throw Error(this+"#"+keyOrObj+" is not a field: "+field.toString(true)); + this[field.name] = (value = field.verifyValue(value)); // May throw + } else + this[keyOrObj] = value; + if (field && field.oneof) { // Field is part of an OneOf (not a virtual OneOf field) + var currentField = this[field.oneof.name]; // Virtual field references currently set field + if (value !== null) { + if (currentField !== null && currentField !== field.name) + this[currentField] = null; // Clear currently set field + this[field.oneof.name] = field.name; // Point virtual field at this field + } else if (/* value === null && */currentField === keyOrObj) + this[field.oneof.name] = null; // Clear virtual field (current field explicitly cleared) + } + return this; + }; + + /** + * Sets a field's value. This is an alias for [@link ProtoBuf.Builder.Message#set}. + * @name ProtoBuf.Builder.Message#$set + * @function + * @param {string|!Object.} keyOrObj String key or plain object holding multiple values + * @param {(*|boolean)=} value Value to set if key is a string, otherwise omitted + * @param {boolean=} noAssert Whether to not assert the value, defaults to `false` + * @throws {Error} If the value cannot be set + * @expose + */ + MessagePrototype.$set = MessagePrototype.set; + + /** + * Gets a field's value. + * @name ProtoBuf.Builder.Message#get + * @function + * @param {string} key Key + * @param {boolean=} noAssert Whether to not assert for an actual field, defaults to `false` + * @return {*} Value + * @throws {Error} If there is no such field + * @expose + */ + MessagePrototype.get = function(key, noAssert) { + if (noAssert) + return this[key]; + var field = T._fieldsByName[key]; + if (!field || !(field instanceof ProtoBuf.Reflect.Message.Field)) + throw Error(this+"#"+key+" is not a field: undefined"); + if (!(field instanceof ProtoBuf.Reflect.Message.Field)) + throw Error(this+"#"+key+" is not a field: "+field.toString(true)); + return this[field.name]; + }; + + /** + * Gets a field's value. This is an alias for {@link ProtoBuf.Builder.Message#$get}. + * @name ProtoBuf.Builder.Message#$get + * @function + * @param {string} key Key + * @return {*} Value + * @throws {Error} If there is no such field + * @expose + */ + MessagePrototype.$get = MessagePrototype.get; + + // Getters and setters + + for (var i=0; i} data Data payload + * @param {(!ByteBuffer|boolean)=} buffer ByteBuffer to encode to. Will create a new one and flip it if omitted. + * @param {boolean=} noVerify Whether to not verify field values, defaults to `false` + * @return {!ByteBuffer} Encoded message as a ByteBuffer + * @expose + */ + Message.encode = function(data, buffer, noVerify) { + return new Message(data).encode(buffer, noVerify); + }; + + /** + * Calculates the byte length of the message. + * @name ProtoBuf.Builder.Message#calculate + * @function + * @returns {number} Byte length + * @throws {Error} If the message cannot be calculated or if required fields are missing. + * @expose + */ + MessagePrototype.calculate = function() { + return T.calculate(this); + }; + + /** + * Encodes the varint32 length-delimited message. + * @name ProtoBuf.Builder.Message#encodeDelimited + * @function + * @param {(!ByteBuffer|boolean)=} buffer ByteBuffer to encode to. Will create a new one and flip it if omitted. + * @param {boolean=} noVerify Whether to not verify field values, defaults to `false` + * @return {!ByteBuffer} Encoded message as a ByteBuffer + * @throws {Error} If the message cannot be encoded or if required fields are missing. The later still + * returns the encoded ByteBuffer in the `encoded` property on the error. + * @expose + */ + MessagePrototype.encodeDelimited = function(buffer, noVerify) { + var isNew = false; + if (!buffer) + buffer = new ByteBuffer(), + isNew = true; + var enc = new ByteBuffer().LE(); + T.encode(this, enc, noVerify).flip(); + buffer.writeVarint32(enc.remaining()); + buffer.append(enc); + return isNew ? buffer.flip() : buffer; + }; + + /** + * Directly encodes the message to an ArrayBuffer. + * @name ProtoBuf.Builder.Message#encodeAB + * @function + * @return {ArrayBuffer} Encoded message as ArrayBuffer + * @throws {Error} If the message cannot be encoded or if required fields are missing. The later still + * returns the encoded ArrayBuffer in the `encoded` property on the error. + * @expose + */ + MessagePrototype.encodeAB = function() { + try { + return this.encode().toArrayBuffer(); + } catch (e) { + if (e["encoded"]) e["encoded"] = e["encoded"].toArrayBuffer(); + throw(e); + } + }; + + /** + * Returns the message as an ArrayBuffer. This is an alias for {@link ProtoBuf.Builder.Message#encodeAB}. + * @name ProtoBuf.Builder.Message#toArrayBuffer + * @function + * @return {ArrayBuffer} Encoded message as ArrayBuffer + * @throws {Error} If the message cannot be encoded or if required fields are missing. The later still + * returns the encoded ArrayBuffer in the `encoded` property on the error. + * @expose + */ + MessagePrototype.toArrayBuffer = MessagePrototype.encodeAB; + + /** + * Directly encodes the message to a node Buffer. + * @name ProtoBuf.Builder.Message#encodeNB + * @function + * @return {!Buffer} + * @throws {Error} If the message cannot be encoded, not running under node.js or if required fields are + * missing. The later still returns the encoded node Buffer in the `encoded` property on the error. + * @expose + */ + MessagePrototype.encodeNB = function() { + try { + return this.encode().toBuffer(); + } catch (e) { + if (e["encoded"]) e["encoded"] = e["encoded"].toBuffer(); + throw(e); + } + }; + + /** + * Returns the message as a node Buffer. This is an alias for {@link ProtoBuf.Builder.Message#encodeNB}. + * @name ProtoBuf.Builder.Message#toBuffer + * @function + * @return {!Buffer} + * @throws {Error} If the message cannot be encoded or if required fields are missing. The later still + * returns the encoded node Buffer in the `encoded` property on the error. + * @expose + */ + MessagePrototype.toBuffer = MessagePrototype.encodeNB; + + /** + * Directly encodes the message to a base64 encoded string. + * @name ProtoBuf.Builder.Message#encode64 + * @function + * @return {string} Base64 encoded string + * @throws {Error} If the underlying buffer cannot be encoded or if required fields are missing. The later + * still returns the encoded base64 string in the `encoded` property on the error. + * @expose + */ + MessagePrototype.encode64 = function() { + try { + return this.encode().toBase64(); + } catch (e) { + if (e["encoded"]) e["encoded"] = e["encoded"].toBase64(); + throw(e); + } + }; + + /** + * Returns the message as a base64 encoded string. This is an alias for {@link ProtoBuf.Builder.Message#encode64}. + * @name ProtoBuf.Builder.Message#toBase64 + * @function + * @return {string} Base64 encoded string + * @throws {Error} If the message cannot be encoded or if required fields are missing. The later still + * returns the encoded base64 string in the `encoded` property on the error. + * @expose + */ + MessagePrototype.toBase64 = MessagePrototype.encode64; + + /** + * Directly encodes the message to a hex encoded string. + * @name ProtoBuf.Builder.Message#encodeHex + * @function + * @return {string} Hex encoded string + * @throws {Error} If the underlying buffer cannot be encoded or if required fields are missing. The later + * still returns the encoded hex string in the `encoded` property on the error. + * @expose + */ + MessagePrototype.encodeHex = function() { + try { + return this.encode().toHex(); + } catch (e) { + if (e["encoded"]) e["encoded"] = e["encoded"].toHex(); + throw(e); + } + }; + + /** + * Returns the message as a hex encoded string. This is an alias for {@link ProtoBuf.Builder.Message#encodeHex}. + * @name ProtoBuf.Builder.Message#toHex + * @function + * @return {string} Hex encoded string + * @throws {Error} If the message cannot be encoded or if required fields are missing. The later still + * returns the encoded hex string in the `encoded` property on the error. + * @expose + */ + MessagePrototype.toHex = MessagePrototype.encodeHex; + + /** + * Clones a message object or field value to a raw object. + * @param {*} obj Object to clone + * @param {boolean} binaryAsBase64 Whether to include binary data as base64 strings or as a buffer otherwise + * @param {boolean} longsAsStrings Whether to encode longs as strings + * @param {!ProtoBuf.Reflect.T=} resolvedType The resolved field type if a field + * @returns {*} Cloned object + * @inner + */ + function cloneRaw(obj, binaryAsBase64, longsAsStrings, resolvedType) { + if (obj === null || typeof obj !== 'object') { + // Convert enum values to their respective names + if (resolvedType && resolvedType instanceof ProtoBuf.Reflect.Enum) { + var name = ProtoBuf.Reflect.Enum.getName(resolvedType.object, obj); + if (name !== null) + return name; + } + // Pass-through string, number, boolean, null... + return obj; + } + // Convert ByteBuffers to raw buffer or strings + if (ByteBuffer.isByteBuffer(obj)) + return binaryAsBase64 ? obj.toBase64() : obj.toBuffer(); + // Convert Longs to proper objects or strings + if (ProtoBuf.Long.isLong(obj)) + return longsAsStrings ? obj.toString() : ProtoBuf.Long.fromValue(obj); + var clone; + // Clone arrays + if (Array.isArray(obj)) { + clone = []; + obj.forEach(function(v, k) { + clone[k] = cloneRaw(v, binaryAsBase64, longsAsStrings, resolvedType); + }); + return clone; + } + clone = {}; + // Convert maps to objects + if (obj instanceof ProtoBuf.Map) { + var it = obj.entries(); + for (var e = it.next(); !e.done; e = it.next()) + clone[obj.keyElem.valueToString(e.value[0])] = cloneRaw(e.value[1], binaryAsBase64, longsAsStrings, obj.valueElem.resolvedType); + return clone; + } + // Everything else is a non-null object + var type = obj.$type, + field = undefined; + for (var i in obj) + if (obj.hasOwnProperty(i)) { + if (type && (field = type.getChild(i))) + clone[i] = cloneRaw(obj[i], binaryAsBase64, longsAsStrings, field.resolvedType); + else + clone[i] = cloneRaw(obj[i], binaryAsBase64, longsAsStrings); + } + return clone; + } + + /** + * Returns the message's raw payload. + * @param {boolean=} binaryAsBase64 Whether to include binary data as base64 strings instead of Buffers, defaults to `false` + * @param {boolean} longsAsStrings Whether to encode longs as strings + * @returns {Object.} Raw payload + * @expose + */ + MessagePrototype.toRaw = function(binaryAsBase64, longsAsStrings) { + return cloneRaw(this, !!binaryAsBase64, !!longsAsStrings, this.$type); + }; + + /** + * Encodes a message to JSON. + * @returns {string} JSON string + * @expose + */ + MessagePrototype.encodeJSON = function() { + return JSON.stringify( + cloneRaw(this, + /* binary-as-base64 */ true, + /* longs-as-strings */ true, + this.$type + ) + ); + }; + + /** + * Decodes a message from the specified buffer or string. + * @name ProtoBuf.Builder.Message.decode + * @function + * @param {!ByteBuffer|!ArrayBuffer|!Buffer|string} buffer Buffer to decode from + * @param {(number|string)=} length Message length. Defaults to decode all the remainig data. + * @param {string=} enc Encoding if buffer is a string: hex, utf8 (not recommended), defaults to base64 + * @return {!ProtoBuf.Builder.Message} Decoded message + * @throws {Error} If the message cannot be decoded or if required fields are missing. The later still + * returns the decoded message with missing fields in the `decoded` property on the error. + * @expose + * @see ProtoBuf.Builder.Message.decode64 + * @see ProtoBuf.Builder.Message.decodeHex + */ + Message.decode = function(buffer, length, enc) { + if (typeof length === 'string') + enc = length, + length = -1; + if (typeof buffer === 'string') + buffer = ByteBuffer.wrap(buffer, enc ? enc : "base64"); + buffer = ByteBuffer.isByteBuffer(buffer) ? buffer : ByteBuffer.wrap(buffer); // May throw + var le = buffer.littleEndian; + try { + var msg = T.decode(buffer.LE()); + buffer.LE(le); + return msg; + } catch (e) { + buffer.LE(le); + throw(e); + } + }; + + /** + * Decodes a varint32 length-delimited message from the specified buffer or string. + * @name ProtoBuf.Builder.Message.decodeDelimited + * @function + * @param {!ByteBuffer|!ArrayBuffer|!Buffer|string} buffer Buffer to decode from + * @param {string=} enc Encoding if buffer is a string: hex, utf8 (not recommended), defaults to base64 + * @return {ProtoBuf.Builder.Message} Decoded message or `null` if not enough bytes are available yet + * @throws {Error} If the message cannot be decoded or if required fields are missing. The later still + * returns the decoded message with missing fields in the `decoded` property on the error. + * @expose + */ + Message.decodeDelimited = function(buffer, enc) { + if (typeof buffer === 'string') + buffer = ByteBuffer.wrap(buffer, enc ? enc : "base64"); + buffer = ByteBuffer.isByteBuffer(buffer) ? buffer : ByteBuffer.wrap(buffer); // May throw + if (buffer.remaining() < 1) + return null; + var off = buffer.offset, + len = buffer.readVarint32(); + if (buffer.remaining() < len) { + buffer.offset = off; + return null; + } + try { + var msg = T.decode(buffer.slice(buffer.offset, buffer.offset + len).LE()); + buffer.offset += len; + return msg; + } catch (err) { + buffer.offset += len; + throw err; + } + }; + + /** + * Decodes the message from the specified base64 encoded string. + * @name ProtoBuf.Builder.Message.decode64 + * @function + * @param {string} str String to decode from + * @return {!ProtoBuf.Builder.Message} Decoded message + * @throws {Error} If the message cannot be decoded or if required fields are missing. The later still + * returns the decoded message with missing fields in the `decoded` property on the error. + * @expose + */ + Message.decode64 = function(str) { + return Message.decode(str, "base64"); + }; + + /** + * Decodes the message from the specified hex encoded string. + * @name ProtoBuf.Builder.Message.decodeHex + * @function + * @param {string} str String to decode from + * @return {!ProtoBuf.Builder.Message} Decoded message + * @throws {Error} If the message cannot be decoded or if required fields are missing. The later still + * returns the decoded message with missing fields in the `decoded` property on the error. + * @expose + */ + Message.decodeHex = function(str) { + return Message.decode(str, "hex"); + }; + + /** + * Decodes the message from a JSON string. + * @name ProtoBuf.Builder.Message.decodeJSON + * @function + * @param {string} str String to decode from + * @return {!ProtoBuf.Builder.Message} Decoded message + * @throws {Error} If the message cannot be decoded or if required fields are + * missing. + * @expose + */ + Message.decodeJSON = function(str) { + return new Message(JSON.parse(str)); + }; + + // Utility + + /** + * Returns a string representation of this Message. + * @name ProtoBuf.Builder.Message#toString + * @function + * @return {string} String representation as of ".Fully.Qualified.MessageName" + * @expose + */ + MessagePrototype.toString = function() { + return T.toString(); + }; + + // Properties + + /** + * Message options. + * @name ProtoBuf.Builder.Message.$options + * @type {Object.} + * @expose + */ + var $optionsS; // cc needs this + + /** + * Message options. + * @name ProtoBuf.Builder.Message#$options + * @type {Object.} + * @expose + */ + var $options; + + /** + * Reflection type. + * @name ProtoBuf.Builder.Message.$type + * @type {!ProtoBuf.Reflect.Message} + * @expose + */ + var $typeS; + + /** + * Reflection type. + * @name ProtoBuf.Builder.Message#$type + * @type {!ProtoBuf.Reflect.Message} + * @expose + */ + var $type; + + if (Object.defineProperty) + Object.defineProperty(Message, '$options', { "value": T.buildOpt() }), + Object.defineProperty(MessagePrototype, "$options", { "value": Message["$options"] }), + Object.defineProperty(Message, "$type", { "value": T }), + Object.defineProperty(MessagePrototype, "$type", { "value": T }); + + return Message; + + })(ProtoBuf, this); + + // Static enums and prototyped sub-messages / cached collections + this._fields = []; + this._fieldsById = {}; + this._fieldsByName = {}; + for (var i=0, k=this.children.length, child; i>> 3; + switch (wireType) { + case ProtoBuf.WIRE_TYPES.VARINT: + do tag = buf.readUint8(); + while ((tag & 0x80) === 0x80); + break; + case ProtoBuf.WIRE_TYPES.BITS64: + buf.offset += 8; + break; + case ProtoBuf.WIRE_TYPES.LDELIM: + tag = buf.readVarint32(); // reads the varint + buf.offset += tag; // skips n bytes + break; + case ProtoBuf.WIRE_TYPES.STARTGROUP: + skipTillGroupEnd(id, buf); + break; + case ProtoBuf.WIRE_TYPES.ENDGROUP: + if (id === expectedId) + return false; + else + throw Error("Illegal GROUPEND after unknown group: "+id+" ("+expectedId+" expected)"); + case ProtoBuf.WIRE_TYPES.BITS32: + buf.offset += 4; + break; + default: + throw Error("Illegal wire type in unknown group "+expectedId+": "+wireType); + } + return true; + } + + /** + * Decodes an encoded message and returns the decoded message. + * @param {ByteBuffer} buffer ByteBuffer to decode from + * @param {number=} length Message length. Defaults to decode all remaining data. + * @param {number=} expectedGroupEndId Expected GROUPEND id if this is a legacy group + * @return {ProtoBuf.Builder.Message} Decoded message + * @throws {Error} If the message cannot be decoded + * @expose + */ + MessagePrototype.decode = function(buffer, length, expectedGroupEndId) { + length = typeof length === 'number' ? length : -1; + var start = buffer.offset, + msg = new (this.clazz)(), + tag, wireType, id, field; + while (buffer.offset < start+length || (length === -1 && buffer.remaining() > 0)) { + tag = buffer.readVarint32(); + wireType = tag & 0x07; + id = tag >>> 3; + if (wireType === ProtoBuf.WIRE_TYPES.ENDGROUP) { + if (id !== expectedGroupEndId) + throw Error("Illegal group end indicator for "+this.toString(true)+": "+id+" ("+(expectedGroupEndId ? expectedGroupEndId+" expected" : "not a group")+")"); + break; + } + if (!(field = this._fieldsById[id])) { + // "messages created by your new code can be parsed by your old code: old binaries simply ignore the new field when parsing." + switch (wireType) { + case ProtoBuf.WIRE_TYPES.VARINT: + buffer.readVarint32(); + break; + case ProtoBuf.WIRE_TYPES.BITS32: + buffer.offset += 4; + break; + case ProtoBuf.WIRE_TYPES.BITS64: + buffer.offset += 8; + break; + case ProtoBuf.WIRE_TYPES.LDELIM: + var len = buffer.readVarint32(); + buffer.offset += len; + break; + case ProtoBuf.WIRE_TYPES.STARTGROUP: + while (skipTillGroupEnd(id, buffer)) {} + break; + default: + throw Error("Illegal wire type for unknown field "+id+" in "+this.toString(true)+"#decode: "+wireType); + } + continue; + } + if (field.repeated && !field.options["packed"]) { + msg[field.name].push(field.decode(wireType, buffer)); + } else if (field.map) { + var keyval = field.decode(wireType, buffer); + msg[field.name].set(keyval[0], keyval[1]); + } else { + msg[field.name] = field.decode(wireType, buffer); + if (field.oneof) { // Field is part of an OneOf (not a virtual OneOf field) + var currentField = msg[field.oneof.name]; // Virtual field references currently set field + if (currentField !== null && currentField !== field.name) + msg[currentField] = null; // Clear currently set field + msg[field.oneof.name] = field.name; // Point virtual field at this field + } + } + } + + // Check if all required fields are present and set default values for optional fields that are not + for (var i=0, k=this._fields.length; i=} options Options + * @param {!ProtoBuf.Reflect.Message.OneOf=} oneof Enclosing OneOf + * @param {string?} syntax The syntax level of this definition (e.g., proto3) + * @constructor + * @extends ProtoBuf.Reflect.T + */ + var Field = function(builder, message, rule, keytype, type, name, id, options, oneof, syntax) { + T.call(this, builder, message, name); + + /** + * @override + */ + this.className = "Message.Field"; + + /** + * Message field required flag. + * @type {boolean} + * @expose + */ + this.required = rule === "required"; + + /** + * Message field repeated flag. + * @type {boolean} + * @expose + */ + this.repeated = rule === "repeated"; + + /** + * Message field map flag. + * @type {boolean} + * @expose + */ + this.map = rule === "map"; + + /** + * Message field key type. Type reference string if unresolved, protobuf + * type if resolved. Valid only if this.map === true, null otherwise. + * @type {string|{name: string, wireType: number}|null} + * @expose + */ + this.keyType = keytype || null; + + /** + * Message field type. Type reference string if unresolved, protobuf type if + * resolved. In a map field, this is the value type. + * @type {string|{name: string, wireType: number}} + * @expose + */ + this.type = type; + + /** + * Resolved type reference inside the global namespace. + * @type {ProtoBuf.Reflect.T|null} + * @expose + */ + this.resolvedType = null; + + /** + * Unique message field id. + * @type {number} + * @expose + */ + this.id = id; + + /** + * Message field options. + * @type {!Object.} + * @dict + * @expose + */ + this.options = options || {}; + + /** + * Default value. + * @type {*} + * @expose + */ + this.defaultValue = null; + + /** + * Enclosing OneOf. + * @type {?ProtoBuf.Reflect.Message.OneOf} + * @expose + */ + this.oneof = oneof || null; + + /** + * Syntax level of this definition (e.g., proto3). + * @type {string} + * @expose + */ + this.syntax = syntax || 'proto2'; + + /** + * Original field name. + * @type {string} + * @expose + */ + this.originalName = this.name; // Used to revert camelcase transformation on naming collisions + + /** + * Element implementation. Created in build() after types are resolved. + * @type {ProtoBuf.Element} + * @expose + */ + this.element = null; + + /** + * Key element implementation, for map fields. Created in build() after + * types are resolved. + * @type {ProtoBuf.Element} + * @expose + */ + this.keyElement = null; + + // Convert field names to camel case notation if the override is set + if (this.builder.options['convertFieldsToCamelCase'] && !(this instanceof Message.ExtensionField)) + this.name = ProtoBuf.Util.toCamelCase(this.name); + }; + + /** + * @alias ProtoBuf.Reflect.Message.Field.prototype + * @inner + */ + var FieldPrototype = Field.prototype = Object.create(T.prototype); + + /** + * Builds the field. + * @override + * @expose + */ + FieldPrototype.build = function() { + this.element = new Element(this.type, this.resolvedType, false, this.syntax); + if (this.map) + this.keyElement = new Element(this.keyType, undefined, true, this.syntax); + + // In proto3, fields do not have field presence, and every field is set to + // its type's default value ("", 0, 0.0, or false). + if (this.syntax === 'proto3' && !this.repeated && !this.map) + this.defaultValue = Element.defaultFieldValue(this.type); + + // Otherwise, default values are present when explicitly specified + else if (typeof this.options['default'] !== 'undefined') + this.defaultValue = this.verifyValue(this.options['default']); + }; + + /** + * Checks if the given value can be set for this field. + * @param {*} value Value to check + * @param {boolean=} skipRepeated Whether to skip the repeated value check or not. Defaults to false. + * @return {*} Verified, maybe adjusted, value + * @throws {Error} If the value cannot be set for this field + * @expose + */ + FieldPrototype.verifyValue = function(value, skipRepeated) { + skipRepeated = skipRepeated || false; + var self = this; + function fail(val, msg) { + throw Error("Illegal value for "+self.toString(true)+" of type "+self.type.name+": "+val+" ("+msg+")"); + } + if (value === null) { // NULL values for optional fields + if (this.required) + fail(typeof value, "required"); + if (this.syntax === 'proto3' && this.type !== ProtoBuf.TYPES["message"]) + fail(typeof value, "proto3 field without field presence cannot be null"); + return null; + } + var i; + if (this.repeated && !skipRepeated) { // Repeated values as arrays + if (!Array.isArray(value)) + value = [value]; + var res = []; + for (i=0; i 0; + + case ProtoBuf.TYPES["bytes"]: + return value.remaining() > 0; + + case ProtoBuf.TYPES["enum"]: + return value !== 0; + + case ProtoBuf.TYPES["message"]: + return value !== null; + default: + return true; + } + }; + + /** + * Encodes the specified field value to the specified buffer. + * @param {*} value Verified field value + * @param {ByteBuffer} buffer ByteBuffer to encode to + * @param {!ProtoBuf.Builder.Message} message Runtime message + * @return {ByteBuffer} The ByteBuffer for chaining + * @throws {Error} If the field cannot be encoded + * @expose + */ + FieldPrototype.encode = function(value, buffer, message) { + if (this.type === null || typeof this.type !== 'object') + throw Error("[INTERNAL] Unresolved type in "+this.toString(true)+": "+this.type); + if (value === null || (this.repeated && value.length == 0)) + return buffer; // Optional omitted + try { + if (this.repeated) { + var i; + // "Only repeated fields of primitive numeric types (types which use the varint, 32-bit, or 64-bit wire + // types) can be declared 'packed'." + if (this.options["packed"] && ProtoBuf.PACKABLE_WIRE_TYPES.indexOf(this.type.wireType) >= 0) { + // "All of the elements of the field are packed into a single key-value pair with wire type 2 + // (length-delimited). Each element is encoded the same way it would be normally, except without a + // tag preceding it." + buffer.writeVarint32((this.id << 3) | ProtoBuf.WIRE_TYPES.LDELIM); + buffer.ensureCapacity(buffer.offset += 1); // We do not know the length yet, so let's assume a varint of length 1 + var start = buffer.offset; // Remember where the contents begin + for (i=0; i 1) { // We need to move the contents + var contents = buffer.slice(start, buffer.offset); + start += varintLen-1; + buffer.offset = start; + buffer.append(contents); + } + buffer.writeVarint32(len, start-varintLen); + } else { + // "If your message definition has repeated elements (without the [packed=true] option), the encoded + // message has zero or more key-value pairs with the same tag number" + for (i=0; i= 0) { + n += ByteBuffer.calculateVarint32((this.id << 3) | ProtoBuf.WIRE_TYPES.LDELIM); + ni = 0; + for (i=0; i= 0) { + if (!skipRepeated) { + nBytes = buffer.readVarint32(); + nBytes = buffer.offset + nBytes; // Limit + var values = []; + while (buffer.offset < nBytes) + values.push(this.decode(this.type.wireType, buffer, true)); + return values; + } + // Read the next value otherwise... + } + + // Handle maps. + if (this.map) { + // Read one (key, value) submessage, and return [key, value] + var key = Element.defaultFieldValue(this.keyType); + value = Element.defaultFieldValue(this.type); + + // Read the length + nBytes = buffer.readVarint32(); + if (buffer.remaining() < nBytes) + throw Error("Illegal number of bytes for "+this.toString(true)+": "+nBytes+" required but got only "+buffer.remaining()); + + // Get a sub-buffer of this key/value submessage + var msgbuf = buffer.clone(); + msgbuf.limit = msgbuf.offset + nBytes; + buffer.offset += nBytes; + + while (msgbuf.remaining() > 0) { + var tag = msgbuf.readVarint32(); + wireType = tag & 0x07; + var id = tag >>> 3; + if (id === 1) { + key = this.keyElement.decode(msgbuf, wireType, id); + } else if (id === 2) { + value = this.element.decode(msgbuf, wireType, id); + } else { + throw Error("Unexpected tag in map field key/value submessage"); + } + } + + return [key, value]; + } + + // Handle singular and non-packed repeated field values. + return this.element.decode(buffer, wireType, this.id); + }; + + /** + * @alias ProtoBuf.Reflect.Message.Field + * @expose + */ + Reflect.Message.Field = Field; + + /** + * Constructs a new Message ExtensionField. + * @exports ProtoBuf.Reflect.Message.ExtensionField + * @param {!ProtoBuf.Builder} builder Builder reference + * @param {!ProtoBuf.Reflect.Message} message Message reference + * @param {string} rule Rule, one of requried, optional, repeated + * @param {string} type Data type, e.g. int32 + * @param {string} name Field name + * @param {number} id Unique field id + * @param {!Object.=} options Options + * @constructor + * @extends ProtoBuf.Reflect.Message.Field + */ + var ExtensionField = function(builder, message, rule, type, name, id, options) { + Field.call(this, builder, message, rule, /* keytype = */ null, type, name, id, options); + + /** + * Extension reference. + * @type {!ProtoBuf.Reflect.Extension} + * @expose + */ + this.extension; + }; + + // Extends Field + ExtensionField.prototype = Object.create(Field.prototype); + + /** + * @alias ProtoBuf.Reflect.Message.ExtensionField + * @expose + */ + Reflect.Message.ExtensionField = ExtensionField; + + /** + * Constructs a new Message OneOf. + * @exports ProtoBuf.Reflect.Message.OneOf + * @param {!ProtoBuf.Builder} builder Builder reference + * @param {!ProtoBuf.Reflect.Message} message Message reference + * @param {string} name OneOf name + * @constructor + * @extends ProtoBuf.Reflect.T + */ + var OneOf = function(builder, message, name) { + T.call(this, builder, message, name); + + /** + * Enclosed fields. + * @type {!Array.} + * @expose + */ + this.fields = []; + }; + + /** + * @alias ProtoBuf.Reflect.Message.OneOf + * @expose + */ + Reflect.Message.OneOf = OneOf; + + /** + * Constructs a new Enum. + * @exports ProtoBuf.Reflect.Enum + * @param {!ProtoBuf.Builder} builder Builder reference + * @param {!ProtoBuf.Reflect.T} parent Parent Reflect object + * @param {string} name Enum name + * @param {Object.=} options Enum options + * @param {string?} syntax The syntax level (e.g., proto3) + * @constructor + * @extends ProtoBuf.Reflect.Namespace + */ + var Enum = function(builder, parent, name, options, syntax) { + Namespace.call(this, builder, parent, name, options, syntax); + + /** + * @override + */ + this.className = "Enum"; + + /** + * Runtime enum object. + * @type {Object.|null} + * @expose + */ + this.object = null; + }; + + /** + * Gets the string name of an enum value. + * @param {!ProtoBuf.Builder.Enum} enm Runtime enum + * @param {number} value Enum value + * @returns {?string} Name or `null` if not present + * @expose + */ + Enum.getName = function(enm, value) { + var keys = Object.keys(enm); + for (var i=0, key; i} + * @expose + */ + EnumPrototype.build = function(rebuild) { + if (this.object && !rebuild) + return this.object; + var enm = new ProtoBuf.Builder.Enum(), + values = this.getChildren(Enum.Value); + for (var i=0, k=values.length; i=} options Options + * @constructor + * @extends ProtoBuf.Reflect.Namespace + */ + var Service = function(builder, root, name, options) { + Namespace.call(this, builder, root, name, options); + + /** + * @override + */ + this.className = "Service"; + + /** + * Built runtime service class. + * @type {?function(new:ProtoBuf.Builder.Service)} + */ + this.clazz = null; + }; + + /** + * @alias ProtoBuf.Reflect.Service.prototype + * @inner + */ + var ServicePrototype = Service.prototype = Object.create(Namespace.prototype); + + /** + * Builds the service and returns the runtime counterpart, which is a fully functional class. + * @see ProtoBuf.Builder.Service + * @param {boolean=} rebuild Whether to rebuild or not + * @return {Function} Service class + * @throws {Error} If the message cannot be built + * @expose + */ + ServicePrototype.build = function(rebuild) { + if (this.clazz && !rebuild) + return this.clazz; + + // Create the runtime Service class in its own scope + return this.clazz = (function(ProtoBuf, T) { + + /** + * Constructs a new runtime Service. + * @name ProtoBuf.Builder.Service + * @param {function(string, ProtoBuf.Builder.Message, function(Error, ProtoBuf.Builder.Message=))=} rpcImpl RPC implementation receiving the method name and the message + * @class Barebone of all runtime services. + * @constructor + * @throws {Error} If the service cannot be created + */ + var Service = function(rpcImpl) { + ProtoBuf.Builder.Service.call(this); + + /** + * Service implementation. + * @name ProtoBuf.Builder.Service#rpcImpl + * @type {!function(string, ProtoBuf.Builder.Message, function(Error, ProtoBuf.Builder.Message=))} + * @expose + */ + this.rpcImpl = rpcImpl || function(name, msg, callback) { + // This is what a user has to implement: A function receiving the method name, the actual message to + // send (type checked) and the callback that's either provided with the error as its first + // argument or null and the actual response message. + setTimeout(callback.bind(this, Error("Not implemented, see: https://github.com/dcodeIO/ProtoBuf.js/wiki/Services")), 0); // Must be async! + }; + }; + + /** + * @alias ProtoBuf.Builder.Service.prototype + * @inner + */ + var ServicePrototype = Service.prototype = Object.create(ProtoBuf.Builder.Service.prototype); + + /** + * Asynchronously performs an RPC call using the given RPC implementation. + * @name ProtoBuf.Builder.Service.[Method] + * @function + * @param {!function(string, ProtoBuf.Builder.Message, function(Error, ProtoBuf.Builder.Message=))} rpcImpl RPC implementation + * @param {ProtoBuf.Builder.Message} req Request + * @param {function(Error, (ProtoBuf.Builder.Message|ByteBuffer|Buffer|string)=)} callback Callback receiving + * the error if any and the response either as a pre-parsed message or as its raw bytes + * @abstract + */ + + /** + * Asynchronously performs an RPC call using the instance's RPC implementation. + * @name ProtoBuf.Builder.Service#[Method] + * @function + * @param {ProtoBuf.Builder.Message} req Request + * @param {function(Error, (ProtoBuf.Builder.Message|ByteBuffer|Buffer|string)=)} callback Callback receiving + * the error if any and the response either as a pre-parsed message or as its raw bytes + * @abstract + */ + + var rpc = T.getChildren(ProtoBuf.Reflect.Service.RPCMethod); + for (var i=0; i} + * @expose + */ + var $optionsS; // cc needs this + + /** + * Service options. + * @name ProtoBuf.Builder.Service#$options + * @type {Object.} + * @expose + */ + var $options; + + /** + * Reflection type. + * @name ProtoBuf.Builder.Service.$type + * @type {!ProtoBuf.Reflect.Service} + * @expose + */ + var $typeS; + + /** + * Reflection type. + * @name ProtoBuf.Builder.Service#$type + * @type {!ProtoBuf.Reflect.Service} + * @expose + */ + var $type; + + if (Object.defineProperty) + Object.defineProperty(Service, "$options", { "value": T.buildOpt() }), + Object.defineProperty(ServicePrototype, "$options", { "value": Service["$options"] }), + Object.defineProperty(Service, "$type", { "value": T }), + Object.defineProperty(ServicePrototype, "$type", { "value": T }); + + return Service; + + })(ProtoBuf, this); + }; + + /** + * @alias ProtoBuf.Reflect.Service + * @expose + */ + Reflect.Service = Service; + + /** + * Abstract service method. + * @exports ProtoBuf.Reflect.Service.Method + * @param {!ProtoBuf.Builder} builder Builder reference + * @param {!ProtoBuf.Reflect.Service} svc Service + * @param {string} name Method name + * @param {Object.=} options Options + * @constructor + * @extends ProtoBuf.Reflect.T + */ + var Method = function(builder, svc, name, options) { + T.call(this, builder, svc, name); + + /** + * @override + */ + this.className = "Service.Method"; + + /** + * Options. + * @type {Object.} + * @expose + */ + this.options = options || {}; + }; + + /** + * @alias ProtoBuf.Reflect.Service.Method.prototype + * @inner + */ + var MethodPrototype = Method.prototype = Object.create(T.prototype); + + /** + * Builds the method's '$options' property. + * @name ProtoBuf.Reflect.Service.Method#buildOpt + * @function + * @return {Object.} + */ + MethodPrototype.buildOpt = NamespacePrototype.buildOpt; + + /** + * @alias ProtoBuf.Reflect.Service.Method + * @expose + */ + Reflect.Service.Method = Method; + + /** + * RPC service method. + * @exports ProtoBuf.Reflect.Service.RPCMethod + * @param {!ProtoBuf.Builder} builder Builder reference + * @param {!ProtoBuf.Reflect.Service} svc Service + * @param {string} name Method name + * @param {string} request Request message name + * @param {string} response Response message name + * @param {boolean} request_stream Whether requests are streamed + * @param {boolean} response_stream Whether responses are streamed + * @param {Object.=} options Options + * @constructor + * @extends ProtoBuf.Reflect.Service.Method + */ + var RPCMethod = function(builder, svc, name, request, response, request_stream, response_stream, options) { + Method.call(this, builder, svc, name, options); + + /** + * @override + */ + this.className = "Service.RPCMethod"; + + /** + * Request message name. + * @type {string} + * @expose + */ + this.requestName = request; + + /** + * Response message name. + * @type {string} + * @expose + */ + this.responseName = response; + + /** + * Whether requests are streamed + * @type {bool} + * @expose + */ + this.requestStream = request_stream; + + /** + * Whether responses are streamed + * @type {bool} + * @expose + */ + this.responseStream = response_stream; + + /** + * Resolved request message type. + * @type {ProtoBuf.Reflect.Message} + * @expose + */ + this.resolvedRequestType = null; + + /** + * Resolved response message type. + * @type {ProtoBuf.Reflect.Message} + * @expose + */ + this.resolvedResponseType = null; + }; + + // Extends Method + RPCMethod.prototype = Object.create(Method.prototype); + + /** + * @alias ProtoBuf.Reflect.Service.RPCMethod + * @expose + */ + Reflect.Service.RPCMethod = RPCMethod; + + return Reflect; + + })(ProtoBuf); + + /** + * @alias ProtoBuf.Builder + * @expose + */ + ProtoBuf.Builder = (function(ProtoBuf, Lang, Reflect) { + "use strict"; + + /** + * Constructs a new Builder. + * @exports ProtoBuf.Builder + * @class Provides the functionality to build protocol messages. + * @param {Object.=} options Options + * @constructor + */ + var Builder = function(options) { + + /** + * Namespace. + * @type {ProtoBuf.Reflect.Namespace} + * @expose + */ + this.ns = new Reflect.Namespace(this, null, ""); // Global namespace + + /** + * Namespace pointer. + * @type {ProtoBuf.Reflect.T} + * @expose + */ + this.ptr = this.ns; + + /** + * Resolved flag. + * @type {boolean} + * @expose + */ + this.resolved = false; + + /** + * The current building result. + * @type {Object.|null} + * @expose + */ + this.result = null; + + /** + * Imported files. + * @type {Array.} + * @expose + */ + this.files = {}; + + /** + * Import root override. + * @type {?string} + * @expose + */ + this.importRoot = null; + + /** + * Options. + * @type {!Object.} + * @expose + */ + this.options = options || {}; + }; + + /** + * @alias ProtoBuf.Builder.prototype + * @inner + */ + var BuilderPrototype = Builder.prototype; + + // ----- Definition tests ----- + + /** + * Tests if a definition most likely describes a message. + * @param {!Object} def + * @returns {boolean} + * @expose + */ + Builder.isMessage = function(def) { + // Messages require a string name + if (typeof def["name"] !== 'string') + return false; + // Messages do not contain values (enum) or rpc methods (service) + if (typeof def["values"] !== 'undefined' || typeof def["rpc"] !== 'undefined') + return false; + return true; + }; + + /** + * Tests if a definition most likely describes a message field. + * @param {!Object} def + * @returns {boolean} + * @expose + */ + Builder.isMessageField = function(def) { + // Message fields require a string rule, name and type and an id + if (typeof def["rule"] !== 'string' || typeof def["name"] !== 'string' || typeof def["type"] !== 'string' || typeof def["id"] === 'undefined') + return false; + return true; + }; + + /** + * Tests if a definition most likely describes an enum. + * @param {!Object} def + * @returns {boolean} + * @expose + */ + Builder.isEnum = function(def) { + // Enums require a string name + if (typeof def["name"] !== 'string') + return false; + // Enums require at least one value + if (typeof def["values"] === 'undefined' || !Array.isArray(def["values"]) || def["values"].length === 0) + return false; + return true; + }; + + /** + * Tests if a definition most likely describes a service. + * @param {!Object} def + * @returns {boolean} + * @expose + */ + Builder.isService = function(def) { + // Services require a string name and an rpc object + if (typeof def["name"] !== 'string' || typeof def["rpc"] !== 'object' || !def["rpc"]) + return false; + return true; + }; + + /** + * Tests if a definition most likely describes an extended message + * @param {!Object} def + * @returns {boolean} + * @expose + */ + Builder.isExtend = function(def) { + // Extends rquire a string ref + if (typeof def["ref"] !== 'string') + return false; + return true; + }; + + // ----- Building ----- + + /** + * Resets the pointer to the root namespace. + * @returns {!ProtoBuf.Builder} this + * @expose + */ + BuilderPrototype.reset = function() { + this.ptr = this.ns; + return this; + }; + + /** + * Defines a namespace on top of the current pointer position and places the pointer on it. + * @param {string} namespace + * @return {!ProtoBuf.Builder} this + * @expose + */ + BuilderPrototype.define = function(namespace) { + if (typeof namespace !== 'string' || !Lang.TYPEREF.test(namespace)) + throw Error("illegal namespace: "+namespace); + namespace.split(".").forEach(function(part) { + var ns = this.ptr.getChild(part); + if (ns === null) // Keep existing + this.ptr.addChild(ns = new Reflect.Namespace(this, this.ptr, part)); + this.ptr = ns; + }, this); + return this; + }; + + /** + * Creates the specified definitions at the current pointer position. + * @param {!Array.} defs Messages, enums or services to create + * @returns {!ProtoBuf.Builder} this + * @throws {Error} If a message definition is invalid + * @expose + */ + BuilderPrototype.create = function(defs) { + if (!defs) + return this; // Nothing to create + if (!Array.isArray(defs)) + defs = [defs]; + else { + if (defs.length === 0) + return this; + defs = defs.slice(); + } + + // It's quite hard to keep track of scopes and memory here, so let's do this iteratively. + var stack = [defs]; + while (stack.length > 0) { + defs = stack.pop(); + + if (!Array.isArray(defs)) // Stack always contains entire namespaces + throw Error("not a valid namespace: "+JSON.stringify(defs)); + + while (defs.length > 0) { + var def = defs.shift(); // Namespaces always contain an array of messages, enums and services + + if (Builder.isMessage(def)) { + var obj = new Reflect.Message(this, this.ptr, def["name"], def["options"], def["isGroup"], def["syntax"]); + + // Create OneOfs + var oneofs = {}; + if (def["oneofs"]) + Object.keys(def["oneofs"]).forEach(function(name) { + obj.addChild(oneofs[name] = new Reflect.Message.OneOf(this, obj, name)); + }, this); + + // Create fields + if (def["fields"]) + def["fields"].forEach(function(fld) { + if (obj.getChild(fld["id"]|0) !== null) + throw Error("duplicate or invalid field id in "+obj.name+": "+fld['id']); + if (fld["options"] && typeof fld["options"] !== 'object') + throw Error("illegal field options in "+obj.name+"#"+fld["name"]); + var oneof = null; + if (typeof fld["oneof"] === 'string' && !(oneof = oneofs[fld["oneof"]])) + throw Error("illegal oneof in "+obj.name+"#"+fld["name"]+": "+fld["oneof"]); + fld = new Reflect.Message.Field(this, obj, fld["rule"], fld["keytype"], fld["type"], fld["name"], fld["id"], fld["options"], oneof, def["syntax"]); + if (oneof) + oneof.fields.push(fld); + obj.addChild(fld); + }, this); + + // Push children to stack + var subObj = []; + if (def["enums"]) + def["enums"].forEach(function(enm) { + subObj.push(enm); + }); + if (def["messages"]) + def["messages"].forEach(function(msg) { + subObj.push(msg); + }); + if (def["services"]) + def["services"].forEach(function(svc) { + subObj.push(svc); + }); + + // Set extension ranges + if (def["extensions"]) { + if (typeof def["extensions"][0] === 'number') // pre 5.0.1 + obj.extensions = [ def["extensions"] ]; + else + obj.extensions = def["extensions"]; + } + + // Create on top of current namespace + this.ptr.addChild(obj); + if (subObj.length > 0) { + stack.push(defs); // Push the current level back + defs = subObj; // Continue processing sub level + subObj = null; + this.ptr = obj; // And move the pointer to this namespace + obj = null; + continue; + } + subObj = null; + + } else if (Builder.isEnum(def)) { + + obj = new Reflect.Enum(this, this.ptr, def["name"], def["options"], def["syntax"]); + def["values"].forEach(function(val) { + obj.addChild(new Reflect.Enum.Value(this, obj, val["name"], val["id"])); + }, this); + this.ptr.addChild(obj); + + } else if (Builder.isService(def)) { + + obj = new Reflect.Service(this, this.ptr, def["name"], def["options"]); + Object.keys(def["rpc"]).forEach(function(name) { + var mtd = def["rpc"][name]; + obj.addChild(new Reflect.Service.RPCMethod(this, obj, name, mtd["request"], mtd["response"], !!mtd["request_stream"], !!mtd["response_stream"], mtd["options"])); + }, this); + this.ptr.addChild(obj); + + } else if (Builder.isExtend(def)) { + + obj = this.ptr.resolve(def["ref"], true); + if (obj) { + def["fields"].forEach(function(fld) { + if (obj.getChild(fld['id']|0) !== null) + throw Error("duplicate extended field id in "+obj.name+": "+fld['id']); + // Check if field id is allowed to be extended + if (obj.extensions) { + var valid = false; + obj.extensions.forEach(function(range) { + if (fld["id"] >= range[0] && fld["id"] <= range[1]) + valid = true; + }); + if (!valid) + throw Error("illegal extended field id in "+obj.name+": "+fld['id']+" (not within valid ranges)"); + } + // Convert extension field names to camel case notation if the override is set + var name = fld["name"]; + if (this.options['convertFieldsToCamelCase']) + name = ProtoBuf.Util.toCamelCase(name); + // see #161: Extensions use their fully qualified name as their runtime key and... + var field = new Reflect.Message.ExtensionField(this, obj, fld["rule"], fld["type"], this.ptr.fqn()+'.'+name, fld["id"], fld["options"]); + // ...are added on top of the current namespace as an extension which is used for + // resolving their type later on (the extension always keeps the original name to + // prevent naming collisions) + var ext = new Reflect.Extension(this, this.ptr, fld["name"], field); + field.extension = ext; + this.ptr.addChild(ext); + obj.addChild(field); + }, this); + + } else if (!/\.?google\.protobuf\./.test(def["ref"])) // Silently skip internal extensions + throw Error("extended message "+def["ref"]+" is not defined"); + + } else + throw Error("not a valid definition: "+JSON.stringify(def)); + + def = null; + obj = null; + } + // Break goes here + defs = null; + this.ptr = this.ptr.parent; // Namespace done, continue at parent + } + this.resolved = false; // Require re-resolve + this.result = null; // Require re-build + return this; + }; + + /** + * Propagates syntax to all children. + * @param {!Object} parent + * @inner + */ + function propagateSyntax(parent) { + if (parent['messages']) { + parent['messages'].forEach(function(child) { + child["syntax"] = parent["syntax"]; + propagateSyntax(child); + }); + } + if (parent['enums']) { + parent['enums'].forEach(function(child) { + child["syntax"] = parent["syntax"]; + }); + } + } + + /** + * Imports another definition into this builder. + * @param {Object.} json Parsed import + * @param {(string|{root: string, file: string})=} filename Imported file name + * @returns {!ProtoBuf.Builder} this + * @throws {Error} If the definition or file cannot be imported + * @expose + */ + BuilderPrototype["import"] = function(json, filename) { + var delim = '/'; + + // Make sure to skip duplicate imports + + if (typeof filename === 'string') { + + if (ProtoBuf.Util.IS_NODE) + filename = require("path")['resolve'](filename); + if (this.files[filename] === true) + return this.reset(); + this.files[filename] = true; + + } else if (typeof filename === 'object') { // Object with root, file. + + var root = filename.root; + if (ProtoBuf.Util.IS_NODE) + root = require("path")['resolve'](root); + if (root.indexOf("\\") >= 0 || filename.file.indexOf("\\") >= 0) + delim = '\\'; + var fname = root + delim + filename.file; + if (this.files[fname] === true) + return this.reset(); + this.files[fname] = true; + } + + // Import imports + + if (json['imports'] && json['imports'].length > 0) { + var importRoot, + resetRoot = false; + + if (typeof filename === 'object') { // If an import root is specified, override + + this.importRoot = filename["root"]; resetRoot = true; // ... and reset afterwards + importRoot = this.importRoot; + filename = filename["file"]; + if (importRoot.indexOf("\\") >= 0 || filename.indexOf("\\") >= 0) + delim = '\\'; + + } else if (typeof filename === 'string') { + + if (this.importRoot) // If import root is overridden, use it + importRoot = this.importRoot; + else { // Otherwise compute from filename + if (filename.indexOf("/") >= 0) { // Unix + importRoot = filename.replace(/\/[^\/]*$/, ""); + if (/* /file.proto */ importRoot === "") + importRoot = "/"; + } else if (filename.indexOf("\\") >= 0) { // Windows + importRoot = filename.replace(/\\[^\\]*$/, ""); + delim = '\\'; + } else + importRoot = "."; + } + + } else + importRoot = null; + + for (var i=0; i)=} path Specifies what to return. If omitted, the entire namespace will be returned. + * @returns {!ProtoBuf.Builder.Message|!Object.} + * @throws {Error} If a type could not be resolved + * @expose + */ + BuilderPrototype.build = function(path) { + this.reset(); + if (!this.resolved) + this.resolveAll(), + this.resolved = true, + this.result = null; // Require re-build + if (this.result === null) // (Re-)Build + this.result = this.ns.build(); + if (!path) + return this.result; + var part = typeof path === 'string' ? path.split(".") : path, + ptr = this.result; // Build namespace pointer (no hasChild etc.) + for (var i=0; i=} contents Initial contents + * @constructor + */ + var Map = function(field, contents) { + if (!field.map) + throw Error("field is not a map"); + + /** + * The field corresponding to this map. + * @type {!ProtoBuf.Reflect.Field} + */ + this.field = field; + + /** + * Element instance corresponding to key type. + * @type {!ProtoBuf.Reflect.Element} + */ + this.keyElem = new Reflect.Element(field.keyType, null, true, field.syntax); + + /** + * Element instance corresponding to value type. + * @type {!ProtoBuf.Reflect.Element} + */ + this.valueElem = new Reflect.Element(field.type, field.resolvedType, false, field.syntax); + + /** + * Internal map: stores mapping of (string form of key) -> (key, value) + * pair. + * + * We provide map semantics for arbitrary key types, but we build on top + * of an Object, which has only string keys. In order to avoid the need + * to convert a string key back to its native type in many situations, + * we store the native key value alongside the value. Thus, we only need + * a one-way mapping from a key type to its string form that guarantees + * uniqueness and equality (i.e., str(K1) === str(K2) if and only if K1 + * === K2). + * + * @type {!Object} + */ + this.map = {}; + + /** + * Returns the number of elements in the map. + */ + Object.defineProperty(this, "size", { + get: function() { return Object.keys(this.map).length; } + }); + + // Fill initial contents from a raw object. + if (contents) { + var keys = Object.keys(contents); + for (var i = 0; i < keys.length; i++) { + var key = this.keyElem.valueFromString(keys[i]); + var val = this.valueElem.verifyValue(contents[keys[i]]); + this.map[this.keyElem.valueToString(key)] = + { key: key, value: val }; + } + } + }; + + var MapPrototype = Map.prototype; + + /** + * Helper: return an iterator over an array. + * @param {!Array<*>} arr the array + * @returns {!Object} an iterator + * @inner + */ + function arrayIterator(arr) { + var idx = 0; + return { + next: function() { + if (idx < arr.length) + return { done: false, value: arr[idx++] }; + return { done: true }; + } + } + } + + /** + * Clears the map. + */ + MapPrototype.clear = function() { + this.map = {}; + }; + + /** + * Deletes a particular key from the map. + * @returns {boolean} Whether any entry with this key was deleted. + */ + MapPrototype["delete"] = function(key) { + var keyValue = this.keyElem.valueToString(this.keyElem.verifyValue(key)); + var hadKey = keyValue in this.map; + delete this.map[keyValue]; + return hadKey; + }; + + /** + * Returns an iterator over [key, value] pairs in the map. + * @returns {Object} The iterator + */ + MapPrototype.entries = function() { + var entries = []; + var strKeys = Object.keys(this.map); + for (var i = 0, entry; i < strKeys.length; i++) + entries.push([(entry=this.map[strKeys[i]]).key, entry.value]); + return arrayIterator(entries); + }; + + /** + * Returns an iterator over keys in the map. + * @returns {Object} The iterator + */ + MapPrototype.keys = function() { + var keys = []; + var strKeys = Object.keys(this.map); + for (var i = 0; i < strKeys.length; i++) + keys.push(this.map[strKeys[i]].key); + return arrayIterator(keys); + }; + + /** + * Returns an iterator over values in the map. + * @returns {!Object} The iterator + */ + MapPrototype.values = function() { + var values = []; + var strKeys = Object.keys(this.map); + for (var i = 0; i < strKeys.length; i++) + values.push(this.map[strKeys[i]].value); + return arrayIterator(values); + }; + + /** + * Iterates over entries in the map, calling a function on each. + * @param {function(this:*, *, *, *)} cb The callback to invoke with value, key, and map arguments. + * @param {Object=} thisArg The `this` value for the callback + */ + MapPrototype.forEach = function(cb, thisArg) { + var strKeys = Object.keys(this.map); + for (var i = 0, entry; i < strKeys.length; i++) + cb.call(thisArg, (entry=this.map[strKeys[i]]).value, entry.key, this); + }; + + /** + * Sets a key in the map to the given value. + * @param {*} key The key + * @param {*} value The value + * @returns {!ProtoBuf.Map} The map instance + */ + MapPrototype.set = function(key, value) { + var keyValue = this.keyElem.verifyValue(key); + var valValue = this.valueElem.verifyValue(value); + this.map[this.keyElem.valueToString(keyValue)] = + { key: keyValue, value: valValue }; + return this; + }; + + /** + * Gets the value corresponding to a key in the map. + * @param {*} key The key + * @returns {*|undefined} The value, or `undefined` if key not present + */ + MapPrototype.get = function(key) { + var keyValue = this.keyElem.valueToString(this.keyElem.verifyValue(key)); + if (!(keyValue in this.map)) + return undefined; + return this.map[keyValue].value; + }; + + /** + * Determines whether the given key is present in the map. + * @param {*} key The key + * @returns {boolean} `true` if the key is present + */ + MapPrototype.has = function(key) { + var keyValue = this.keyElem.valueToString(this.keyElem.verifyValue(key)); + return (keyValue in this.map); + }; + + return Map; + })(ProtoBuf, ProtoBuf.Reflect); + + + /** + * Loads a .proto string and returns the Builder. + * @param {string} proto .proto file contents + * @param {(ProtoBuf.Builder|string|{root: string, file: string})=} builder Builder to append to. Will create a new one if omitted. + * @param {(string|{root: string, file: string})=} filename The corresponding file name if known. Must be specified for imports. + * @return {ProtoBuf.Builder} Builder to create new messages + * @throws {Error} If the definition cannot be parsed or built + * @expose + */ + ProtoBuf.loadProto = function(proto, builder, filename) { + if (typeof builder === 'string' || (builder && typeof builder["file"] === 'string' && typeof builder["root"] === 'string')) + filename = builder, + builder = undefined; + return ProtoBuf.loadJson(ProtoBuf.DotProto.Parser.parse(proto), builder, filename); + }; + + /** + * Loads a .proto string and returns the Builder. This is an alias of {@link ProtoBuf.loadProto}. + * @function + * @param {string} proto .proto file contents + * @param {(ProtoBuf.Builder|string)=} builder Builder to append to. Will create a new one if omitted. + * @param {(string|{root: string, file: string})=} filename The corresponding file name if known. Must be specified for imports. + * @return {ProtoBuf.Builder} Builder to create new messages + * @throws {Error} If the definition cannot be parsed or built + * @expose + */ + ProtoBuf.protoFromString = ProtoBuf.loadProto; // Legacy + + /** + * Loads a .proto file and returns the Builder. + * @param {string|{root: string, file: string}} filename Path to proto file or an object specifying 'file' with + * an overridden 'root' path for all imported files. + * @param {function(?Error, !ProtoBuf.Builder=)=} callback Callback that will receive `null` as the first and + * the Builder as its second argument on success, otherwise the error as its first argument. If omitted, the + * file will be read synchronously and this function will return the Builder. + * @param {ProtoBuf.Builder=} builder Builder to append to. Will create a new one if omitted. + * @return {?ProtoBuf.Builder|undefined} The Builder if synchronous (no callback specified, will be NULL if the + * request has failed), else undefined + * @expose + */ + ProtoBuf.loadProtoFile = function(filename, callback, builder) { + if (callback && typeof callback === 'object') + builder = callback, + callback = null; + else if (!callback || typeof callback !== 'function') + callback = null; + if (callback) + return ProtoBuf.Util.fetch(typeof filename === 'string' ? filename : filename["root"]+"/"+filename["file"], function(contents) { + if (contents === null) { + callback(Error("Failed to fetch file")); + return; + } + try { + callback(null, ProtoBuf.loadProto(contents, builder, filename)); + } catch (e) { + callback(e); + } + }); + var contents = ProtoBuf.Util.fetch(typeof filename === 'object' ? filename["root"]+"/"+filename["file"] : filename); + return contents === null ? null : ProtoBuf.loadProto(contents, builder, filename); + }; + + /** + * Loads a .proto file and returns the Builder. This is an alias of {@link ProtoBuf.loadProtoFile}. + * @function + * @param {string|{root: string, file: string}} filename Path to proto file or an object specifying 'file' with + * an overridden 'root' path for all imported files. + * @param {function(?Error, !ProtoBuf.Builder=)=} callback Callback that will receive `null` as the first and + * the Builder as its second argument on success, otherwise the error as its first argument. If omitted, the + * file will be read synchronously and this function will return the Builder. + * @param {ProtoBuf.Builder=} builder Builder to append to. Will create a new one if omitted. + * @return {!ProtoBuf.Builder|undefined} The Builder if synchronous (no callback specified, will be NULL if the + * request has failed), else undefined + * @expose + */ + ProtoBuf.protoFromFile = ProtoBuf.loadProtoFile; // Legacy + + + /** + * Constructs a new empty Builder. + * @param {Object.=} options Builder options, defaults to global options set on ProtoBuf + * @return {!ProtoBuf.Builder} Builder + * @expose + */ + ProtoBuf.newBuilder = function(options) { + options = options || {}; + if (typeof options['convertFieldsToCamelCase'] === 'undefined') + options['convertFieldsToCamelCase'] = ProtoBuf.convertFieldsToCamelCase; + if (typeof options['populateAccessors'] === 'undefined') + options['populateAccessors'] = ProtoBuf.populateAccessors; + return new ProtoBuf.Builder(options); + }; + + /** + * Loads a .json definition and returns the Builder. + * @param {!*|string} json JSON definition + * @param {(ProtoBuf.Builder|string|{root: string, file: string})=} builder Builder to append to. Will create a new one if omitted. + * @param {(string|{root: string, file: string})=} filename The corresponding file name if known. Must be specified for imports. + * @return {ProtoBuf.Builder} Builder to create new messages + * @throws {Error} If the definition cannot be parsed or built + * @expose + */ + ProtoBuf.loadJson = function(json, builder, filename) { + if (typeof builder === 'string' || (builder && typeof builder["file"] === 'string' && typeof builder["root"] === 'string')) + filename = builder, + builder = null; + if (!builder || typeof builder !== 'object') + builder = ProtoBuf.newBuilder(); + if (typeof json === 'string') + json = JSON.parse(json); + builder["import"](json, filename); + builder.resolveAll(); + return builder; + }; + + /** + * Loads a .json file and returns the Builder. + * @param {string|!{root: string, file: string}} filename Path to json file or an object specifying 'file' with + * an overridden 'root' path for all imported files. + * @param {function(?Error, !ProtoBuf.Builder=)=} callback Callback that will receive `null` as the first and + * the Builder as its second argument on success, otherwise the error as its first argument. If omitted, the + * file will be read synchronously and this function will return the Builder. + * @param {ProtoBuf.Builder=} builder Builder to append to. Will create a new one if omitted. + * @return {?ProtoBuf.Builder|undefined} The Builder if synchronous (no callback specified, will be NULL if the + * request has failed), else undefined + * @expose + */ + ProtoBuf.loadJsonFile = function(filename, callback, builder) { + if (callback && typeof callback === 'object') + builder = callback, + callback = null; + else if (!callback || typeof callback !== 'function') + callback = null; + if (callback) + return ProtoBuf.Util.fetch(typeof filename === 'string' ? filename : filename["root"]+"/"+filename["file"], function(contents) { + if (contents === null) { + callback(Error("Failed to fetch file")); + return; + } + try { + callback(null, ProtoBuf.loadJson(JSON.parse(contents), builder, filename)); + } catch (e) { + callback(e); + } + }); + var contents = ProtoBuf.Util.fetch(typeof filename === 'object' ? filename["root"]+"/"+filename["file"] : filename); + return contents === null ? null : ProtoBuf.loadJson(JSON.parse(contents), builder, filename); + }; + + return ProtoBuf; +}); (function() { 'use strict'; @@ -35315,7 +35301,7 @@ Curve25519Worker.prototype = { return curve25519.verify(pubKey, msg, sig); } }; - }; + } Internal.Curve = wrapCurve25519(Internal.curve25519); Internal.Curve.async = wrapCurve25519(Internal.curve25519_async); @@ -35346,21 +35332,8 @@ Curve25519Worker.prototype = { })(); -/* vim: ts=4:sw=4 - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ +/* vim: ts=4:sw=4 */ + var Internal = Internal || {}; (function() { @@ -35487,63 +35460,21 @@ var Internal = Internal || {}; })(); -/* vim: ts=4:sw=4 - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . +/* + * vim: ts=4:sw=4 */ var util = (function() { 'use strict'; - var StaticByteBufferProto = new dcodeIO.ByteBuffer().__proto__; var StaticArrayBufferProto = new ArrayBuffer().__proto__; - var StaticUint8ArrayProto = new Uint8Array().__proto__; - - function stringObject(thing) { - if (typeof thing === 'string') { - return thing; - } - if (thing === Object(thing)) { - if (thing.__proto__ == StaticUint8ArrayProto) { - return String.fromCharCode.apply(null, thing); - } - if (thing.__proto__ == StaticArrayBufferProto) { - return stringObject(new Uint8Array(thing)); - } - if (thing.__proto__ == StaticByteBufferProto) { - return thing.toString('binary'); - } - } - throw new Error('unsure how to stringify object of type ' + typeof thing); - } return { toString: function(thing) { if (typeof thing == 'string') { return thing; - } else if (util.isStringable(thing)) { - return util.stringObject(thing); - } else { - throw new Error("Unsure how to convert object to string from type " + typeof thing); } - }, - stringObject: stringObject, - isStringable: function (thing) { - return (thing === Object(thing) && - (thing.__proto__ == StaticArrayBufferProto || - thing.__proto__ == StaticUint8ArrayProto || - thing.__proto__ == StaticByteBufferProto)); + return new dcodeIO.ByteBuffer.wrap(thing).toString('binary'); }, toArrayBuffer: function(thing) { if (thing === undefined) { @@ -35553,42 +35484,23 @@ var util = (function() { if (thing.__proto__ == StaticArrayBufferProto) { return thing; } - //TODO: Several more cases here... - } - - if (thing instanceof Array) { - // Assuming Uint16Array from curve25519 - //TODO: Move to convertToArrayBuffer - var res = new ArrayBuffer(thing.length * 2); - var uint = new Uint16Array(res); - for (var i = 0; i < thing.length; i++) { - uint[i] = thing[i]; - } - return res; } var str; - if (util.isStringable(thing)) { - str = util.stringObject(thing); - } else if (typeof thing == "string") { + if (typeof thing == "string") { str = thing; } else { - throw new Error("Tried to convert a non-stringable thing of type " + typeof thing + " to an array buffer"); + throw new Error("Tried to convert a non-string of type " + typeof thing + " to an array buffer"); } - var res = new ArrayBuffer(str.length); - var uint = new Uint8Array(res); - for (var i = 0; i < str.length; i++) { - uint[i] = str.charCodeAt(i); - } - return res; + return new dcodeIO.ByteBuffer.wrap(thing, 'binary').toArrayBuffer(); }, isEqual: function(a, b) { // TODO: Special-case arraybuffers, etc if (a === undefined || b === undefined) { return false; } - a = stringObject(a); - b = stringObject(b); + a = util.toString(a); + b = util.toString(b); var maxLength = Math.max(a.length, b.length); if (maxLength < 5) { throw new Error("a/b compare too short"); @@ -35683,21 +35595,7 @@ Internal.protoText = function() { return protoText; }(); -/* vim: ts=4:sw=4 - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ +/* vim: ts=4:sw=4 */ var Internal = Internal || {}; Internal.protobuf = function() { @@ -35705,7 +35603,7 @@ Internal.protobuf = function() { function loadProtoBufs(filename) { return dcodeIO.ProtoBuf.loadProto(Internal.protoText['protos/' + filename]).build('textsecure'); - }; + } var protocolMessages = loadProtoBufs('WhisperTextProtocol.proto'); @@ -35715,44 +35613,50 @@ Internal.protobuf = function() { }; }(); -/* vim: ts=4:sw=4 - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ +/* vim: ts=4:sw=4 */ var Internal = Internal || {}; +Internal.BaseKeyType = { + OURS: 1, + THEIRS: 2 +}; +Internal.ChainType = { + SENDING: 1, + RECEIVING: 2 +}; + Internal.SessionRecord = function() { 'use strict'; var MESSAGE_LOST_THRESHOLD_MS = 1000*60*60*24*7; + + var StaticByteBufferProto = new dcodeIO.ByteBuffer().__proto__; + var StaticArrayBufferProto = new ArrayBuffer().__proto__; + var StaticUint8ArrayProto = new Uint8Array().__proto__; + + function isStringable(thing) { + return (thing === Object(thing) && + (thing.__proto__ == StaticArrayBufferProto || + thing.__proto__ == StaticUint8ArrayProto || + thing.__proto__ == StaticByteBufferProto)); + } function ensureStringed(thing) { if (typeof thing == "string" || typeof thing == "number" || typeof thing == "boolean") { return thing; - } else if (util.isStringable(thing)) { - return util.stringObject(thing); + } else if (isStringable(thing)) { + return util.toString(thing); } else if (thing instanceof Array) { - var res = []; + var array = []; for (var i = 0; i < thing.length; i++) { - res[i] = ensureStringed(thing[i]); + array[i] = ensureStringed(thing[i]); } - return res; + return array; } else if (thing === Object(thing)) { - var res = {}; + var obj = {}; for (var key in thing) { - res[key] = ensureStringed(thing[key]); + obj[key] = ensureStringed(thing[key]); } - return res; + return obj; } else if (thing === null) { return null; } else { @@ -35804,19 +35708,12 @@ Internal.SessionRecord = function() { }, getSessionByBaseKey: function(baseKey) { - return this._sessions[util.toString(baseKey)]; - }, - getSessionOrIdentityKeyByBaseKey: function(baseKey) { - var preferredSession = this.getSessionByBaseKey(baseKey); - if (preferredSession !== undefined) { - return preferredSession; + var session = this._sessions[util.toString(baseKey)]; + if (session && session.indexInfo.baseKeyType === Internal.BaseKeyType.OURS) { + console.log("Tried to lookup a session using our basekey"); + return undefined; } - - if (this.identityKey !== undefined) { - return { indexInfo: { remoteIdentityKey: this.identityKey } }; - } - - throw new Error("Datastore inconsistency: device was stored without identity key"); + return session; }, getSessionByRemoteEphemeralKey: function(remoteEphemeralKey) { this.detectDuplicateOpenSessions(); @@ -35824,7 +35721,7 @@ Internal.SessionRecord = function() { var searchKey = util.toString(remoteEphemeralKey); - var openSession = undefined; + var openSession; for (var key in sessions) { if (sessions[key].indexInfo.closed == -1) { openSession = sessions[key]; @@ -35855,7 +35752,7 @@ Internal.SessionRecord = function() { return undefined; }, detectDuplicateOpenSessions: function() { - var openSession = undefined; + var openSession; var sessions = this._sessions; for (var key in sessions) { if (sessions[key].indexInfo.closed == -1) { @@ -35925,8 +35822,8 @@ Internal.SessionRecord = function() { } } // Delete current root key and our ephemeral key pair to disallow ratchet stepping - delete session.currentRatchet['rootKey']; - delete session.currentRatchet['ephemeralKeyPair']; + delete session.currentRatchet.rootKey; + delete session.currentRatchet.ephemeralKeyPair; session.indexInfo.closed = Date.now(); this.removeOldChains(session); }, @@ -36185,6 +36082,7 @@ SessionBuilder.prototype = { // otherwise we figure it out when we first maybeStepRatchet with the remote's ephemeral key if (isInitiator) { session.indexInfo.baseKey = ourEphemeralKey.pubKey; + session.indexInfo.baseKeyType = Internal.BaseKeyType.OURS; return Internal.crypto.createKeyPair().then(function(ourSendingEphemeralKey) { session.currentRatchet.ephemeralKeyPair = ourSendingEphemeralKey; return this.calculateSendingRatchet(session, theirSignedPubKey).then(function() { @@ -36193,6 +36091,7 @@ SessionBuilder.prototype = { }.bind(this)); } else { session.indexInfo.baseKey = theirEphemeralPubKey; + session.indexInfo.baseKeyType = Internal.BaseKeyType.THEIRS; session.currentRatchet.ephemeralKeyPair = ourSignedKey; return session; } @@ -36211,7 +36110,8 @@ SessionBuilder.prototype = { }).then(function(masterKey) { session[util.toString(ratchet.ephemeralKeyPair.pubKey)] = { messageKeys : {}, - chainKey : { counter : -1, key : masterKey[1] } + chainKey : { counter : -1, key : masterKey[1] }, + chainType : Internal.ChainType.SENDING }; ratchet.rootKey = masterKey[0]; }); @@ -36276,6 +36176,9 @@ SessionCipher.prototype = { session.currentRatchet.ephemeralKeyPair.pubKey ); chain = session[util.toString(msg.ephemeralKey)]; + if (chain.chainType === Internal.ChainType.RECEIVING) { + throw new Error("Tried to encrypt on a receiving chain"); + } return this.fillMessageKeys(chain, chain.chainKey.counter + 1); }.bind(this)).then(function() { @@ -36334,7 +36237,7 @@ SessionCipher.prototype = { var messageLengthWithTerminator = messageLength + 1; var messagePartCount = Math.floor(messageLengthWithTerminator / 160); - if (messageLengthWithTerminator % 160 != 0) { + if (messageLengthWithTerminator % 160 !== 0) { messagePartCount++; } @@ -36422,6 +36325,9 @@ SessionCipher.prototype = { return this.maybeStepRatchet(session, remoteEphemeralKey, message.previousCounter).then(function() { var chain = session[util.toString(message.ephemeralKey)]; + if (chain.chainType === Internal.ChainType.SENDING) { + throw new Error("Tried to decrypt on a sending chain"); + } return this.fillMessageKeys(chain, message.counter).then(function() { var messageKey = chain.messageKeys[message.counter]; @@ -36455,12 +36361,12 @@ SessionCipher.prototype = { plaintext.set(paddedPlaintext.subarray(0, i)); plaintext = plaintext.buffer; break; - } else if (paddedPlaintext[i] != 0x00) { + } else if (paddedPlaintext[i] !== 0x00) { throw new Error('Invalid padding'); } } - delete session['pendingPreKey']; + delete session.pendingPreKey; return plaintext; }); }, @@ -36541,7 +36447,8 @@ SessionCipher.prototype = { } session[util.toString(ephemeralPublicKey)] = { messageKeys: {}, - chainKey: { counter: -1, key: masterKey[1] } + chainKey: { counter: -1, key: masterKey[1] }, + chainType: sending ? Internal.ChainType.SENDING : Internal.ChainType.RECEIVING }; ratchet.rootKey = masterKey[0]; }); diff --git a/libtextsecure/libsignal-protocol.js b/libtextsecure/libsignal-protocol.js index 8afdd31d..424d69c5 100644 --- a/libtextsecure/libsignal-protocol.js +++ b/libtextsecure/libsignal-protocol.js @@ -25133,21 +25133,7 @@ run(); -/* vim: ts=4:sw=4:expandtab - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ +/* vim: ts=4:sw=4:expandtab */ var Internal = Internal || {}; (function() { @@ -25173,7 +25159,7 @@ var Internal = Internal || {}; var priv = new Uint8Array(privKey); priv[0] &= 248; priv[31] &= 127; - priv[31] |= 64 + priv[31] |= 64; // Where to store the result var publicKey_ptr = Module._malloc(32); @@ -25364,1614 +25350,1614 @@ Curve25519Worker.prototype = { })(); -/* - Copyright 2013 Daniel Wirtz - Copyright 2009 The Closure Library Authors. All Rights Reserved. - - 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 long.js (c) 2013 Daniel Wirtz - * Released under the Apache License, Version 2.0 - * see: https://github.com/dcodeIO/long.js for details - */ -(function(global, factory) { - - /* AMD */ if (typeof define === 'function' && define["amd"]) - define([], factory); - /* CommonJS */ else if (typeof require === 'function' && typeof module === "object" && module && module["exports"]) - module["exports"] = factory(); - /* Global */ else - (global["dcodeIO"] = global["dcodeIO"] || {})["Long"] = factory(); - -})(this, function() { - "use strict"; - - /** - * Constructs a 64 bit two's-complement integer, given its low and high 32 bit values as *signed* integers. - * See the from* functions below for more convenient ways of constructing Longs. - * @exports Long - * @class A Long class for representing a 64 bit two's-complement integer value. - * @param {number} low The low (signed) 32 bits of the long - * @param {number} high The high (signed) 32 bits of the long - * @param {boolean=} unsigned Whether unsigned or not, defaults to `false` for signed - * @constructor - */ - function Long(low, high, unsigned) { - - /** - * The low 32 bits as a signed value. - * @type {number} - * @expose - */ - this.low = low | 0; - - /** - * The high 32 bits as a signed value. - * @type {number} - * @expose - */ - this.high = high | 0; - - /** - * Whether unsigned or not. - * @type {boolean} - * @expose - */ - this.unsigned = !!unsigned; - } - - // The internal representation of a long is the two given signed, 32-bit values. - // We use 32-bit pieces because these are the size of integers on which - // Javascript performs bit-operations. For operations like addition and - // multiplication, we split each number into 16 bit pieces, which can easily be - // multiplied within Javascript's floating-point representation without overflow - // or change in sign. - // - // In the algorithms below, we frequently reduce the negative case to the - // positive case by negating the input(s) and then post-processing the result. - // Note that we must ALWAYS check specially whether those values are MIN_VALUE - // (-2^63) because -MIN_VALUE == MIN_VALUE (since 2^63 cannot be represented as - // a positive number, it overflows back into a negative). Not handling this - // case would often result in infinite recursion. - // - // Common constant values ZERO, ONE, NEG_ONE, etc. are defined below the from* - // methods on which they depend. - - /** - * An indicator used to reliably determine if an object is a Long or not. - * @type {boolean} - * @const - * @expose - * @private - */ - Long.__isLong__; - - Object.defineProperty(Long.prototype, "__isLong__", { - value: true, - enumerable: false, - configurable: false - }); - - /** - * @function - * @param {*} obj Object - * @returns {boolean} - * @inner - */ - function isLong(obj) { - return (obj && obj["__isLong__"]) === true; - } - - /** - * Tests if the specified object is a Long. - * @function - * @param {*} obj Object - * @returns {boolean} - * @expose - */ - Long.isLong = isLong; - - /** - * A cache of the Long representations of small integer values. - * @type {!Object} - * @inner - */ - var INT_CACHE = {}; - - /** - * A cache of the Long representations of small unsigned integer values. - * @type {!Object} - * @inner - */ - var UINT_CACHE = {}; - - /** - * @param {number} value - * @param {boolean=} unsigned - * @returns {!Long} - * @inner - */ - function fromInt(value, unsigned) { - var obj, cachedObj, cache; - if (unsigned) { - value >>>= 0; - if (cache = (0 <= value && value < 256)) { - cachedObj = UINT_CACHE[value]; - if (cachedObj) - return cachedObj; - } - obj = fromBits(value, (value | 0) < 0 ? -1 : 0, true); - if (cache) - UINT_CACHE[value] = obj; - return obj; - } else { - value |= 0; - if (cache = (-128 <= value && value < 128)) { - cachedObj = INT_CACHE[value]; - if (cachedObj) - return cachedObj; - } - obj = fromBits(value, value < 0 ? -1 : 0, false); - if (cache) - INT_CACHE[value] = obj; - return obj; - } - } - - /** - * Returns a Long representing the given 32 bit integer value. - * @function - * @param {number} value The 32 bit integer in question - * @param {boolean=} unsigned Whether unsigned or not, defaults to `false` for signed - * @returns {!Long} The corresponding Long value - * @expose - */ - Long.fromInt = fromInt; - - /** - * @param {number} value - * @param {boolean=} unsigned - * @returns {!Long} - * @inner - */ - function fromNumber(value, unsigned) { - if (isNaN(value) || !isFinite(value)) - return unsigned ? UZERO : ZERO; - if (unsigned) { - if (value < 0) - return UZERO; - if (value >= TWO_PWR_64_DBL) - return MAX_UNSIGNED_VALUE; - } else { - if (value <= -TWO_PWR_63_DBL) - return MIN_VALUE; - if (value + 1 >= TWO_PWR_63_DBL) - return MAX_VALUE; - } - if (value < 0) - return fromNumber(-value, unsigned).neg(); - return fromBits((value % TWO_PWR_32_DBL) | 0, (value / TWO_PWR_32_DBL) | 0, unsigned); - } - - /** - * Returns a Long representing the given value, provided that it is a finite number. Otherwise, zero is returned. - * @function - * @param {number} value The number in question - * @param {boolean=} unsigned Whether unsigned or not, defaults to `false` for signed - * @returns {!Long} The corresponding Long value - * @expose - */ - Long.fromNumber = fromNumber; - - /** - * @param {number} lowBits - * @param {number} highBits - * @param {boolean=} unsigned - * @returns {!Long} - * @inner - */ - function fromBits(lowBits, highBits, unsigned) { - return new Long(lowBits, highBits, unsigned); - } - - /** - * Returns a Long representing the 64 bit integer that comes by concatenating the given low and high bits. Each is - * assumed to use 32 bits. - * @function - * @param {number} lowBits The low 32 bits - * @param {number} highBits The high 32 bits - * @param {boolean=} unsigned Whether unsigned or not, defaults to `false` for signed - * @returns {!Long} The corresponding Long value - * @expose - */ - Long.fromBits = fromBits; - - /** - * @function - * @param {number} base - * @param {number} exponent - * @returns {number} - * @inner - */ - var pow_dbl = Math.pow; // Used 4 times (4*8 to 15+4) - - /** - * @param {string} str - * @param {(boolean|number)=} unsigned - * @param {number=} radix - * @returns {!Long} - * @inner - */ - function fromString(str, unsigned, radix) { - if (str.length === 0) - throw Error('empty string'); - if (str === "NaN" || str === "Infinity" || str === "+Infinity" || str === "-Infinity") - return ZERO; - if (typeof unsigned === 'number') { - // For goog.math.long compatibility - radix = unsigned, - unsigned = false; - } else { - unsigned = !! unsigned; - } - radix = radix || 10; - if (radix < 2 || 36 < radix) - throw RangeError('radix'); - - var p; - if ((p = str.indexOf('-')) > 0) - throw Error('interior hyphen'); - else if (p === 0) { - return fromString(str.substring(1), unsigned, radix).neg(); - } - - // Do several (8) digits each time through the loop, so as to - // minimize the calls to the very expensive emulated div. - var radixToPower = fromNumber(pow_dbl(radix, 8)); - - var result = ZERO; - for (var i = 0; i < str.length; i += 8) { - var size = Math.min(8, str.length - i), - value = parseInt(str.substring(i, i + size), radix); - if (size < 8) { - var power = fromNumber(pow_dbl(radix, size)); - result = result.mul(power).add(fromNumber(value)); - } else { - result = result.mul(radixToPower); - result = result.add(fromNumber(value)); - } - } - result.unsigned = unsigned; - return result; - } - - /** - * Returns a Long representation of the given string, written using the specified radix. - * @function - * @param {string} str The textual representation of the Long - * @param {(boolean|number)=} unsigned Whether unsigned or not, defaults to `false` for signed - * @param {number=} radix The radix in which the text is written (2-36), defaults to 10 - * @returns {!Long} The corresponding Long value - * @expose - */ - Long.fromString = fromString; - - /** - * @function - * @param {!Long|number|string|!{low: number, high: number, unsigned: boolean}} val - * @returns {!Long} - * @inner - */ - function fromValue(val) { - if (val /* is compatible */ instanceof Long) - return val; - if (typeof val === 'number') - return fromNumber(val); - if (typeof val === 'string') - return fromString(val); - // Throws for non-objects, converts non-instanceof Long: - return fromBits(val.low, val.high, val.unsigned); - } - - /** - * Converts the specified value to a Long. - * @function - * @param {!Long|number|string|!{low: number, high: number, unsigned: boolean}} val Value - * @returns {!Long} - * @expose - */ - Long.fromValue = fromValue; - - // NOTE: the compiler should inline these constant values below and then remove these variables, so there should be - // no runtime penalty for these. - - /** - * @type {number} - * @const - * @inner - */ - var TWO_PWR_16_DBL = 1 << 16; - - /** - * @type {number} - * @const - * @inner - */ - var TWO_PWR_24_DBL = 1 << 24; - - /** - * @type {number} - * @const - * @inner - */ - var TWO_PWR_32_DBL = TWO_PWR_16_DBL * TWO_PWR_16_DBL; - - /** - * @type {number} - * @const - * @inner - */ - var TWO_PWR_64_DBL = TWO_PWR_32_DBL * TWO_PWR_32_DBL; - - /** - * @type {number} - * @const - * @inner - */ - var TWO_PWR_63_DBL = TWO_PWR_64_DBL / 2; - - /** - * @type {!Long} - * @const - * @inner - */ - var TWO_PWR_24 = fromInt(TWO_PWR_24_DBL); - - /** - * @type {!Long} - * @inner - */ - var ZERO = fromInt(0); - - /** - * Signed zero. - * @type {!Long} - * @expose - */ - Long.ZERO = ZERO; - - /** - * @type {!Long} - * @inner - */ - var UZERO = fromInt(0, true); - - /** - * Unsigned zero. - * @type {!Long} - * @expose - */ - Long.UZERO = UZERO; - - /** - * @type {!Long} - * @inner - */ - var ONE = fromInt(1); - - /** - * Signed one. - * @type {!Long} - * @expose - */ - Long.ONE = ONE; - - /** - * @type {!Long} - * @inner - */ - var UONE = fromInt(1, true); - - /** - * Unsigned one. - * @type {!Long} - * @expose - */ - Long.UONE = UONE; - - /** - * @type {!Long} - * @inner - */ - var NEG_ONE = fromInt(-1); - - /** - * Signed negative one. - * @type {!Long} - * @expose - */ - Long.NEG_ONE = NEG_ONE; - - /** - * @type {!Long} - * @inner - */ - var MAX_VALUE = fromBits(0xFFFFFFFF|0, 0x7FFFFFFF|0, false); - - /** - * Maximum signed value. - * @type {!Long} - * @expose - */ - Long.MAX_VALUE = MAX_VALUE; - - /** - * @type {!Long} - * @inner - */ - var MAX_UNSIGNED_VALUE = fromBits(0xFFFFFFFF|0, 0xFFFFFFFF|0, true); - - /** - * Maximum unsigned value. - * @type {!Long} - * @expose - */ - Long.MAX_UNSIGNED_VALUE = MAX_UNSIGNED_VALUE; - - /** - * @type {!Long} - * @inner - */ - var MIN_VALUE = fromBits(0, 0x80000000|0, false); - - /** - * Minimum signed value. - * @type {!Long} - * @expose - */ - Long.MIN_VALUE = MIN_VALUE; - - /** - * @alias Long.prototype - * @inner - */ - var LongPrototype = Long.prototype; - - /** - * Converts the Long to a 32 bit integer, assuming it is a 32 bit integer. - * @returns {number} - * @expose - */ - LongPrototype.toInt = function toInt() { - return this.unsigned ? this.low >>> 0 : this.low; - }; - - /** - * Converts the Long to a the nearest floating-point representation of this value (double, 53 bit mantissa). - * @returns {number} - * @expose - */ - LongPrototype.toNumber = function toNumber() { - if (this.unsigned) - return ((this.high >>> 0) * TWO_PWR_32_DBL) + (this.low >>> 0); - return this.high * TWO_PWR_32_DBL + (this.low >>> 0); - }; - - /** - * Converts the Long to a string written in the specified radix. - * @param {number=} radix Radix (2-36), defaults to 10 - * @returns {string} - * @override - * @throws {RangeError} If `radix` is out of range - * @expose - */ - LongPrototype.toString = function toString(radix) { - radix = radix || 10; - if (radix < 2 || 36 < radix) - throw RangeError('radix'); - if (this.isZero()) - return '0'; - if (this.isNegative()) { // Unsigned Longs are never negative - if (this.eq(MIN_VALUE)) { - // We need to change the Long value before it can be negated, so we remove - // the bottom-most digit in this base and then recurse to do the rest. - var radixLong = fromNumber(radix), - div = this.div(radixLong), - rem1 = div.mul(radixLong).sub(this); - return div.toString(radix) + rem1.toInt().toString(radix); - } else - return '-' + this.neg().toString(radix); - } - - // Do several (6) digits each time through the loop, so as to - // minimize the calls to the very expensive emulated div. - var radixToPower = fromNumber(pow_dbl(radix, 6), this.unsigned), - rem = this; - var result = ''; - while (true) { - var remDiv = rem.div(radixToPower), - intval = rem.sub(remDiv.mul(radixToPower)).toInt() >>> 0, - digits = intval.toString(radix); - rem = remDiv; - if (rem.isZero()) - return digits + result; - else { - while (digits.length < 6) - digits = '0' + digits; - result = '' + digits + result; - } - } - }; - - /** - * Gets the high 32 bits as a signed integer. - * @returns {number} Signed high bits - * @expose - */ - LongPrototype.getHighBits = function getHighBits() { - return this.high; - }; - - /** - * Gets the high 32 bits as an unsigned integer. - * @returns {number} Unsigned high bits - * @expose - */ - LongPrototype.getHighBitsUnsigned = function getHighBitsUnsigned() { - return this.high >>> 0; - }; - - /** - * Gets the low 32 bits as a signed integer. - * @returns {number} Signed low bits - * @expose - */ - LongPrototype.getLowBits = function getLowBits() { - return this.low; - }; - - /** - * Gets the low 32 bits as an unsigned integer. - * @returns {number} Unsigned low bits - * @expose - */ - LongPrototype.getLowBitsUnsigned = function getLowBitsUnsigned() { - return this.low >>> 0; - }; - - /** - * Gets the number of bits needed to represent the absolute value of this Long. - * @returns {number} - * @expose - */ - LongPrototype.getNumBitsAbs = function getNumBitsAbs() { - if (this.isNegative()) // Unsigned Longs are never negative - return this.eq(MIN_VALUE) ? 64 : this.neg().getNumBitsAbs(); - var val = this.high != 0 ? this.high : this.low; - for (var bit = 31; bit > 0; bit--) - if ((val & (1 << bit)) != 0) - break; - return this.high != 0 ? bit + 33 : bit + 1; - }; - - /** - * Tests if this Long's value equals zero. - * @returns {boolean} - * @expose - */ - LongPrototype.isZero = function isZero() { - return this.high === 0 && this.low === 0; - }; - - /** - * Tests if this Long's value is negative. - * @returns {boolean} - * @expose - */ - LongPrototype.isNegative = function isNegative() { - return !this.unsigned && this.high < 0; - }; - - /** - * Tests if this Long's value is positive. - * @returns {boolean} - * @expose - */ - LongPrototype.isPositive = function isPositive() { - return this.unsigned || this.high >= 0; - }; - - /** - * Tests if this Long's value is odd. - * @returns {boolean} - * @expose - */ - LongPrototype.isOdd = function isOdd() { - return (this.low & 1) === 1; - }; - - /** - * Tests if this Long's value is even. - * @returns {boolean} - * @expose - */ - LongPrototype.isEven = function isEven() { - return (this.low & 1) === 0; - }; - - /** - * Tests if this Long's value equals the specified's. - * @param {!Long|number|string} other Other value - * @returns {boolean} - * @expose - */ - LongPrototype.equals = function equals(other) { - if (!isLong(other)) - other = fromValue(other); - if (this.unsigned !== other.unsigned && (this.high >>> 31) === 1 && (other.high >>> 31) === 1) - return false; - return this.high === other.high && this.low === other.low; - }; - - /** - * Tests if this Long's value equals the specified's. This is an alias of {@link Long#equals}. - * @function - * @param {!Long|number|string} other Other value - * @returns {boolean} - * @expose - */ - LongPrototype.eq = LongPrototype.equals; - - /** - * Tests if this Long's value differs from the specified's. - * @param {!Long|number|string} other Other value - * @returns {boolean} - * @expose - */ - LongPrototype.notEquals = function notEquals(other) { - return !this.eq(/* validates */ other); - }; - - /** - * Tests if this Long's value differs from the specified's. This is an alias of {@link Long#notEquals}. - * @function - * @param {!Long|number|string} other Other value - * @returns {boolean} - * @expose - */ - LongPrototype.neq = LongPrototype.notEquals; - - /** - * Tests if this Long's value is less than the specified's. - * @param {!Long|number|string} other Other value - * @returns {boolean} - * @expose - */ - LongPrototype.lessThan = function lessThan(other) { - return this.comp(/* validates */ other) < 0; - }; - - /** - * Tests if this Long's value is less than the specified's. This is an alias of {@link Long#lessThan}. - * @function - * @param {!Long|number|string} other Other value - * @returns {boolean} - * @expose - */ - LongPrototype.lt = LongPrototype.lessThan; - - /** - * Tests if this Long's value is less than or equal the specified's. - * @param {!Long|number|string} other Other value - * @returns {boolean} - * @expose - */ - LongPrototype.lessThanOrEqual = function lessThanOrEqual(other) { - return this.comp(/* validates */ other) <= 0; - }; - - /** - * Tests if this Long's value is less than or equal the specified's. This is an alias of {@link Long#lessThanOrEqual}. - * @function - * @param {!Long|number|string} other Other value - * @returns {boolean} - * @expose - */ - LongPrototype.lte = LongPrototype.lessThanOrEqual; - - /** - * Tests if this Long's value is greater than the specified's. - * @param {!Long|number|string} other Other value - * @returns {boolean} - * @expose - */ - LongPrototype.greaterThan = function greaterThan(other) { - return this.comp(/* validates */ other) > 0; - }; - - /** - * Tests if this Long's value is greater than the specified's. This is an alias of {@link Long#greaterThan}. - * @function - * @param {!Long|number|string} other Other value - * @returns {boolean} - * @expose - */ - LongPrototype.gt = LongPrototype.greaterThan; - - /** - * Tests if this Long's value is greater than or equal the specified's. - * @param {!Long|number|string} other Other value - * @returns {boolean} - * @expose - */ - LongPrototype.greaterThanOrEqual = function greaterThanOrEqual(other) { - return this.comp(/* validates */ other) >= 0; - }; - - /** - * Tests if this Long's value is greater than or equal the specified's. This is an alias of {@link Long#greaterThanOrEqual}. - * @function - * @param {!Long|number|string} other Other value - * @returns {boolean} - * @expose - */ - LongPrototype.gte = LongPrototype.greaterThanOrEqual; - - /** - * Compares this Long's value with the specified's. - * @param {!Long|number|string} other Other value - * @returns {number} 0 if they are the same, 1 if the this is greater and -1 - * if the given one is greater - * @expose - */ - LongPrototype.compare = function compare(other) { - if (!isLong(other)) - other = fromValue(other); - if (this.eq(other)) - return 0; - var thisNeg = this.isNegative(), - otherNeg = other.isNegative(); - if (thisNeg && !otherNeg) - return -1; - if (!thisNeg && otherNeg) - return 1; - // At this point the sign bits are the same - if (!this.unsigned) - return this.sub(other).isNegative() ? -1 : 1; - // Both are positive if at least one is unsigned - return (other.high >>> 0) > (this.high >>> 0) || (other.high === this.high && (other.low >>> 0) > (this.low >>> 0)) ? -1 : 1; - }; - - /** - * Compares this Long's value with the specified's. This is an alias of {@link Long#compare}. - * @function - * @param {!Long|number|string} other Other value - * @returns {number} 0 if they are the same, 1 if the this is greater and -1 - * if the given one is greater - * @expose - */ - LongPrototype.comp = LongPrototype.compare; - - /** - * Negates this Long's value. - * @returns {!Long} Negated Long - * @expose - */ - LongPrototype.negate = function negate() { - if (!this.unsigned && this.eq(MIN_VALUE)) - return MIN_VALUE; - return this.not().add(ONE); - }; - - /** - * Negates this Long's value. This is an alias of {@link Long#negate}. - * @function - * @returns {!Long} Negated Long - * @expose - */ - LongPrototype.neg = LongPrototype.negate; - - /** - * Returns the sum of this and the specified Long. - * @param {!Long|number|string} addend Addend - * @returns {!Long} Sum - * @expose - */ - LongPrototype.add = function add(addend) { - if (!isLong(addend)) - addend = fromValue(addend); - - // Divide each number into 4 chunks of 16 bits, and then sum the chunks. - - var a48 = this.high >>> 16; - var a32 = this.high & 0xFFFF; - var a16 = this.low >>> 16; - var a00 = this.low & 0xFFFF; - - var b48 = addend.high >>> 16; - var b32 = addend.high & 0xFFFF; - var b16 = addend.low >>> 16; - var b00 = addend.low & 0xFFFF; - - var c48 = 0, c32 = 0, c16 = 0, c00 = 0; - c00 += a00 + b00; - c16 += c00 >>> 16; - c00 &= 0xFFFF; - c16 += a16 + b16; - c32 += c16 >>> 16; - c16 &= 0xFFFF; - c32 += a32 + b32; - c48 += c32 >>> 16; - c32 &= 0xFFFF; - c48 += a48 + b48; - c48 &= 0xFFFF; - return fromBits((c16 << 16) | c00, (c48 << 16) | c32, this.unsigned); - }; - - /** - * Returns the difference of this and the specified Long. - * @param {!Long|number|string} subtrahend Subtrahend - * @returns {!Long} Difference - * @expose - */ - LongPrototype.subtract = function subtract(subtrahend) { - if (!isLong(subtrahend)) - subtrahend = fromValue(subtrahend); - return this.add(subtrahend.neg()); - }; - - /** - * Returns the difference of this and the specified Long. This is an alias of {@link Long#subtract}. - * @function - * @param {!Long|number|string} subtrahend Subtrahend - * @returns {!Long} Difference - * @expose - */ - LongPrototype.sub = LongPrototype.subtract; - - /** - * Returns the product of this and the specified Long. - * @param {!Long|number|string} multiplier Multiplier - * @returns {!Long} Product - * @expose - */ - LongPrototype.multiply = function multiply(multiplier) { - if (this.isZero()) - return ZERO; - if (!isLong(multiplier)) - multiplier = fromValue(multiplier); - if (multiplier.isZero()) - return ZERO; - if (this.eq(MIN_VALUE)) - return multiplier.isOdd() ? MIN_VALUE : ZERO; - if (multiplier.eq(MIN_VALUE)) - return this.isOdd() ? MIN_VALUE : ZERO; - - if (this.isNegative()) { - if (multiplier.isNegative()) - return this.neg().mul(multiplier.neg()); - else - return this.neg().mul(multiplier).neg(); - } else if (multiplier.isNegative()) - return this.mul(multiplier.neg()).neg(); - - // If both longs are small, use float multiplication - if (this.lt(TWO_PWR_24) && multiplier.lt(TWO_PWR_24)) - return fromNumber(this.toNumber() * multiplier.toNumber(), this.unsigned); - - // Divide each long into 4 chunks of 16 bits, and then add up 4x4 products. - // We can skip products that would overflow. - - var a48 = this.high >>> 16; - var a32 = this.high & 0xFFFF; - var a16 = this.low >>> 16; - var a00 = this.low & 0xFFFF; - - var b48 = multiplier.high >>> 16; - var b32 = multiplier.high & 0xFFFF; - var b16 = multiplier.low >>> 16; - var b00 = multiplier.low & 0xFFFF; - - var c48 = 0, c32 = 0, c16 = 0, c00 = 0; - c00 += a00 * b00; - c16 += c00 >>> 16; - c00 &= 0xFFFF; - c16 += a16 * b00; - c32 += c16 >>> 16; - c16 &= 0xFFFF; - c16 += a00 * b16; - c32 += c16 >>> 16; - c16 &= 0xFFFF; - c32 += a32 * b00; - c48 += c32 >>> 16; - c32 &= 0xFFFF; - c32 += a16 * b16; - c48 += c32 >>> 16; - c32 &= 0xFFFF; - c32 += a00 * b32; - c48 += c32 >>> 16; - c32 &= 0xFFFF; - c48 += a48 * b00 + a32 * b16 + a16 * b32 + a00 * b48; - c48 &= 0xFFFF; - return fromBits((c16 << 16) | c00, (c48 << 16) | c32, this.unsigned); - }; - - /** - * Returns the product of this and the specified Long. This is an alias of {@link Long#multiply}. - * @function - * @param {!Long|number|string} multiplier Multiplier - * @returns {!Long} Product - * @expose - */ - LongPrototype.mul = LongPrototype.multiply; - - /** - * Returns this Long divided by the specified. The result is signed if this Long is signed or - * unsigned if this Long is unsigned. - * @param {!Long|number|string} divisor Divisor - * @returns {!Long} Quotient - * @expose - */ - LongPrototype.divide = function divide(divisor) { - if (!isLong(divisor)) - divisor = fromValue(divisor); - if (divisor.isZero()) - throw Error('division by zero'); - if (this.isZero()) - return this.unsigned ? UZERO : ZERO; - var approx, rem, res; - if (!this.unsigned) { - if (this.eq(MIN_VALUE)) { - if (divisor.eq(ONE) || divisor.eq(NEG_ONE)) - return MIN_VALUE; // recall that -MIN_VALUE == MIN_VALUE - else if (divisor.eq(MIN_VALUE)) - return ONE; - else { - // At this point, we have |other| >= 2, so |this/other| < |MIN_VALUE|. - var halfThis = this.shr(1); - approx = halfThis.div(divisor).shl(1); - if (approx.eq(ZERO)) { - return divisor.isNegative() ? ONE : NEG_ONE; - } else { - rem = this.sub(divisor.mul(approx)); - res = approx.add(rem.div(divisor)); - return res; - } - } - } else if (divisor.eq(MIN_VALUE)) - return this.unsigned ? UZERO : ZERO; - if (this.isNegative()) { - if (divisor.isNegative()) - return this.neg().div(divisor.neg()); - return this.neg().div(divisor).neg(); - } else if (divisor.isNegative()) - return this.div(divisor.neg()).neg(); - } else if (!divisor.unsigned) - divisor = divisor.toUnsigned(); - - // The algorithm below has not been made for unsigned longs. It's therefore - // required to take special care of the MSB prior to running it. - if (this.unsigned) { - if (divisor.gt(this)) - return UZERO; - if (divisor.gt(this.shru(1))) // 15 >>> 1 = 7 ; with divisor = 8 ; true - return UONE; - res = UZERO; - } else - res = ZERO; - - // Repeat the following until the remainder is less than other: find a - // floating-point that approximates remainder / other *from below*, add this - // into the result, and subtract it from the remainder. It is critical that - // the approximate value is less than or equal to the real value so that the - // remainder never becomes negative. - rem = this; - while (rem.gte(divisor)) { - // Approximate the result of division. This may be a little greater or - // smaller than the actual value. - approx = Math.max(1, Math.floor(rem.toNumber() / divisor.toNumber())); - - // We will tweak the approximate result by changing it in the 48-th digit or - // the smallest non-fractional digit, whichever is larger. - var log2 = Math.ceil(Math.log(approx) / Math.LN2), - delta = (log2 <= 48) ? 1 : pow_dbl(2, log2 - 48), - - // Decrease the approximation until it is smaller than the remainder. Note - // that if it is too large, the product overflows and is negative. - approxRes = fromNumber(approx), - approxRem = approxRes.mul(divisor); - while (approxRem.isNegative() || approxRem.gt(rem)) { - approx -= delta; - approxRes = fromNumber(approx, this.unsigned); - approxRem = approxRes.mul(divisor); - } - - // We know the answer can't be zero... and actually, zero would cause - // infinite recursion since we would make no progress. - if (approxRes.isZero()) - approxRes = ONE; - - res = res.add(approxRes); - rem = rem.sub(approxRem); - } - return res; - }; - - /** - * Returns this Long divided by the specified. This is an alias of {@link Long#divide}. - * @function - * @param {!Long|number|string} divisor Divisor - * @returns {!Long} Quotient - * @expose - */ - LongPrototype.div = LongPrototype.divide; - - /** - * Returns this Long modulo the specified. - * @param {!Long|number|string} divisor Divisor - * @returns {!Long} Remainder - * @expose - */ - LongPrototype.modulo = function modulo(divisor) { - if (!isLong(divisor)) - divisor = fromValue(divisor); - return this.sub(this.div(divisor).mul(divisor)); - }; - - /** - * Returns this Long modulo the specified. This is an alias of {@link Long#modulo}. - * @function - * @param {!Long|number|string} divisor Divisor - * @returns {!Long} Remainder - * @expose - */ - LongPrototype.mod = LongPrototype.modulo; - - /** - * Returns the bitwise NOT of this Long. - * @returns {!Long} - * @expose - */ - LongPrototype.not = function not() { - return fromBits(~this.low, ~this.high, this.unsigned); - }; - - /** - * Returns the bitwise AND of this Long and the specified. - * @param {!Long|number|string} other Other Long - * @returns {!Long} - * @expose - */ - LongPrototype.and = function and(other) { - if (!isLong(other)) - other = fromValue(other); - return fromBits(this.low & other.low, this.high & other.high, this.unsigned); - }; - - /** - * Returns the bitwise OR of this Long and the specified. - * @param {!Long|number|string} other Other Long - * @returns {!Long} - * @expose - */ - LongPrototype.or = function or(other) { - if (!isLong(other)) - other = fromValue(other); - return fromBits(this.low | other.low, this.high | other.high, this.unsigned); - }; - - /** - * Returns the bitwise XOR of this Long and the given one. - * @param {!Long|number|string} other Other Long - * @returns {!Long} - * @expose - */ - LongPrototype.xor = function xor(other) { - if (!isLong(other)) - other = fromValue(other); - return fromBits(this.low ^ other.low, this.high ^ other.high, this.unsigned); - }; - - /** - * Returns this Long with bits shifted to the left by the given amount. - * @param {number|!Long} numBits Number of bits - * @returns {!Long} Shifted Long - * @expose - */ - LongPrototype.shiftLeft = function shiftLeft(numBits) { - if (isLong(numBits)) - numBits = numBits.toInt(); - if ((numBits &= 63) === 0) - return this; - else if (numBits < 32) - return fromBits(this.low << numBits, (this.high << numBits) | (this.low >>> (32 - numBits)), this.unsigned); - else - return fromBits(0, this.low << (numBits - 32), this.unsigned); - }; - - /** - * Returns this Long with bits shifted to the left by the given amount. This is an alias of {@link Long#shiftLeft}. - * @function - * @param {number|!Long} numBits Number of bits - * @returns {!Long} Shifted Long - * @expose - */ - LongPrototype.shl = LongPrototype.shiftLeft; - - /** - * Returns this Long with bits arithmetically shifted to the right by the given amount. - * @param {number|!Long} numBits Number of bits - * @returns {!Long} Shifted Long - * @expose - */ - LongPrototype.shiftRight = function shiftRight(numBits) { - if (isLong(numBits)) - numBits = numBits.toInt(); - if ((numBits &= 63) === 0) - return this; - else if (numBits < 32) - return fromBits((this.low >>> numBits) | (this.high << (32 - numBits)), this.high >> numBits, this.unsigned); - else - return fromBits(this.high >> (numBits - 32), this.high >= 0 ? 0 : -1, this.unsigned); - }; - - /** - * Returns this Long with bits arithmetically shifted to the right by the given amount. This is an alias of {@link Long#shiftRight}. - * @function - * @param {number|!Long} numBits Number of bits - * @returns {!Long} Shifted Long - * @expose - */ - LongPrototype.shr = LongPrototype.shiftRight; - - /** - * Returns this Long with bits logically shifted to the right by the given amount. - * @param {number|!Long} numBits Number of bits - * @returns {!Long} Shifted Long - * @expose - */ - LongPrototype.shiftRightUnsigned = function shiftRightUnsigned(numBits) { - if (isLong(numBits)) - numBits = numBits.toInt(); - numBits &= 63; - if (numBits === 0) - return this; - else { - var high = this.high; - if (numBits < 32) { - var low = this.low; - return fromBits((low >>> numBits) | (high << (32 - numBits)), high >>> numBits, this.unsigned); - } else if (numBits === 32) - return fromBits(high, 0, this.unsigned); - else - return fromBits(high >>> (numBits - 32), 0, this.unsigned); - } - }; - - /** - * Returns this Long with bits logically shifted to the right by the given amount. This is an alias of {@link Long#shiftRightUnsigned}. - * @function - * @param {number|!Long} numBits Number of bits - * @returns {!Long} Shifted Long - * @expose - */ - LongPrototype.shru = LongPrototype.shiftRightUnsigned; - - /** - * Converts this Long to signed. - * @returns {!Long} Signed long - * @expose - */ - LongPrototype.toSigned = function toSigned() { - if (!this.unsigned) - return this; - return fromBits(this.low, this.high, false); - }; - - /** - * Converts this Long to unsigned. - * @returns {!Long} Unsigned long - * @expose - */ - LongPrototype.toUnsigned = function toUnsigned() { - if (this.unsigned) - return this; - return fromBits(this.low, this.high, true); - }; - - return Long; -}); - -/* - Copyright 2013-2014 Daniel Wirtz - - 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 - * This version of ByteBuffer.js uses an ArrayBuffer as its backing buffer which is accessed through a DataView and is - * compatible with modern browsers. - * Released under the Apache License, Version 2.0 - * see: https://github.com/dcodeIO/ByteBuffer.js for details - */ // -(function(global) { - "use strict"; - - /** - * @param {function(new: Long, number, number, boolean=)=} Long - * @returns {function(new: ByteBuffer, number=, boolean=, boolean=)}} - * @inner - */ - function loadByteBuffer(Long) { - - /** - * 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 RangeError("Illegal capacity"); - littleEndian = !!littleEndian; - noAssert = !!noAssert; - } - - /** - * Backing buffer. - * @type {!ArrayBuffer} - * @expose - */ - this.buffer = capacity === 0 ? EMPTY_BUFFER : new ArrayBuffer(capacity); - - /** - * Data view to manipulate the backing buffer. Becomes `null` if the backing buffer has a capacity of `0`. - * @type {?DataView} - * @expose - */ - this.view = capacity === 0 ? null : new DataView(this.buffer); - - /** - * 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.5.5"; - - /** - * 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. May be `null` if Long.js has not been loaded - * and int64 support is not available. - * @type {?Long} - * @const - * @see https://github.com/dcodeIO/Long.js - * @expose - */ - ByteBuffer.Long = Long || null; - - /** - * @alias ByteBuffer.prototype - * @inner - */ - var ByteBufferPrototype = ByteBuffer.prototype; - - // helpers - - /** - * @type {!ArrayBuffer} - * @inner - */ - var EMPTY_BUFFER = new ArrayBuffer(0); - - /** - * String.fromCharCode reference for compile-time renaming. - * @type {function(...number):string} - * @inner - */ - var stringFromCharCode = String.fromCharCode; - - /** - * Creates a source function for a string. - * @param {string} s String to read from - * @returns {function():number|null} Source function returning the next char code respectively `null` if there are - * no more characters left. - * @throws {TypeError} If the argument is invalid - * @inner - */ - function stringSource(s) { - var i=0; return function() { - return i < s.length ? s.charCodeAt(i++) : null; - }; - } - - /** - * Creates a destination function for a string. - * @returns {function(number=):undefined|string} Destination function successively called with the next char code. - * Returns the final string when called without arguments. - * @inner - */ - function stringDestination() { - var cs = [], ps = []; return function() { - if (arguments.length === 0) - return ps.join('')+stringFromCharCode.apply(String, cs); - if (cs.length + arguments.length > 1024) - ps.push(stringFromCharCode.apply(String, cs)), - cs.length = 0; - Array.prototype.push.apply(cs, arguments); - }; - } - - /** - * 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.} 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 0) capacity += length; - } - if (capacity === 0) - return new ByteBuffer(0, littleEndian, noAssert); - var bb = new ByteBuffer(capacity, littleEndian, noAssert), - bi; - var view = new Uint8Array(bb.buffer); - i=0; while (i} 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 Error("Unsupported encoding: "+encoding); - } - } - if (buffer === null || typeof buffer !== 'object') - throw TypeError("Illegal buffer"); - var bb; - if (ByteBuffer.isByteBuffer(buffer)) { - bb = ByteBufferPrototype.clone.call(buffer); - bb.markedOffset = -1; - return bb; - } - if (buffer instanceof Uint8Array) { // Extract ArrayBuffer from Uint8Array - bb = new ByteBuffer(0, littleEndian, noAssert); - if (buffer.length > 0) { // Avoid references to more than one EMPTY_BUFFER - bb.buffer = buffer.buffer; - bb.offset = buffer.byteOffset; - bb.limit = buffer.byteOffset + buffer.length; - bb.view = buffer.length > 0 ? new DataView(buffer.buffer) : null; - } - } else if (buffer instanceof ArrayBuffer) { // Reuse ArrayBuffer - bb = new ByteBuffer(0, littleEndian, noAssert); - if (buffer.byteLength > 0) { - bb.buffer = buffer; - bb.offset = 0; - bb.limit = buffer.byteLength; - bb.view = buffer.byteLength > 0 ? new DataView(buffer) : null; - } - } else if (Object.prototype.toString.call(buffer) === "[object Array]") { // Create from octets - bb = new ByteBuffer(buffer.length, littleEndian, noAssert); - bb.limit = buffer.length; - for (i=0; i + Copyright 2009 The Closure Library Authors. All Rights Reserved. + + 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 long.js (c) 2013 Daniel Wirtz + * Released under the Apache License, Version 2.0 + * see: https://github.com/dcodeIO/long.js for details + */ +(function(global, factory) { + + /* AMD */ if (typeof define === 'function' && define["amd"]) + define([], factory); + /* CommonJS */ else if (typeof require === 'function' && typeof module === "object" && module && module["exports"]) + module["exports"] = factory(); + /* Global */ else + (global["dcodeIO"] = global["dcodeIO"] || {})["Long"] = factory(); + +})(this, function() { + "use strict"; + + /** + * Constructs a 64 bit two's-complement integer, given its low and high 32 bit values as *signed* integers. + * See the from* functions below for more convenient ways of constructing Longs. + * @exports Long + * @class A Long class for representing a 64 bit two's-complement integer value. + * @param {number} low The low (signed) 32 bits of the long + * @param {number} high The high (signed) 32 bits of the long + * @param {boolean=} unsigned Whether unsigned or not, defaults to `false` for signed + * @constructor + */ + function Long(low, high, unsigned) { + + /** + * The low 32 bits as a signed value. + * @type {number} + * @expose + */ + this.low = low | 0; + + /** + * The high 32 bits as a signed value. + * @type {number} + * @expose + */ + this.high = high | 0; + + /** + * Whether unsigned or not. + * @type {boolean} + * @expose + */ + this.unsigned = !!unsigned; + } + + // The internal representation of a long is the two given signed, 32-bit values. + // We use 32-bit pieces because these are the size of integers on which + // Javascript performs bit-operations. For operations like addition and + // multiplication, we split each number into 16 bit pieces, which can easily be + // multiplied within Javascript's floating-point representation without overflow + // or change in sign. + // + // In the algorithms below, we frequently reduce the negative case to the + // positive case by negating the input(s) and then post-processing the result. + // Note that we must ALWAYS check specially whether those values are MIN_VALUE + // (-2^63) because -MIN_VALUE == MIN_VALUE (since 2^63 cannot be represented as + // a positive number, it overflows back into a negative). Not handling this + // case would often result in infinite recursion. + // + // Common constant values ZERO, ONE, NEG_ONE, etc. are defined below the from* + // methods on which they depend. + + /** + * An indicator used to reliably determine if an object is a Long or not. + * @type {boolean} + * @const + * @expose + * @private + */ + Long.__isLong__; + + Object.defineProperty(Long.prototype, "__isLong__", { + value: true, + enumerable: false, + configurable: false + }); + + /** + * @function + * @param {*} obj Object + * @returns {boolean} + * @inner + */ + function isLong(obj) { + return (obj && obj["__isLong__"]) === true; + } + + /** + * Tests if the specified object is a Long. + * @function + * @param {*} obj Object + * @returns {boolean} + * @expose + */ + Long.isLong = isLong; + + /** + * A cache of the Long representations of small integer values. + * @type {!Object} + * @inner + */ + var INT_CACHE = {}; + + /** + * A cache of the Long representations of small unsigned integer values. + * @type {!Object} + * @inner + */ + var UINT_CACHE = {}; + + /** + * @param {number} value + * @param {boolean=} unsigned + * @returns {!Long} + * @inner + */ + function fromInt(value, unsigned) { + var obj, cachedObj, cache; + if (unsigned) { + value >>>= 0; + if (cache = (0 <= value && value < 256)) { + cachedObj = UINT_CACHE[value]; + if (cachedObj) + return cachedObj; + } + obj = fromBits(value, (value | 0) < 0 ? -1 : 0, true); + if (cache) + UINT_CACHE[value] = obj; + return obj; + } else { + value |= 0; + if (cache = (-128 <= value && value < 128)) { + cachedObj = INT_CACHE[value]; + if (cachedObj) + return cachedObj; + } + obj = fromBits(value, value < 0 ? -1 : 0, false); + if (cache) + INT_CACHE[value] = obj; + return obj; + } + } + + /** + * Returns a Long representing the given 32 bit integer value. + * @function + * @param {number} value The 32 bit integer in question + * @param {boolean=} unsigned Whether unsigned or not, defaults to `false` for signed + * @returns {!Long} The corresponding Long value + * @expose + */ + Long.fromInt = fromInt; + + /** + * @param {number} value + * @param {boolean=} unsigned + * @returns {!Long} + * @inner + */ + function fromNumber(value, unsigned) { + if (isNaN(value) || !isFinite(value)) + return unsigned ? UZERO : ZERO; + if (unsigned) { + if (value < 0) + return UZERO; + if (value >= TWO_PWR_64_DBL) + return MAX_UNSIGNED_VALUE; + } else { + if (value <= -TWO_PWR_63_DBL) + return MIN_VALUE; + if (value + 1 >= TWO_PWR_63_DBL) + return MAX_VALUE; + } + if (value < 0) + return fromNumber(-value, unsigned).neg(); + return fromBits((value % TWO_PWR_32_DBL) | 0, (value / TWO_PWR_32_DBL) | 0, unsigned); + } + + /** + * Returns a Long representing the given value, provided that it is a finite number. Otherwise, zero is returned. + * @function + * @param {number} value The number in question + * @param {boolean=} unsigned Whether unsigned or not, defaults to `false` for signed + * @returns {!Long} The corresponding Long value + * @expose + */ + Long.fromNumber = fromNumber; + + /** + * @param {number} lowBits + * @param {number} highBits + * @param {boolean=} unsigned + * @returns {!Long} + * @inner + */ + function fromBits(lowBits, highBits, unsigned) { + return new Long(lowBits, highBits, unsigned); + } + + /** + * Returns a Long representing the 64 bit integer that comes by concatenating the given low and high bits. Each is + * assumed to use 32 bits. + * @function + * @param {number} lowBits The low 32 bits + * @param {number} highBits The high 32 bits + * @param {boolean=} unsigned Whether unsigned or not, defaults to `false` for signed + * @returns {!Long} The corresponding Long value + * @expose + */ + Long.fromBits = fromBits; + + /** + * @function + * @param {number} base + * @param {number} exponent + * @returns {number} + * @inner + */ + var pow_dbl = Math.pow; // Used 4 times (4*8 to 15+4) + + /** + * @param {string} str + * @param {(boolean|number)=} unsigned + * @param {number=} radix + * @returns {!Long} + * @inner + */ + function fromString(str, unsigned, radix) { + if (str.length === 0) + throw Error('empty string'); + if (str === "NaN" || str === "Infinity" || str === "+Infinity" || str === "-Infinity") + return ZERO; + if (typeof unsigned === 'number') { + // For goog.math.long compatibility + radix = unsigned, + unsigned = false; + } else { + unsigned = !! unsigned; + } + radix = radix || 10; + if (radix < 2 || 36 < radix) + throw RangeError('radix'); + + var p; + if ((p = str.indexOf('-')) > 0) + throw Error('interior hyphen'); + else if (p === 0) { + return fromString(str.substring(1), unsigned, radix).neg(); + } + + // Do several (8) digits each time through the loop, so as to + // minimize the calls to the very expensive emulated div. + var radixToPower = fromNumber(pow_dbl(radix, 8)); + + var result = ZERO; + for (var i = 0; i < str.length; i += 8) { + var size = Math.min(8, str.length - i), + value = parseInt(str.substring(i, i + size), radix); + if (size < 8) { + var power = fromNumber(pow_dbl(radix, size)); + result = result.mul(power).add(fromNumber(value)); + } else { + result = result.mul(radixToPower); + result = result.add(fromNumber(value)); + } + } + result.unsigned = unsigned; + return result; + } + + /** + * Returns a Long representation of the given string, written using the specified radix. + * @function + * @param {string} str The textual representation of the Long + * @param {(boolean|number)=} unsigned Whether unsigned or not, defaults to `false` for signed + * @param {number=} radix The radix in which the text is written (2-36), defaults to 10 + * @returns {!Long} The corresponding Long value + * @expose + */ + Long.fromString = fromString; + + /** + * @function + * @param {!Long|number|string|!{low: number, high: number, unsigned: boolean}} val + * @returns {!Long} + * @inner + */ + function fromValue(val) { + if (val /* is compatible */ instanceof Long) + return val; + if (typeof val === 'number') + return fromNumber(val); + if (typeof val === 'string') + return fromString(val); + // Throws for non-objects, converts non-instanceof Long: + return fromBits(val.low, val.high, val.unsigned); + } + + /** + * Converts the specified value to a Long. + * @function + * @param {!Long|number|string|!{low: number, high: number, unsigned: boolean}} val Value + * @returns {!Long} + * @expose + */ + Long.fromValue = fromValue; + + // NOTE: the compiler should inline these constant values below and then remove these variables, so there should be + // no runtime penalty for these. + + /** + * @type {number} + * @const + * @inner + */ + var TWO_PWR_16_DBL = 1 << 16; + + /** + * @type {number} + * @const + * @inner + */ + var TWO_PWR_24_DBL = 1 << 24; + + /** + * @type {number} + * @const + * @inner + */ + var TWO_PWR_32_DBL = TWO_PWR_16_DBL * TWO_PWR_16_DBL; + + /** + * @type {number} + * @const + * @inner + */ + var TWO_PWR_64_DBL = TWO_PWR_32_DBL * TWO_PWR_32_DBL; + + /** + * @type {number} + * @const + * @inner + */ + var TWO_PWR_63_DBL = TWO_PWR_64_DBL / 2; + + /** + * @type {!Long} + * @const + * @inner + */ + var TWO_PWR_24 = fromInt(TWO_PWR_24_DBL); + + /** + * @type {!Long} + * @inner + */ + var ZERO = fromInt(0); + + /** + * Signed zero. + * @type {!Long} + * @expose + */ + Long.ZERO = ZERO; + + /** + * @type {!Long} + * @inner + */ + var UZERO = fromInt(0, true); + + /** + * Unsigned zero. + * @type {!Long} + * @expose + */ + Long.UZERO = UZERO; + + /** + * @type {!Long} + * @inner + */ + var ONE = fromInt(1); + + /** + * Signed one. + * @type {!Long} + * @expose + */ + Long.ONE = ONE; + + /** + * @type {!Long} + * @inner + */ + var UONE = fromInt(1, true); + + /** + * Unsigned one. + * @type {!Long} + * @expose + */ + Long.UONE = UONE; + + /** + * @type {!Long} + * @inner + */ + var NEG_ONE = fromInt(-1); + + /** + * Signed negative one. + * @type {!Long} + * @expose + */ + Long.NEG_ONE = NEG_ONE; + + /** + * @type {!Long} + * @inner + */ + var MAX_VALUE = fromBits(0xFFFFFFFF|0, 0x7FFFFFFF|0, false); + + /** + * Maximum signed value. + * @type {!Long} + * @expose + */ + Long.MAX_VALUE = MAX_VALUE; + + /** + * @type {!Long} + * @inner + */ + var MAX_UNSIGNED_VALUE = fromBits(0xFFFFFFFF|0, 0xFFFFFFFF|0, true); + + /** + * Maximum unsigned value. + * @type {!Long} + * @expose + */ + Long.MAX_UNSIGNED_VALUE = MAX_UNSIGNED_VALUE; + + /** + * @type {!Long} + * @inner + */ + var MIN_VALUE = fromBits(0, 0x80000000|0, false); + + /** + * Minimum signed value. + * @type {!Long} + * @expose + */ + Long.MIN_VALUE = MIN_VALUE; + + /** + * @alias Long.prototype + * @inner + */ + var LongPrototype = Long.prototype; + + /** + * Converts the Long to a 32 bit integer, assuming it is a 32 bit integer. + * @returns {number} + * @expose + */ + LongPrototype.toInt = function toInt() { + return this.unsigned ? this.low >>> 0 : this.low; + }; + + /** + * Converts the Long to a the nearest floating-point representation of this value (double, 53 bit mantissa). + * @returns {number} + * @expose + */ + LongPrototype.toNumber = function toNumber() { + if (this.unsigned) + return ((this.high >>> 0) * TWO_PWR_32_DBL) + (this.low >>> 0); + return this.high * TWO_PWR_32_DBL + (this.low >>> 0); + }; + + /** + * Converts the Long to a string written in the specified radix. + * @param {number=} radix Radix (2-36), defaults to 10 + * @returns {string} + * @override + * @throws {RangeError} If `radix` is out of range + * @expose + */ + LongPrototype.toString = function toString(radix) { + radix = radix || 10; + if (radix < 2 || 36 < radix) + throw RangeError('radix'); + if (this.isZero()) + return '0'; + if (this.isNegative()) { // Unsigned Longs are never negative + if (this.eq(MIN_VALUE)) { + // We need to change the Long value before it can be negated, so we remove + // the bottom-most digit in this base and then recurse to do the rest. + var radixLong = fromNumber(radix), + div = this.div(radixLong), + rem1 = div.mul(radixLong).sub(this); + return div.toString(radix) + rem1.toInt().toString(radix); + } else + return '-' + this.neg().toString(radix); + } + + // Do several (6) digits each time through the loop, so as to + // minimize the calls to the very expensive emulated div. + var radixToPower = fromNumber(pow_dbl(radix, 6), this.unsigned), + rem = this; + var result = ''; + while (true) { + var remDiv = rem.div(radixToPower), + intval = rem.sub(remDiv.mul(radixToPower)).toInt() >>> 0, + digits = intval.toString(radix); + rem = remDiv; + if (rem.isZero()) + return digits + result; + else { + while (digits.length < 6) + digits = '0' + digits; + result = '' + digits + result; + } + } + }; + + /** + * Gets the high 32 bits as a signed integer. + * @returns {number} Signed high bits + * @expose + */ + LongPrototype.getHighBits = function getHighBits() { + return this.high; + }; + + /** + * Gets the high 32 bits as an unsigned integer. + * @returns {number} Unsigned high bits + * @expose + */ + LongPrototype.getHighBitsUnsigned = function getHighBitsUnsigned() { + return this.high >>> 0; + }; + + /** + * Gets the low 32 bits as a signed integer. + * @returns {number} Signed low bits + * @expose + */ + LongPrototype.getLowBits = function getLowBits() { + return this.low; + }; + + /** + * Gets the low 32 bits as an unsigned integer. + * @returns {number} Unsigned low bits + * @expose + */ + LongPrototype.getLowBitsUnsigned = function getLowBitsUnsigned() { + return this.low >>> 0; + }; + + /** + * Gets the number of bits needed to represent the absolute value of this Long. + * @returns {number} + * @expose + */ + LongPrototype.getNumBitsAbs = function getNumBitsAbs() { + if (this.isNegative()) // Unsigned Longs are never negative + return this.eq(MIN_VALUE) ? 64 : this.neg().getNumBitsAbs(); + var val = this.high != 0 ? this.high : this.low; + for (var bit = 31; bit > 0; bit--) + if ((val & (1 << bit)) != 0) + break; + return this.high != 0 ? bit + 33 : bit + 1; + }; + + /** + * Tests if this Long's value equals zero. + * @returns {boolean} + * @expose + */ + LongPrototype.isZero = function isZero() { + return this.high === 0 && this.low === 0; + }; + + /** + * Tests if this Long's value is negative. + * @returns {boolean} + * @expose + */ + LongPrototype.isNegative = function isNegative() { + return !this.unsigned && this.high < 0; + }; + + /** + * Tests if this Long's value is positive. + * @returns {boolean} + * @expose + */ + LongPrototype.isPositive = function isPositive() { + return this.unsigned || this.high >= 0; + }; + + /** + * Tests if this Long's value is odd. + * @returns {boolean} + * @expose + */ + LongPrototype.isOdd = function isOdd() { + return (this.low & 1) === 1; + }; + + /** + * Tests if this Long's value is even. + * @returns {boolean} + * @expose + */ + LongPrototype.isEven = function isEven() { + return (this.low & 1) === 0; + }; + + /** + * Tests if this Long's value equals the specified's. + * @param {!Long|number|string} other Other value + * @returns {boolean} + * @expose + */ + LongPrototype.equals = function equals(other) { + if (!isLong(other)) + other = fromValue(other); + if (this.unsigned !== other.unsigned && (this.high >>> 31) === 1 && (other.high >>> 31) === 1) + return false; + return this.high === other.high && this.low === other.low; + }; + + /** + * Tests if this Long's value equals the specified's. This is an alias of {@link Long#equals}. + * @function + * @param {!Long|number|string} other Other value + * @returns {boolean} + * @expose + */ + LongPrototype.eq = LongPrototype.equals; + + /** + * Tests if this Long's value differs from the specified's. + * @param {!Long|number|string} other Other value + * @returns {boolean} + * @expose + */ + LongPrototype.notEquals = function notEquals(other) { + return !this.eq(/* validates */ other); + }; + + /** + * Tests if this Long's value differs from the specified's. This is an alias of {@link Long#notEquals}. + * @function + * @param {!Long|number|string} other Other value + * @returns {boolean} + * @expose + */ + LongPrototype.neq = LongPrototype.notEquals; + + /** + * Tests if this Long's value is less than the specified's. + * @param {!Long|number|string} other Other value + * @returns {boolean} + * @expose + */ + LongPrototype.lessThan = function lessThan(other) { + return this.comp(/* validates */ other) < 0; + }; + + /** + * Tests if this Long's value is less than the specified's. This is an alias of {@link Long#lessThan}. + * @function + * @param {!Long|number|string} other Other value + * @returns {boolean} + * @expose + */ + LongPrototype.lt = LongPrototype.lessThan; + + /** + * Tests if this Long's value is less than or equal the specified's. + * @param {!Long|number|string} other Other value + * @returns {boolean} + * @expose + */ + LongPrototype.lessThanOrEqual = function lessThanOrEqual(other) { + return this.comp(/* validates */ other) <= 0; + }; + + /** + * Tests if this Long's value is less than or equal the specified's. This is an alias of {@link Long#lessThanOrEqual}. + * @function + * @param {!Long|number|string} other Other value + * @returns {boolean} + * @expose + */ + LongPrototype.lte = LongPrototype.lessThanOrEqual; + + /** + * Tests if this Long's value is greater than the specified's. + * @param {!Long|number|string} other Other value + * @returns {boolean} + * @expose + */ + LongPrototype.greaterThan = function greaterThan(other) { + return this.comp(/* validates */ other) > 0; + }; + + /** + * Tests if this Long's value is greater than the specified's. This is an alias of {@link Long#greaterThan}. + * @function + * @param {!Long|number|string} other Other value + * @returns {boolean} + * @expose + */ + LongPrototype.gt = LongPrototype.greaterThan; + + /** + * Tests if this Long's value is greater than or equal the specified's. + * @param {!Long|number|string} other Other value + * @returns {boolean} + * @expose + */ + LongPrototype.greaterThanOrEqual = function greaterThanOrEqual(other) { + return this.comp(/* validates */ other) >= 0; + }; + + /** + * Tests if this Long's value is greater than or equal the specified's. This is an alias of {@link Long#greaterThanOrEqual}. + * @function + * @param {!Long|number|string} other Other value + * @returns {boolean} + * @expose + */ + LongPrototype.gte = LongPrototype.greaterThanOrEqual; + + /** + * Compares this Long's value with the specified's. + * @param {!Long|number|string} other Other value + * @returns {number} 0 if they are the same, 1 if the this is greater and -1 + * if the given one is greater + * @expose + */ + LongPrototype.compare = function compare(other) { + if (!isLong(other)) + other = fromValue(other); + if (this.eq(other)) + return 0; + var thisNeg = this.isNegative(), + otherNeg = other.isNegative(); + if (thisNeg && !otherNeg) + return -1; + if (!thisNeg && otherNeg) + return 1; + // At this point the sign bits are the same + if (!this.unsigned) + return this.sub(other).isNegative() ? -1 : 1; + // Both are positive if at least one is unsigned + return (other.high >>> 0) > (this.high >>> 0) || (other.high === this.high && (other.low >>> 0) > (this.low >>> 0)) ? -1 : 1; + }; + + /** + * Compares this Long's value with the specified's. This is an alias of {@link Long#compare}. + * @function + * @param {!Long|number|string} other Other value + * @returns {number} 0 if they are the same, 1 if the this is greater and -1 + * if the given one is greater + * @expose + */ + LongPrototype.comp = LongPrototype.compare; + + /** + * Negates this Long's value. + * @returns {!Long} Negated Long + * @expose + */ + LongPrototype.negate = function negate() { + if (!this.unsigned && this.eq(MIN_VALUE)) + return MIN_VALUE; + return this.not().add(ONE); + }; + + /** + * Negates this Long's value. This is an alias of {@link Long#negate}. + * @function + * @returns {!Long} Negated Long + * @expose + */ + LongPrototype.neg = LongPrototype.negate; + + /** + * Returns the sum of this and the specified Long. + * @param {!Long|number|string} addend Addend + * @returns {!Long} Sum + * @expose + */ + LongPrototype.add = function add(addend) { + if (!isLong(addend)) + addend = fromValue(addend); + + // Divide each number into 4 chunks of 16 bits, and then sum the chunks. + + var a48 = this.high >>> 16; + var a32 = this.high & 0xFFFF; + var a16 = this.low >>> 16; + var a00 = this.low & 0xFFFF; + + var b48 = addend.high >>> 16; + var b32 = addend.high & 0xFFFF; + var b16 = addend.low >>> 16; + var b00 = addend.low & 0xFFFF; + + var c48 = 0, c32 = 0, c16 = 0, c00 = 0; + c00 += a00 + b00; + c16 += c00 >>> 16; + c00 &= 0xFFFF; + c16 += a16 + b16; + c32 += c16 >>> 16; + c16 &= 0xFFFF; + c32 += a32 + b32; + c48 += c32 >>> 16; + c32 &= 0xFFFF; + c48 += a48 + b48; + c48 &= 0xFFFF; + return fromBits((c16 << 16) | c00, (c48 << 16) | c32, this.unsigned); + }; + + /** + * Returns the difference of this and the specified Long. + * @param {!Long|number|string} subtrahend Subtrahend + * @returns {!Long} Difference + * @expose + */ + LongPrototype.subtract = function subtract(subtrahend) { + if (!isLong(subtrahend)) + subtrahend = fromValue(subtrahend); + return this.add(subtrahend.neg()); + }; + + /** + * Returns the difference of this and the specified Long. This is an alias of {@link Long#subtract}. + * @function + * @param {!Long|number|string} subtrahend Subtrahend + * @returns {!Long} Difference + * @expose + */ + LongPrototype.sub = LongPrototype.subtract; + + /** + * Returns the product of this and the specified Long. + * @param {!Long|number|string} multiplier Multiplier + * @returns {!Long} Product + * @expose + */ + LongPrototype.multiply = function multiply(multiplier) { + if (this.isZero()) + return ZERO; + if (!isLong(multiplier)) + multiplier = fromValue(multiplier); + if (multiplier.isZero()) + return ZERO; + if (this.eq(MIN_VALUE)) + return multiplier.isOdd() ? MIN_VALUE : ZERO; + if (multiplier.eq(MIN_VALUE)) + return this.isOdd() ? MIN_VALUE : ZERO; + + if (this.isNegative()) { + if (multiplier.isNegative()) + return this.neg().mul(multiplier.neg()); + else + return this.neg().mul(multiplier).neg(); + } else if (multiplier.isNegative()) + return this.mul(multiplier.neg()).neg(); + + // If both longs are small, use float multiplication + if (this.lt(TWO_PWR_24) && multiplier.lt(TWO_PWR_24)) + return fromNumber(this.toNumber() * multiplier.toNumber(), this.unsigned); + + // Divide each long into 4 chunks of 16 bits, and then add up 4x4 products. + // We can skip products that would overflow. + + var a48 = this.high >>> 16; + var a32 = this.high & 0xFFFF; + var a16 = this.low >>> 16; + var a00 = this.low & 0xFFFF; + + var b48 = multiplier.high >>> 16; + var b32 = multiplier.high & 0xFFFF; + var b16 = multiplier.low >>> 16; + var b00 = multiplier.low & 0xFFFF; + + var c48 = 0, c32 = 0, c16 = 0, c00 = 0; + c00 += a00 * b00; + c16 += c00 >>> 16; + c00 &= 0xFFFF; + c16 += a16 * b00; + c32 += c16 >>> 16; + c16 &= 0xFFFF; + c16 += a00 * b16; + c32 += c16 >>> 16; + c16 &= 0xFFFF; + c32 += a32 * b00; + c48 += c32 >>> 16; + c32 &= 0xFFFF; + c32 += a16 * b16; + c48 += c32 >>> 16; + c32 &= 0xFFFF; + c32 += a00 * b32; + c48 += c32 >>> 16; + c32 &= 0xFFFF; + c48 += a48 * b00 + a32 * b16 + a16 * b32 + a00 * b48; + c48 &= 0xFFFF; + return fromBits((c16 << 16) | c00, (c48 << 16) | c32, this.unsigned); + }; + + /** + * Returns the product of this and the specified Long. This is an alias of {@link Long#multiply}. + * @function + * @param {!Long|number|string} multiplier Multiplier + * @returns {!Long} Product + * @expose + */ + LongPrototype.mul = LongPrototype.multiply; + + /** + * Returns this Long divided by the specified. The result is signed if this Long is signed or + * unsigned if this Long is unsigned. + * @param {!Long|number|string} divisor Divisor + * @returns {!Long} Quotient + * @expose + */ + LongPrototype.divide = function divide(divisor) { + if (!isLong(divisor)) + divisor = fromValue(divisor); + if (divisor.isZero()) + throw Error('division by zero'); + if (this.isZero()) + return this.unsigned ? UZERO : ZERO; + var approx, rem, res; + if (!this.unsigned) { + if (this.eq(MIN_VALUE)) { + if (divisor.eq(ONE) || divisor.eq(NEG_ONE)) + return MIN_VALUE; // recall that -MIN_VALUE == MIN_VALUE + else if (divisor.eq(MIN_VALUE)) + return ONE; + else { + // At this point, we have |other| >= 2, so |this/other| < |MIN_VALUE|. + var halfThis = this.shr(1); + approx = halfThis.div(divisor).shl(1); + if (approx.eq(ZERO)) { + return divisor.isNegative() ? ONE : NEG_ONE; + } else { + rem = this.sub(divisor.mul(approx)); + res = approx.add(rem.div(divisor)); + return res; + } + } + } else if (divisor.eq(MIN_VALUE)) + return this.unsigned ? UZERO : ZERO; + if (this.isNegative()) { + if (divisor.isNegative()) + return this.neg().div(divisor.neg()); + return this.neg().div(divisor).neg(); + } else if (divisor.isNegative()) + return this.div(divisor.neg()).neg(); + } else if (!divisor.unsigned) + divisor = divisor.toUnsigned(); + + // The algorithm below has not been made for unsigned longs. It's therefore + // required to take special care of the MSB prior to running it. + if (this.unsigned) { + if (divisor.gt(this)) + return UZERO; + if (divisor.gt(this.shru(1))) // 15 >>> 1 = 7 ; with divisor = 8 ; true + return UONE; + res = UZERO; + } else + res = ZERO; + + // Repeat the following until the remainder is less than other: find a + // floating-point that approximates remainder / other *from below*, add this + // into the result, and subtract it from the remainder. It is critical that + // the approximate value is less than or equal to the real value so that the + // remainder never becomes negative. + rem = this; + while (rem.gte(divisor)) { + // Approximate the result of division. This may be a little greater or + // smaller than the actual value. + approx = Math.max(1, Math.floor(rem.toNumber() / divisor.toNumber())); + + // We will tweak the approximate result by changing it in the 48-th digit or + // the smallest non-fractional digit, whichever is larger. + var log2 = Math.ceil(Math.log(approx) / Math.LN2), + delta = (log2 <= 48) ? 1 : pow_dbl(2, log2 - 48), + + // Decrease the approximation until it is smaller than the remainder. Note + // that if it is too large, the product overflows and is negative. + approxRes = fromNumber(approx), + approxRem = approxRes.mul(divisor); + while (approxRem.isNegative() || approxRem.gt(rem)) { + approx -= delta; + approxRes = fromNumber(approx, this.unsigned); + approxRem = approxRes.mul(divisor); + } + + // We know the answer can't be zero... and actually, zero would cause + // infinite recursion since we would make no progress. + if (approxRes.isZero()) + approxRes = ONE; + + res = res.add(approxRes); + rem = rem.sub(approxRem); + } + return res; + }; + + /** + * Returns this Long divided by the specified. This is an alias of {@link Long#divide}. + * @function + * @param {!Long|number|string} divisor Divisor + * @returns {!Long} Quotient + * @expose + */ + LongPrototype.div = LongPrototype.divide; + + /** + * Returns this Long modulo the specified. + * @param {!Long|number|string} divisor Divisor + * @returns {!Long} Remainder + * @expose + */ + LongPrototype.modulo = function modulo(divisor) { + if (!isLong(divisor)) + divisor = fromValue(divisor); + return this.sub(this.div(divisor).mul(divisor)); + }; + + /** + * Returns this Long modulo the specified. This is an alias of {@link Long#modulo}. + * @function + * @param {!Long|number|string} divisor Divisor + * @returns {!Long} Remainder + * @expose + */ + LongPrototype.mod = LongPrototype.modulo; + + /** + * Returns the bitwise NOT of this Long. + * @returns {!Long} + * @expose + */ + LongPrototype.not = function not() { + return fromBits(~this.low, ~this.high, this.unsigned); + }; + + /** + * Returns the bitwise AND of this Long and the specified. + * @param {!Long|number|string} other Other Long + * @returns {!Long} + * @expose + */ + LongPrototype.and = function and(other) { + if (!isLong(other)) + other = fromValue(other); + return fromBits(this.low & other.low, this.high & other.high, this.unsigned); + }; + + /** + * Returns the bitwise OR of this Long and the specified. + * @param {!Long|number|string} other Other Long + * @returns {!Long} + * @expose + */ + LongPrototype.or = function or(other) { + if (!isLong(other)) + other = fromValue(other); + return fromBits(this.low | other.low, this.high | other.high, this.unsigned); + }; + + /** + * Returns the bitwise XOR of this Long and the given one. + * @param {!Long|number|string} other Other Long + * @returns {!Long} + * @expose + */ + LongPrototype.xor = function xor(other) { + if (!isLong(other)) + other = fromValue(other); + return fromBits(this.low ^ other.low, this.high ^ other.high, this.unsigned); + }; + + /** + * Returns this Long with bits shifted to the left by the given amount. + * @param {number|!Long} numBits Number of bits + * @returns {!Long} Shifted Long + * @expose + */ + LongPrototype.shiftLeft = function shiftLeft(numBits) { + if (isLong(numBits)) + numBits = numBits.toInt(); + if ((numBits &= 63) === 0) + return this; + else if (numBits < 32) + return fromBits(this.low << numBits, (this.high << numBits) | (this.low >>> (32 - numBits)), this.unsigned); + else + return fromBits(0, this.low << (numBits - 32), this.unsigned); + }; + + /** + * Returns this Long with bits shifted to the left by the given amount. This is an alias of {@link Long#shiftLeft}. + * @function + * @param {number|!Long} numBits Number of bits + * @returns {!Long} Shifted Long + * @expose + */ + LongPrototype.shl = LongPrototype.shiftLeft; + + /** + * Returns this Long with bits arithmetically shifted to the right by the given amount. + * @param {number|!Long} numBits Number of bits + * @returns {!Long} Shifted Long + * @expose + */ + LongPrototype.shiftRight = function shiftRight(numBits) { + if (isLong(numBits)) + numBits = numBits.toInt(); + if ((numBits &= 63) === 0) + return this; + else if (numBits < 32) + return fromBits((this.low >>> numBits) | (this.high << (32 - numBits)), this.high >> numBits, this.unsigned); + else + return fromBits(this.high >> (numBits - 32), this.high >= 0 ? 0 : -1, this.unsigned); + }; + + /** + * Returns this Long with bits arithmetically shifted to the right by the given amount. This is an alias of {@link Long#shiftRight}. + * @function + * @param {number|!Long} numBits Number of bits + * @returns {!Long} Shifted Long + * @expose + */ + LongPrototype.shr = LongPrototype.shiftRight; + + /** + * Returns this Long with bits logically shifted to the right by the given amount. + * @param {number|!Long} numBits Number of bits + * @returns {!Long} Shifted Long + * @expose + */ + LongPrototype.shiftRightUnsigned = function shiftRightUnsigned(numBits) { + if (isLong(numBits)) + numBits = numBits.toInt(); + numBits &= 63; + if (numBits === 0) + return this; + else { + var high = this.high; + if (numBits < 32) { + var low = this.low; + return fromBits((low >>> numBits) | (high << (32 - numBits)), high >>> numBits, this.unsigned); + } else if (numBits === 32) + return fromBits(high, 0, this.unsigned); + else + return fromBits(high >>> (numBits - 32), 0, this.unsigned); + } + }; + + /** + * Returns this Long with bits logically shifted to the right by the given amount. This is an alias of {@link Long#shiftRightUnsigned}. + * @function + * @param {number|!Long} numBits Number of bits + * @returns {!Long} Shifted Long + * @expose + */ + LongPrototype.shru = LongPrototype.shiftRightUnsigned; + + /** + * Converts this Long to signed. + * @returns {!Long} Signed long + * @expose + */ + LongPrototype.toSigned = function toSigned() { + if (!this.unsigned) + return this; + return fromBits(this.low, this.high, false); + }; + + /** + * Converts this Long to unsigned. + * @returns {!Long} Unsigned long + * @expose + */ + LongPrototype.toUnsigned = function toUnsigned() { + if (this.unsigned) + return this; + return fromBits(this.low, this.high, true); + }; + + return Long; +}); + +/* + Copyright 2013-2014 Daniel Wirtz + + 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 + * This version of ByteBuffer.js uses an ArrayBuffer as its backing buffer which is accessed through a DataView and is + * compatible with modern browsers. + * Released under the Apache License, Version 2.0 + * see: https://github.com/dcodeIO/ByteBuffer.js for details + */ // +(function(global) { + "use strict"; + + /** + * @param {function(new: Long, number, number, boolean=)=} Long + * @returns {function(new: ByteBuffer, number=, boolean=, boolean=)}} + * @inner + */ + function loadByteBuffer(Long) { + + /** + * 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 RangeError("Illegal capacity"); + littleEndian = !!littleEndian; + noAssert = !!noAssert; + } + + /** + * Backing buffer. + * @type {!ArrayBuffer} + * @expose + */ + this.buffer = capacity === 0 ? EMPTY_BUFFER : new ArrayBuffer(capacity); + + /** + * Data view to manipulate the backing buffer. Becomes `null` if the backing buffer has a capacity of `0`. + * @type {?DataView} + * @expose + */ + this.view = capacity === 0 ? null : new DataView(this.buffer); + + /** + * 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.5.5"; + + /** + * 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. May be `null` if Long.js has not been loaded + * and int64 support is not available. + * @type {?Long} + * @const + * @see https://github.com/dcodeIO/Long.js + * @expose + */ + ByteBuffer.Long = Long || null; + + /** + * @alias ByteBuffer.prototype + * @inner + */ + var ByteBufferPrototype = ByteBuffer.prototype; + + // helpers + + /** + * @type {!ArrayBuffer} + * @inner + */ + var EMPTY_BUFFER = new ArrayBuffer(0); + + /** + * String.fromCharCode reference for compile-time renaming. + * @type {function(...number):string} + * @inner + */ + var stringFromCharCode = String.fromCharCode; + + /** + * Creates a source function for a string. + * @param {string} s String to read from + * @returns {function():number|null} Source function returning the next char code respectively `null` if there are + * no more characters left. + * @throws {TypeError} If the argument is invalid + * @inner + */ + function stringSource(s) { + var i=0; return function() { + return i < s.length ? s.charCodeAt(i++) : null; + }; + } + + /** + * Creates a destination function for a string. + * @returns {function(number=):undefined|string} Destination function successively called with the next char code. + * Returns the final string when called without arguments. + * @inner + */ + function stringDestination() { + var cs = [], ps = []; return function() { + if (arguments.length === 0) + return ps.join('')+stringFromCharCode.apply(String, cs); + if (cs.length + arguments.length > 1024) + ps.push(stringFromCharCode.apply(String, cs)), + cs.length = 0; + Array.prototype.push.apply(cs, arguments); + }; + } + + /** + * 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.} 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 0) capacity += length; + } + if (capacity === 0) + return new ByteBuffer(0, littleEndian, noAssert); + var bb = new ByteBuffer(capacity, littleEndian, noAssert), + bi; + var view = new Uint8Array(bb.buffer); + i=0; while (i} 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 Error("Unsupported encoding: "+encoding); + } + } + if (buffer === null || typeof buffer !== 'object') + throw TypeError("Illegal buffer"); + var bb; + if (ByteBuffer.isByteBuffer(buffer)) { + bb = ByteBufferPrototype.clone.call(buffer); + bb.markedOffset = -1; + return bb; + } + if (buffer instanceof Uint8Array) { // Extract ArrayBuffer from Uint8Array + bb = new ByteBuffer(0, littleEndian, noAssert); + if (buffer.length > 0) { // Avoid references to more than one EMPTY_BUFFER + bb.buffer = buffer.buffer; + bb.offset = buffer.byteOffset; + bb.limit = buffer.byteOffset + buffer.length; + bb.view = buffer.length > 0 ? new DataView(buffer.buffer) : null; + } + } else if (buffer instanceof ArrayBuffer) { // Reuse ArrayBuffer + bb = new ByteBuffer(0, littleEndian, noAssert); + if (buffer.byteLength > 0) { + bb.buffer = buffer; + bb.offset = 0; + bb.limit = buffer.byteLength; + bb.view = buffer.byteLength > 0 ? new DataView(buffer) : null; + } + } else if (Object.prototype.toString.call(buffer) === "[object Array]") { // Create from octets + bb = new ByteBuffer(buffer.length, littleEndian, noAssert); + bb.limit = buffer.length; + for (i=0; i>>= 0; if (offset < 0 || offset + 0 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.byteLength); - } + } offset += 1; var capacity0 = this.buffer.byteLength; if (offset > capacity0) this.resize((capacity0 *= 2) > offset ? capacity0 : offset); offset -= 1; - this.view.setInt8(offset, value); + this.view.setInt8(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 - */ - ByteBufferPrototype.writeByte = ByteBufferPrototype.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 - */ - ByteBufferPrototype.readInt8 = function(offset) { + 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 + */ + ByteBufferPrototype.writeByte = ByteBufferPrototype.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 + */ + ByteBufferPrototype.readInt8 = function(offset) { var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; - if (!this.noAssert) { + if (!this.noAssert) { if (typeof offset !== 'number' || offset % 1 !== 0) throw TypeError("Illegal offset: "+offset+" (not an integer)"); offset >>>= 0; if (offset < 0 || offset + 1 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= "+offset+" (+"+1+") <= "+this.buffer.byteLength); - } - var value = this.view.getInt8(offset); + } + var value = this.view.getInt8(offset); 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 - */ - ByteBufferPrototype.readByte = ByteBufferPrototype.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 - */ - ByteBufferPrototype.writeUint8 = function(value, offset) { + 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 + */ + ByteBufferPrototype.readByte = ByteBufferPrototype.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 + */ + ByteBufferPrototype.writeUint8 = function(value, offset) { var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; - if (!this.noAssert) { + if (!this.noAssert) { if (typeof value !== 'number' || value % 1 !== 0) throw TypeError("Illegal value: "+value+" (not an integer)"); value >>>= 0; @@ -27050,52 +27036,52 @@ Curve25519Worker.prototype = { offset >>>= 0; if (offset < 0 || offset + 0 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.byteLength); - } + } offset += 1; var capacity1 = this.buffer.byteLength; if (offset > capacity1) this.resize((capacity1 *= 2) > offset ? capacity1 : offset); offset -= 1; - this.view.setUint8(offset, value); + this.view.setUint8(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 - */ - ByteBufferPrototype.readUint8 = function(offset) { + 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 + */ + ByteBufferPrototype.readUint8 = function(offset) { var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; - if (!this.noAssert) { + if (!this.noAssert) { if (typeof offset !== 'number' || offset % 1 !== 0) throw TypeError("Illegal offset: "+offset+" (not an integer)"); offset >>>= 0; if (offset < 0 || offset + 1 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= "+offset+" (+"+1+") <= "+this.buffer.byteLength); - } - var value = this.view.getUint8(offset); + } + var value = this.view.getUint8(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 - */ - ByteBufferPrototype.writeInt16 = function(value, offset) { + 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 + */ + ByteBufferPrototype.writeInt16 = function(value, offset) { var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; - if (!this.noAssert) { + if (!this.noAssert) { if (typeof value !== 'number' || value % 1 !== 0) throw TypeError("Illegal value: "+value+" (not an integer)"); value |= 0; @@ -27104,74 +27090,74 @@ Curve25519Worker.prototype = { offset >>>= 0; if (offset < 0 || offset + 0 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.byteLength); - } + } offset += 2; var capacity2 = this.buffer.byteLength; if (offset > capacity2) this.resize((capacity2 *= 2) > offset ? capacity2 : offset); offset -= 2; - this.view.setInt16(offset, value, this.littleEndian); + this.view.setInt16(offset, value, this.littleEndian); 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 - */ - ByteBufferPrototype.writeShort = ByteBufferPrototype.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 - */ - ByteBufferPrototype.readInt16 = function(offset) { + 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 + */ + ByteBufferPrototype.writeShort = ByteBufferPrototype.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 + */ + ByteBufferPrototype.readInt16 = function(offset) { var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; - if (!this.noAssert) { + if (!this.noAssert) { if (typeof offset !== 'number' || offset % 1 !== 0) throw TypeError("Illegal offset: "+offset+" (not an integer)"); offset >>>= 0; if (offset < 0 || offset + 2 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= "+offset+" (+"+2+") <= "+this.buffer.byteLength); - } - var value = this.view.getInt16(offset, this.littleEndian); + } + var value = this.view.getInt16(offset, this.littleEndian); 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 - */ - ByteBufferPrototype.readShort = ByteBufferPrototype.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 - */ - ByteBufferPrototype.writeUint16 = function(value, offset) { + 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 + */ + ByteBufferPrototype.readShort = ByteBufferPrototype.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 + */ + ByteBufferPrototype.writeUint16 = function(value, offset) { var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; - if (!this.noAssert) { + if (!this.noAssert) { if (typeof value !== 'number' || value % 1 !== 0) throw TypeError("Illegal value: "+value+" (not an integer)"); value >>>= 0; @@ -27180,52 +27166,52 @@ Curve25519Worker.prototype = { offset >>>= 0; if (offset < 0 || offset + 0 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.byteLength); - } + } offset += 2; var capacity3 = this.buffer.byteLength; if (offset > capacity3) this.resize((capacity3 *= 2) > offset ? capacity3 : offset); offset -= 2; - this.view.setUint16(offset, value, this.littleEndian); + this.view.setUint16(offset, value, this.littleEndian); 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 - */ - ByteBufferPrototype.readUint16 = function(offset) { + 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 + */ + ByteBufferPrototype.readUint16 = function(offset) { var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; - if (!this.noAssert) { + if (!this.noAssert) { if (typeof offset !== 'number' || offset % 1 !== 0) throw TypeError("Illegal offset: "+offset+" (not an integer)"); offset >>>= 0; if (offset < 0 || offset + 2 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= "+offset+" (+"+2+") <= "+this.buffer.byteLength); - } - var value = this.view.getUint16(offset, this.littleEndian); + } + var value = this.view.getUint16(offset, this.littleEndian); 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 - */ - ByteBufferPrototype.writeInt32 = function(value, offset) { + 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 + */ + ByteBufferPrototype.writeInt32 = function(value, offset) { var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; - if (!this.noAssert) { + if (!this.noAssert) { if (typeof value !== 'number' || value % 1 !== 0) throw TypeError("Illegal value: "+value+" (not an integer)"); value |= 0; @@ -27234,64 +27220,64 @@ Curve25519Worker.prototype = { offset >>>= 0; if (offset < 0 || offset + 0 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.byteLength); - } + } offset += 4; var capacity4 = this.buffer.byteLength; if (offset > capacity4) this.resize((capacity4 *= 2) > offset ? capacity4 : offset); offset -= 4; - this.view.setInt32(offset, value, this.littleEndian); + this.view.setInt32(offset, value, this.littleEndian); 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 - */ - ByteBufferPrototype.writeInt = ByteBufferPrototype.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 - */ - ByteBufferPrototype.readInt32 = function(offset) { + 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 + */ + ByteBufferPrototype.writeInt = ByteBufferPrototype.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 + */ + ByteBufferPrototype.readInt32 = function(offset) { var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; - if (!this.noAssert) { + if (!this.noAssert) { if (typeof offset !== 'number' || offset % 1 !== 0) throw TypeError("Illegal offset: "+offset+" (not an integer)"); offset >>>= 0; if (offset < 0 || offset + 4 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= "+offset+" (+"+4+") <= "+this.buffer.byteLength); - } - var value = this.view.getInt32(offset, this.littleEndian); + } + var value = this.view.getInt32(offset, this.littleEndian); 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 - */ - ByteBufferPrototype.readInt = ByteBufferPrototype.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 - */ - ByteBufferPrototype.writeUint32 = function(value, offset) { + 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 + */ + ByteBufferPrototype.readInt = ByteBufferPrototype.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 + */ + ByteBufferPrototype.writeUint32 = function(value, offset) { var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; - if (!this.noAssert) { + if (!this.noAssert) { if (typeof value !== 'number' || value % 1 !== 0) throw TypeError("Illegal value: "+value+" (not an integer)"); value >>>= 0; @@ -27300,53 +27286,53 @@ Curve25519Worker.prototype = { offset >>>= 0; if (offset < 0 || offset + 0 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.byteLength); - } + } offset += 4; var capacity5 = this.buffer.byteLength; if (offset > capacity5) this.resize((capacity5 *= 2) > offset ? capacity5 : offset); offset -= 4; - this.view.setUint32(offset, value, this.littleEndian); + this.view.setUint32(offset, value, this.littleEndian); 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 - */ - ByteBufferPrototype.readUint32 = function(offset) { + 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 + */ + ByteBufferPrototype.readUint32 = function(offset) { var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; - if (!this.noAssert) { + if (!this.noAssert) { if (typeof offset !== 'number' || offset % 1 !== 0) throw TypeError("Illegal offset: "+offset+" (not an integer)"); offset >>>= 0; if (offset < 0 || offset + 4 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= "+offset+" (+"+4+") <= "+this.buffer.byteLength); - } - var value = this.view.getUint32(offset, this.littleEndian); + } + var value = this.view.getUint32(offset, this.littleEndian); 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 - */ - ByteBufferPrototype.writeInt64 = function(value, offset) { + 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 + */ + ByteBufferPrototype.writeInt64 = function(value, offset) { var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; - if (!this.noAssert) { + if (!this.noAssert) { if (typeof value === 'number') value = Long.fromNumber(value); else if (typeof value === 'string') @@ -27358,7 +27344,7 @@ Curve25519Worker.prototype = { offset >>>= 0; if (offset < 0 || offset + 0 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.byteLength); - } + } if (typeof value === 'number') value = Long.fromNumber(value); else if (typeof value === 'string') @@ -27368,68 +27354,68 @@ Curve25519Worker.prototype = { if (offset > capacity6) this.resize((capacity6 *= 2) > offset ? capacity6 : offset); offset -= 8; - if (this.littleEndian) { - this.view.setInt32(offset , value.low , true); - this.view.setInt32(offset+4, value.high, true); - } else { - this.view.setInt32(offset , value.high, false); - this.view.setInt32(offset+4, value.low , false); - } + if (this.littleEndian) { + this.view.setInt32(offset , value.low , true); + this.view.setInt32(offset+4, value.high, true); + } else { + this.view.setInt32(offset , value.high, false); + this.view.setInt32(offset+4, value.low , false); + } 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 - */ - ByteBufferPrototype.writeLong = ByteBufferPrototype.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 - */ - ByteBufferPrototype.readInt64 = function(offset) { + 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 + */ + ByteBufferPrototype.writeLong = ByteBufferPrototype.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 + */ + ByteBufferPrototype.readInt64 = function(offset) { var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; - if (!this.noAssert) { + if (!this.noAssert) { if (typeof offset !== 'number' || offset % 1 !== 0) throw TypeError("Illegal offset: "+offset+" (not an integer)"); offset >>>= 0; if (offset < 0 || offset + 8 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= "+offset+" (+"+8+") <= "+this.buffer.byteLength); - } - var value = this.littleEndian - ? new Long(this.view.getInt32(offset , true ), this.view.getInt32(offset+4, true ), false) - : new Long(this.view.getInt32(offset+4, false), this.view.getInt32(offset , false), false); + } + var value = this.littleEndian + ? new Long(this.view.getInt32(offset , true ), this.view.getInt32(offset+4, true ), false) + : new Long(this.view.getInt32(offset+4, false), this.view.getInt32(offset , false), 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 - */ - ByteBufferPrototype.readLong = ByteBufferPrototype.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 - */ - ByteBufferPrototype.writeUint64 = function(value, offset) { + 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 + */ + ByteBufferPrototype.readLong = ByteBufferPrototype.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 + */ + ByteBufferPrototype.writeUint64 = function(value, offset) { var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; - if (!this.noAssert) { + if (!this.noAssert) { if (typeof value === 'number') value = Long.fromNumber(value); else if (typeof value === 'string') @@ -27441,7 +27427,7 @@ Curve25519Worker.prototype = { offset >>>= 0; if (offset < 0 || offset + 0 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.byteLength); - } + } if (typeof value === 'number') value = Long.fromNumber(value); else if (typeof value === 'string') @@ -27451,244 +27437,244 @@ Curve25519Worker.prototype = { if (offset > capacity7) this.resize((capacity7 *= 2) > offset ? capacity7 : offset); offset -= 8; - if (this.littleEndian) { - this.view.setInt32(offset , value.low , true); - this.view.setInt32(offset+4, value.high, true); - } else { - this.view.setInt32(offset , value.high, false); - this.view.setInt32(offset+4, value.low , false); - } + if (this.littleEndian) { + this.view.setInt32(offset , value.low , true); + this.view.setInt32(offset+4, value.high, true); + } else { + this.view.setInt32(offset , value.high, false); + this.view.setInt32(offset+4, value.low , false); + } 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 - */ - ByteBufferPrototype.readUint64 = function(offset) { + 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 + */ + ByteBufferPrototype.readUint64 = function(offset) { var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; - if (!this.noAssert) { + if (!this.noAssert) { if (typeof offset !== 'number' || offset % 1 !== 0) throw TypeError("Illegal offset: "+offset+" (not an integer)"); offset >>>= 0; if (offset < 0 || offset + 8 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= "+offset+" (+"+8+") <= "+this.buffer.byteLength); - } - var value = this.littleEndian - ? new Long(this.view.getInt32(offset , true ), this.view.getInt32(offset+4, true ), true) - : new Long(this.view.getInt32(offset+4, false), this.view.getInt32(offset , false), true); + } + var value = this.littleEndian + ? new Long(this.view.getInt32(offset , true ), this.view.getInt32(offset+4, true ), true) + : new Long(this.view.getInt32(offset+4, false), this.view.getInt32(offset , false), 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 - */ - ByteBufferPrototype.writeFloat32 = function(value, offset) { + 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 + */ + ByteBufferPrototype.writeFloat32 = function(value, offset) { var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; - if (!this.noAssert) { - if (typeof value !== 'number') - throw TypeError("Illegal value: "+value+" (not a number)"); + if (!this.noAssert) { + if (typeof value !== 'number') + throw TypeError("Illegal value: "+value+" (not a number)"); if (typeof offset !== 'number' || offset % 1 !== 0) throw TypeError("Illegal offset: "+offset+" (not an integer)"); offset >>>= 0; if (offset < 0 || offset + 0 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.byteLength); - } + } offset += 4; var capacity8 = this.buffer.byteLength; if (offset > capacity8) this.resize((capacity8 *= 2) > offset ? capacity8 : offset); offset -= 4; - this.view.setFloat32(offset, value, this.littleEndian); + this.view.setFloat32(offset, value, this.littleEndian); 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 - */ - ByteBufferPrototype.writeFloat = ByteBufferPrototype.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 - */ - ByteBufferPrototype.readFloat32 = function(offset) { + 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 + */ + ByteBufferPrototype.writeFloat = ByteBufferPrototype.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 + */ + ByteBufferPrototype.readFloat32 = function(offset) { var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; - if (!this.noAssert) { + if (!this.noAssert) { if (typeof offset !== 'number' || offset % 1 !== 0) throw TypeError("Illegal offset: "+offset+" (not an integer)"); offset >>>= 0; if (offset < 0 || offset + 4 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= "+offset+" (+"+4+") <= "+this.buffer.byteLength); - } - var value = this.view.getFloat32(offset, this.littleEndian); + } + var value = this.view.getFloat32(offset, this.littleEndian); 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 - */ - ByteBufferPrototype.readFloat = ByteBufferPrototype.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 - */ - ByteBufferPrototype.writeFloat64 = function(value, offset) { + 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 + */ + ByteBufferPrototype.readFloat = ByteBufferPrototype.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 + */ + ByteBufferPrototype.writeFloat64 = function(value, offset) { var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; - if (!this.noAssert) { - if (typeof value !== 'number') - throw TypeError("Illegal value: "+value+" (not a number)"); + if (!this.noAssert) { + if (typeof value !== 'number') + throw TypeError("Illegal value: "+value+" (not a number)"); if (typeof offset !== 'number' || offset % 1 !== 0) throw TypeError("Illegal offset: "+offset+" (not an integer)"); offset >>>= 0; if (offset < 0 || offset + 0 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.byteLength); - } + } offset += 8; var capacity9 = this.buffer.byteLength; if (offset > capacity9) this.resize((capacity9 *= 2) > offset ? capacity9 : offset); offset -= 8; - this.view.setFloat64(offset, value, this.littleEndian); + this.view.setFloat64(offset, value, this.littleEndian); 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 - */ - ByteBufferPrototype.writeDouble = ByteBufferPrototype.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 - */ - ByteBufferPrototype.readFloat64 = function(offset) { + 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 + */ + ByteBufferPrototype.writeDouble = ByteBufferPrototype.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 + */ + ByteBufferPrototype.readFloat64 = function(offset) { var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; - if (!this.noAssert) { + if (!this.noAssert) { if (typeof offset !== 'number' || offset % 1 !== 0) throw TypeError("Illegal offset: "+offset+" (not an integer)"); offset >>>= 0; if (offset < 0 || offset + 8 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= "+offset+" (+"+8+") <= "+this.buffer.byteLength); - } - var value = this.view.getFloat64(offset, this.littleEndian); + } + var value = this.view.getFloat64(offset, this.littleEndian); 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 - */ - ByteBufferPrototype.readDouble = ByteBufferPrototype.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 - */ - ByteBufferPrototype.writeVarint32 = function(value, offset) { + 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 + */ + ByteBufferPrototype.readDouble = ByteBufferPrototype.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 + */ + ByteBufferPrototype.writeVarint32 = function(value, offset) { var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; - if (!this.noAssert) { + if (!this.noAssert) { if (typeof value !== 'number' || value % 1 !== 0) throw TypeError("Illegal value: "+value+" (not an integer)"); value |= 0; @@ -27697,217 +27683,217 @@ Curve25519Worker.prototype = { offset >>>= 0; if (offset < 0 || offset + 0 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.byteLength); - } - var size = ByteBuffer.calculateVarint32(value), - b; + } + var size = ByteBuffer.calculateVarint32(value), + b; offset += size; var capacity10 = this.buffer.byteLength; if (offset > capacity10) this.resize((capacity10 *= 2) > offset ? capacity10 : offset); offset -= size; - // ref: http://code.google.com/searchframe#WTeibokF6gE/trunk/src/google/protobuf/io/coded_stream.cc - this.view.setUint8(offset, b = value | 0x80); - value >>>= 0; - if (value >= 1 << 7) { - b = (value >> 7) | 0x80; - this.view.setUint8(offset+1, b); - if (value >= 1 << 14) { - b = (value >> 14) | 0x80; - this.view.setUint8(offset+2, b); - if (value >= 1 << 21) { - b = (value >> 21) | 0x80; - this.view.setUint8(offset+3, b); - if (value >= 1 << 28) { - this.view.setUint8(offset+4, (value >> 28) & 0x0F); - size = 5; - } else { - this.view.setUint8(offset+3, b & 0x7F); - size = 4; - } - } else { - this.view.setUint8(offset+2, b & 0x7F); - size = 3; - } - } else { - this.view.setUint8(offset+1, b & 0x7F); - size = 2; - } - } 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) { + // ref: http://code.google.com/searchframe#WTeibokF6gE/trunk/src/google/protobuf/io/coded_stream.cc + this.view.setUint8(offset, b = value | 0x80); + value >>>= 0; + if (value >= 1 << 7) { + b = (value >> 7) | 0x80; + this.view.setUint8(offset+1, b); + if (value >= 1 << 14) { + b = (value >> 14) | 0x80; + this.view.setUint8(offset+2, b); + if (value >= 1 << 21) { + b = (value >> 21) | 0x80; + this.view.setUint8(offset+3, b); + if (value >= 1 << 28) { + this.view.setUint8(offset+4, (value >> 28) & 0x0F); + size = 5; + } else { + this.view.setUint8(offset+3, b & 0x7F); + size = 4; + } + } else { + this.view.setUint8(offset+2, b & 0x7F); + size = 3; + } + } else { + this.view.setUint8(offset+1, b & 0x7F); + size = 2; + } + } 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) { var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; - if (!this.noAssert) { + if (!this.noAssert) { if (typeof offset !== 'number' || offset % 1 !== 0) throw TypeError("Illegal offset: "+offset+" (not an integer)"); offset >>>= 0; if (offset < 0 || offset + 1 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= "+offset+" (+"+1+") <= "+this.buffer.byteLength); - } - // 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; - } - 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; - }; - - // 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) { + } + // 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; + } + 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; + }; + + // 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) { if (typeof value === 'number') value = Long.fromNumber(value); else if (typeof value === 'string') value = Long.fromString(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) { + // 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) { if (typeof value === 'number') value = Long.fromNumber(value, false); else if (typeof value === 'string') value = Long.fromString(value, false); else if (value.unsigned !== false) value = value.toSigned(); - // 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) { + // 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) { if (typeof value === 'number') value = Long.fromNumber(value, false); else if (typeof value === 'string') value = Long.fromString(value, false); else if (value.unsigned !== false) value = value.toSigned(); - // 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) { + // 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) { var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; - if (!this.noAssert) { + if (!this.noAssert) { if (typeof value === 'number') value = Long.fromNumber(value); else if (typeof value === 'string') @@ -27919,401 +27905,401 @@ Curve25519Worker.prototype = { offset >>>= 0; if (offset < 0 || offset + 0 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.byteLength); - } + } if (typeof value === 'number') value = Long.fromNumber(value, false); else if (typeof value === 'string') value = Long.fromString(value, false); else if (value.unsigned !== false) value = value.toSigned(); - var size = ByteBuffer.calculateVarint64(value), - part0 = value.toInt() >>> 0, - part1 = value.shiftRightUnsigned(28).toInt() >>> 0, - part2 = value.shiftRightUnsigned(56).toInt() >>> 0; + var size = ByteBuffer.calculateVarint64(value), + part0 = value.toInt() >>> 0, + part1 = value.shiftRightUnsigned(28).toInt() >>> 0, + part2 = value.shiftRightUnsigned(56).toInt() >>> 0; offset += size; var capacity11 = this.buffer.byteLength; if (offset > capacity11) this.resize((capacity11 *= 2) > offset ? capacity11 : offset); offset -= size; - switch (size) { - 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) { + switch (size) { + 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) { var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; - if (!this.noAssert) { + if (!this.noAssert) { if (typeof offset !== 'number' || offset % 1 !== 0) throw TypeError("Illegal offset: "+offset+" (not an integer)"); offset >>>= 0; if (offset < 0 || offset + 1 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= "+offset+" (+"+1+") <= "+this.buffer.byteLength); - } - // ref: src/google/protobuf/io/coded_stream.cc - var start = offset, - part0 = 0, - part1 = 0, - part2 = 0, - b = 0; - 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 - - - // types/strings/cstring - - /** - * Writes a NULL-terminated UTF8 encoded string. For this to work the specified string must not contain any NULL - * characters itself. - * @param {string} str String to write - * @param {number=} offset Offset to write to. Will use and increase {@link ByteBuffer#offset} by the number of bytes - * contained in `str` + 1 if omitted. - * @returns {!ByteBuffer|number} this if offset is omitted, else the actual number of bytes written - * @expose - */ - ByteBufferPrototype.writeCString = function(str, offset) { + } + // ref: src/google/protobuf/io/coded_stream.cc + var start = offset, + part0 = 0, + part1 = 0, + part2 = 0, + b = 0; + 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 + + + // types/strings/cstring + + /** + * Writes a NULL-terminated UTF8 encoded string. For this to work the specified string must not contain any NULL + * characters itself. + * @param {string} str String to write + * @param {number=} offset Offset to write to. Will use and increase {@link ByteBuffer#offset} by the number of bytes + * contained in `str` + 1 if omitted. + * @returns {!ByteBuffer|number} this if offset is omitted, else the actual number of bytes written + * @expose + */ + ByteBufferPrototype.writeCString = function(str, offset) { var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; - var i, - k = str.length; - if (!this.noAssert) { - if (typeof str !== 'string') - throw TypeError("Illegal str: Not a string"); - for (i=0; i>>= 0; if (offset < 0 || offset + 0 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.byteLength); - } - // UTF8 strings do not contain zero bytes in between except for the zero character, so: - k = utfx.calculateUTF16asUTF8(stringSource(str))[1]; + } + // UTF8 strings do not contain zero bytes in between except for the zero character, so: + k = utfx.calculateUTF16asUTF8(stringSource(str))[1]; offset += k+1; var capacity12 = this.buffer.byteLength; if (offset > capacity12) this.resize((capacity12 *= 2) > offset ? capacity12 : offset); offset -= k+1; - utfx.encodeUTF16toUTF8(stringSource(str), function(b) { - this.view.setUint8(offset++, b); - }.bind(this)); - this.view.setUint8(offset++, 0); - if (relative) { - this.offset = offset; - return this; - } - return k; - }; - - /** - * Reads a NULL-terminated UTF8 encoded string. For this to work the string read must not contain any NULL characters - * itself. - * @param {number=} offset Offset to read from. Will use and increase {@link ByteBuffer#offset} by the number of bytes - * read if omitted. - * @returns {string|!{string: string, length: number}} The string read if offset is omitted, else the string - * read and the actual number of bytes read. - * @expose - */ - ByteBufferPrototype.readCString = function(offset) { + utfx.encodeUTF16toUTF8(stringSource(str), function(b) { + this.view.setUint8(offset++, b); + }.bind(this)); + this.view.setUint8(offset++, 0); + if (relative) { + this.offset = offset; + return this; + } + return k; + }; + + /** + * Reads a NULL-terminated UTF8 encoded string. For this to work the string read must not contain any NULL characters + * itself. + * @param {number=} offset Offset to read from. Will use and increase {@link ByteBuffer#offset} by the number of bytes + * read if omitted. + * @returns {string|!{string: string, length: number}} The string read if offset is omitted, else the string + * read and the actual number of bytes read. + * @expose + */ + ByteBufferPrototype.readCString = function(offset) { var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; - if (!this.noAssert) { + if (!this.noAssert) { if (typeof offset !== 'number' || offset % 1 !== 0) throw TypeError("Illegal offset: "+offset+" (not an integer)"); offset >>>= 0; if (offset < 0 || offset + 1 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= "+offset+" (+"+1+") <= "+this.buffer.byteLength); - } - var start = offset, - temp; - // UTF8 strings do not contain zero bytes in between except for the zero character itself, so: - var sd, b = -1; - utfx.decodeUTF8toUTF16(function() { - if (b === 0) return null; - if (offset >= this.limit) - throw RangeError("Illegal range: Truncated data, "+offset+" < "+this.limit); - return (b = this.view.getUint8(offset++)) === 0 ? null : b; - }.bind(this), sd = stringDestination(), true); - if (relative) { - this.offset = offset; - return sd(); - } else { - return { - "string": sd(), - "length": offset - start - }; - } - }; - - // types/strings/istring - - /** - * Writes a length as uint32 prefixed UTF8 encoded string. - * @param {string} str String 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 - * @see ByteBuffer#writeVarint32 - */ - ByteBufferPrototype.writeIString = function(str, offset) { + } + var start = offset, + temp; + // UTF8 strings do not contain zero bytes in between except for the zero character itself, so: + var sd, b = -1; + utfx.decodeUTF8toUTF16(function() { + if (b === 0) return null; + if (offset >= this.limit) + throw RangeError("Illegal range: Truncated data, "+offset+" < "+this.limit); + return (b = this.view.getUint8(offset++)) === 0 ? null : b; + }.bind(this), sd = stringDestination(), true); + if (relative) { + this.offset = offset; + return sd(); + } else { + return { + "string": sd(), + "length": offset - start + }; + } + }; + + // types/strings/istring + + /** + * Writes a length as uint32 prefixed UTF8 encoded string. + * @param {string} str String 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 + * @see ByteBuffer#writeVarint32 + */ + ByteBufferPrototype.writeIString = function(str, offset) { var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; - if (!this.noAssert) { - if (typeof str !== 'string') - throw TypeError("Illegal str: Not a string"); + if (!this.noAssert) { + if (typeof str !== 'string') + throw TypeError("Illegal str: Not a string"); if (typeof offset !== 'number' || offset % 1 !== 0) throw TypeError("Illegal offset: "+offset+" (not an integer)"); offset >>>= 0; if (offset < 0 || offset + 0 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.byteLength); - } - var start = offset, - k; - k = utfx.calculateUTF16asUTF8(stringSource(str), this.noAssert)[1]; + } + var start = offset, + k; + k = utfx.calculateUTF16asUTF8(stringSource(str), this.noAssert)[1]; offset += 4+k; var capacity13 = this.buffer.byteLength; if (offset > capacity13) this.resize((capacity13 *= 2) > offset ? capacity13 : offset); offset -= 4+k; - this.view.setUint32(offset, k, this.littleEndian); - offset += 4; - utfx.encodeUTF16toUTF8(stringSource(str), function(b) { - this.view.setUint8(offset++, b); - }.bind(this)); - if (offset !== start + 4 + k) - throw RangeError("Illegal range: Truncated data, "+offset+" == "+(offset+4+k)); - if (relative) { - this.offset = offset; - return this; - } - return offset - start; - }; - - /** - * Reads a length as uint32 prefixed UTF8 encoded string. - * @param {number=} offset Offset to read from. Will use and increase {@link ByteBuffer#offset} by the number of bytes - * read if omitted. - * @returns {string|!{string: string, length: number}} The string read if offset is omitted, else the string - * read and the actual number of bytes read. - * @expose - * @see ByteBuffer#readVarint32 - */ - ByteBufferPrototype.readIString = function(offset) { + this.view.setUint32(offset, k, this.littleEndian); + offset += 4; + utfx.encodeUTF16toUTF8(stringSource(str), function(b) { + this.view.setUint8(offset++, b); + }.bind(this)); + if (offset !== start + 4 + k) + throw RangeError("Illegal range: Truncated data, "+offset+" == "+(offset+4+k)); + if (relative) { + this.offset = offset; + return this; + } + return offset - start; + }; + + /** + * Reads a length as uint32 prefixed UTF8 encoded string. + * @param {number=} offset Offset to read from. Will use and increase {@link ByteBuffer#offset} by the number of bytes + * read if omitted. + * @returns {string|!{string: string, length: number}} The string read if offset is omitted, else the string + * read and the actual number of bytes read. + * @expose + * @see ByteBuffer#readVarint32 + */ + ByteBufferPrototype.readIString = function(offset) { var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; - if (!this.noAssert) { + if (!this.noAssert) { if (typeof offset !== 'number' || offset % 1 !== 0) throw TypeError("Illegal offset: "+offset+" (not an integer)"); offset >>>= 0; if (offset < 0 || offset + 4 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= "+offset+" (+"+4+") <= "+this.buffer.byteLength); - } - var temp = 0, - start = offset, - str; - temp = this.view.getUint32(offset, this.littleEndian); - offset += 4; - var k = offset + temp, - sd; - utfx.decodeUTF8toUTF16(function() { - return offset < k ? this.view.getUint8(offset++) : null; - }.bind(this), sd = stringDestination(), this.noAssert); - str = sd(); - if (relative) { - this.offset = offset; - return str; - } else { - return { - 'string': str, - 'length': offset - start - }; - } - }; - - // types/strings/utf8string - - /** - * Metrics representing number of UTF8 characters. Evaluates to `c`. - * @type {string} - * @const - * @expose - */ - ByteBuffer.METRICS_CHARS = 'c'; - - /** - * Metrics representing number of bytes. Evaluates to `b`. - * @type {string} - * @const - * @expose - */ - ByteBuffer.METRICS_BYTES = 'b'; - - /** - * Writes an UTF8 encoded string. - * @param {string} str String to write - * @param {number=} offset Offset to write to. Will use and increase {@link ByteBuffer#offset} if omitted. - * @returns {!ByteBuffer|number} this if offset is omitted, else the actual number of bytes written. - * @expose - */ - ByteBufferPrototype.writeUTF8String = function(str, offset) { + } + var temp = 0, + start = offset, + str; + temp = this.view.getUint32(offset, this.littleEndian); + offset += 4; + var k = offset + temp, + sd; + utfx.decodeUTF8toUTF16(function() { + return offset < k ? this.view.getUint8(offset++) : null; + }.bind(this), sd = stringDestination(), this.noAssert); + str = sd(); + if (relative) { + this.offset = offset; + return str; + } else { + return { + 'string': str, + 'length': offset - start + }; + } + }; + + // types/strings/utf8string + + /** + * Metrics representing number of UTF8 characters. Evaluates to `c`. + * @type {string} + * @const + * @expose + */ + ByteBuffer.METRICS_CHARS = 'c'; + + /** + * Metrics representing number of bytes. Evaluates to `b`. + * @type {string} + * @const + * @expose + */ + ByteBuffer.METRICS_BYTES = 'b'; + + /** + * Writes an UTF8 encoded string. + * @param {string} str String to write + * @param {number=} offset Offset to write to. Will use and increase {@link ByteBuffer#offset} if omitted. + * @returns {!ByteBuffer|number} this if offset is omitted, else the actual number of bytes written. + * @expose + */ + ByteBufferPrototype.writeUTF8String = function(str, offset) { var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; - if (!this.noAssert) { + if (!this.noAssert) { if (typeof offset !== 'number' || offset % 1 !== 0) throw TypeError("Illegal offset: "+offset+" (not an integer)"); offset >>>= 0; if (offset < 0 || offset + 0 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.byteLength); - } - var k; - var start = offset; - k = utfx.calculateUTF16asUTF8(stringSource(str))[1]; + } + var k; + var start = offset; + k = utfx.calculateUTF16asUTF8(stringSource(str))[1]; offset += k; var capacity14 = this.buffer.byteLength; if (offset > capacity14) this.resize((capacity14 *= 2) > offset ? capacity14 : offset); offset -= k; - utfx.encodeUTF16toUTF8(stringSource(str), function(b) { - this.view.setUint8(offset++, b); - }.bind(this)); - if (relative) { - this.offset = offset; - return this; - } - return offset - start; - }; - - /** - * Writes an UTF8 encoded string. This is an alias of {@link ByteBuffer#writeUTF8String}. - * @function - * @param {string} str String to write - * @param {number=} offset Offset to write to. Will use and increase {@link ByteBuffer#offset} if omitted. - * @returns {!ByteBuffer|number} this if offset is omitted, else the actual number of bytes written. - * @expose - */ - ByteBufferPrototype.writeString = ByteBufferPrototype.writeUTF8String; - - /** - * Calculates the number of UTF8 characters of a string. JavaScript itself uses UTF-16, so that a string's - * `length` property does not reflect its actual UTF8 size if it contains code points larger than 0xFFFF. - * @function - * @param {string} str String to calculate - * @returns {number} Number of UTF8 characters - * @expose - */ - ByteBuffer.calculateUTF8Chars = function(str) { - return utfx.calculateUTF16asUTF8(stringSource(str))[0]; - }; - - /** - * Calculates the number of UTF8 bytes of a string. - * @function - * @param {string} str String to calculate - * @returns {number} Number of UTF8 bytes - * @expose - */ - ByteBuffer.calculateUTF8Bytes = function(str) { - return utfx.calculateUTF16asUTF8(stringSource(str))[1]; - }; - - /** - * Reads an UTF8 encoded string. - * @param {number} length Number of characters or bytes to read. - * @param {string=} metrics Metrics specifying what `length` is meant to count. Defaults to - * {@link ByteBuffer.METRICS_CHARS}. - * @param {number=} offset Offset to read from. Will use and increase {@link ByteBuffer#offset} by the number of bytes - * read if omitted. - * @returns {string|!{string: string, length: number}} The string read if offset is omitted, else the string - * read and the actual number of bytes read. - * @expose - */ - ByteBufferPrototype.readUTF8String = function(length, metrics, offset) { - if (typeof metrics === 'number') { - offset = metrics; - metrics = undefined; - } + utfx.encodeUTF16toUTF8(stringSource(str), function(b) { + this.view.setUint8(offset++, b); + }.bind(this)); + if (relative) { + this.offset = offset; + return this; + } + return offset - start; + }; + + /** + * Writes an UTF8 encoded string. This is an alias of {@link ByteBuffer#writeUTF8String}. + * @function + * @param {string} str String to write + * @param {number=} offset Offset to write to. Will use and increase {@link ByteBuffer#offset} if omitted. + * @returns {!ByteBuffer|number} this if offset is omitted, else the actual number of bytes written. + * @expose + */ + ByteBufferPrototype.writeString = ByteBufferPrototype.writeUTF8String; + + /** + * Calculates the number of UTF8 characters of a string. JavaScript itself uses UTF-16, so that a string's + * `length` property does not reflect its actual UTF8 size if it contains code points larger than 0xFFFF. + * @function + * @param {string} str String to calculate + * @returns {number} Number of UTF8 characters + * @expose + */ + ByteBuffer.calculateUTF8Chars = function(str) { + return utfx.calculateUTF16asUTF8(stringSource(str))[0]; + }; + + /** + * Calculates the number of UTF8 bytes of a string. + * @function + * @param {string} str String to calculate + * @returns {number} Number of UTF8 bytes + * @expose + */ + ByteBuffer.calculateUTF8Bytes = function(str) { + return utfx.calculateUTF16asUTF8(stringSource(str))[1]; + }; + + /** + * Reads an UTF8 encoded string. + * @param {number} length Number of characters or bytes to read. + * @param {string=} metrics Metrics specifying what `length` is meant to count. Defaults to + * {@link ByteBuffer.METRICS_CHARS}. + * @param {number=} offset Offset to read from. Will use and increase {@link ByteBuffer#offset} by the number of bytes + * read if omitted. + * @returns {string|!{string: string, length: number}} The string read if offset is omitted, else the string + * read and the actual number of bytes read. + * @expose + */ + ByteBufferPrototype.readUTF8String = function(length, metrics, offset) { + if (typeof metrics === 'number') { + offset = metrics; + metrics = undefined; + } var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; - if (typeof metrics === 'undefined') metrics = ByteBuffer.METRICS_CHARS; - if (!this.noAssert) { + if (typeof metrics === 'undefined') metrics = ByteBuffer.METRICS_CHARS; + if (!this.noAssert) { if (typeof length !== 'number' || length % 1 !== 0) throw TypeError("Illegal length: "+length+" (not an integer)"); length |= 0; @@ -28322,284 +28308,284 @@ Curve25519Worker.prototype = { offset >>>= 0; if (offset < 0 || offset + 0 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.byteLength); - } - var i = 0, - start = offset, - sd; - if (metrics === ByteBuffer.METRICS_CHARS) { // The same for node and the browser - sd = stringDestination(); - utfx.decodeUTF8(function() { - return i < length && offset < this.limit ? this.view.getUint8(offset++) : null; - }.bind(this), function(cp) { - ++i; utfx.UTF8toUTF16(cp, sd); - }.bind(this)); - if (i !== length) - throw RangeError("Illegal range: Truncated data, "+i+" == "+length); - if (relative) { - this.offset = offset; - return sd(); - } else { - return { - "string": sd(), - "length": offset - start - }; - } - } else if (metrics === ByteBuffer.METRICS_BYTES) { - if (!this.noAssert) { + } + var i = 0, + start = offset, + sd; + if (metrics === ByteBuffer.METRICS_CHARS) { // The same for node and the browser + sd = stringDestination(); + utfx.decodeUTF8(function() { + return i < length && offset < this.limit ? this.view.getUint8(offset++) : null; + }.bind(this), function(cp) { + ++i; utfx.UTF8toUTF16(cp, sd); + }.bind(this)); + if (i !== length) + throw RangeError("Illegal range: Truncated data, "+i+" == "+length); + if (relative) { + this.offset = offset; + return sd(); + } else { + return { + "string": sd(), + "length": offset - start + }; + } + } else if (metrics === ByteBuffer.METRICS_BYTES) { + if (!this.noAssert) { if (typeof offset !== 'number' || offset % 1 !== 0) throw TypeError("Illegal offset: "+offset+" (not an integer)"); offset >>>= 0; if (offset < 0 || offset + length > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= "+offset+" (+"+length+") <= "+this.buffer.byteLength); - } - var k = offset + length; - utfx.decodeUTF8toUTF16(function() { - return offset < k ? this.view.getUint8(offset++) : null; - }.bind(this), sd = stringDestination(), this.noAssert); - if (offset !== k) - throw RangeError("Illegal range: Truncated data, "+offset+" == "+k); - if (relative) { - this.offset = offset; - return sd(); - } else { - return { - 'string': sd(), - 'length': offset - start - }; - } - } else - throw TypeError("Unsupported metrics: "+metrics); - }; - - /** - * Reads an UTF8 encoded string. This is an alias of {@link ByteBuffer#readUTF8String}. - * @function - * @param {number} length Number of characters or bytes to read - * @param {number=} metrics Metrics specifying what `n` is meant to count. Defaults to - * {@link ByteBuffer.METRICS_CHARS}. - * @param {number=} offset Offset to read from. Will use and increase {@link ByteBuffer#offset} by the number of bytes - * read if omitted. - * @returns {string|!{string: string, length: number}} The string read if offset is omitted, else the string - * read and the actual number of bytes read. - * @expose - */ - ByteBufferPrototype.readString = ByteBufferPrototype.readUTF8String; - - // types/strings/vstring - - /** - * Writes a length as varint32 prefixed UTF8 encoded string. - * @param {string} str String 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 - * @see ByteBuffer#writeVarint32 - */ - ByteBufferPrototype.writeVString = function(str, offset) { + } + var k = offset + length; + utfx.decodeUTF8toUTF16(function() { + return offset < k ? this.view.getUint8(offset++) : null; + }.bind(this), sd = stringDestination(), this.noAssert); + if (offset !== k) + throw RangeError("Illegal range: Truncated data, "+offset+" == "+k); + if (relative) { + this.offset = offset; + return sd(); + } else { + return { + 'string': sd(), + 'length': offset - start + }; + } + } else + throw TypeError("Unsupported metrics: "+metrics); + }; + + /** + * Reads an UTF8 encoded string. This is an alias of {@link ByteBuffer#readUTF8String}. + * @function + * @param {number} length Number of characters or bytes to read + * @param {number=} metrics Metrics specifying what `n` is meant to count. Defaults to + * {@link ByteBuffer.METRICS_CHARS}. + * @param {number=} offset Offset to read from. Will use and increase {@link ByteBuffer#offset} by the number of bytes + * read if omitted. + * @returns {string|!{string: string, length: number}} The string read if offset is omitted, else the string + * read and the actual number of bytes read. + * @expose + */ + ByteBufferPrototype.readString = ByteBufferPrototype.readUTF8String; + + // types/strings/vstring + + /** + * Writes a length as varint32 prefixed UTF8 encoded string. + * @param {string} str String 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 + * @see ByteBuffer#writeVarint32 + */ + ByteBufferPrototype.writeVString = function(str, offset) { var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; - if (!this.noAssert) { - if (typeof str !== 'string') - throw TypeError("Illegal str: Not a string"); + if (!this.noAssert) { + if (typeof str !== 'string') + throw TypeError("Illegal str: Not a string"); if (typeof offset !== 'number' || offset % 1 !== 0) throw TypeError("Illegal offset: "+offset+" (not an integer)"); offset >>>= 0; if (offset < 0 || offset + 0 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.byteLength); - } - var start = offset, - k, l; - k = utfx.calculateUTF16asUTF8(stringSource(str), this.noAssert)[1]; - l = ByteBuffer.calculateVarint32(k); + } + var start = offset, + k, l; + k = utfx.calculateUTF16asUTF8(stringSource(str), this.noAssert)[1]; + l = ByteBuffer.calculateVarint32(k); offset += l+k; var capacity15 = this.buffer.byteLength; if (offset > capacity15) this.resize((capacity15 *= 2) > offset ? capacity15 : offset); offset -= l+k; - offset += this.writeVarint32(k, offset); - utfx.encodeUTF16toUTF8(stringSource(str), function(b) { - this.view.setUint8(offset++, b); - }.bind(this)); - if (offset !== start+k+l) - throw RangeError("Illegal range: Truncated data, "+offset+" == "+(offset+k+l)); - if (relative) { - this.offset = offset; - return this; - } - return offset - start; - }; - - /** - * Reads a length as varint32 prefixed UTF8 encoded string. - * @param {number=} offset Offset to read from. Will use and increase {@link ByteBuffer#offset} by the number of bytes - * read if omitted. - * @returns {string|!{string: string, length: number}} The string read if offset is omitted, else the string - * read and the actual number of bytes read. - * @expose - * @see ByteBuffer#readVarint32 - */ - ByteBufferPrototype.readVString = function(offset) { + offset += this.writeVarint32(k, offset); + utfx.encodeUTF16toUTF8(stringSource(str), function(b) { + this.view.setUint8(offset++, b); + }.bind(this)); + if (offset !== start+k+l) + throw RangeError("Illegal range: Truncated data, "+offset+" == "+(offset+k+l)); + if (relative) { + this.offset = offset; + return this; + } + return offset - start; + }; + + /** + * Reads a length as varint32 prefixed UTF8 encoded string. + * @param {number=} offset Offset to read from. Will use and increase {@link ByteBuffer#offset} by the number of bytes + * read if omitted. + * @returns {string|!{string: string, length: number}} The string read if offset is omitted, else the string + * read and the actual number of bytes read. + * @expose + * @see ByteBuffer#readVarint32 + */ + ByteBufferPrototype.readVString = function(offset) { var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; - if (!this.noAssert) { + if (!this.noAssert) { if (typeof offset !== 'number' || offset % 1 !== 0) throw TypeError("Illegal offset: "+offset+" (not an integer)"); offset >>>= 0; if (offset < 0 || offset + 1 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= "+offset+" (+"+1+") <= "+this.buffer.byteLength); - } - var temp = this.readVarint32(offset), - start = offset, - str; - offset += temp['length']; - temp = temp['value']; - var k = offset + temp, - sd = stringDestination(); - utfx.decodeUTF8toUTF16(function() { - return offset < k ? this.view.getUint8(offset++) : null; - }.bind(this), sd, this.noAssert); - str = sd(); - if (relative) { - this.offset = offset; - return str; - } else { - return { - 'string': str, - 'length': offset - start - }; - } - }; - - - /** - * Appends some data to this ByteBuffer. This will overwrite any contents behind the specified offset up to the appended - * data's length. - * @param {!ByteBuffer|!ArrayBuffer|!Uint8Array|string} source Data to append. If `source` is a ByteBuffer, its offsets - * will be modified according to the performed read operation. - * @param {(string|number)=} encoding Encoding if `data` is a string ("base64", "hex", "binary", defaults to "utf8") - * @param {number=} offset Offset to append at. Will use and increase {@link ByteBuffer#offset} by the number of bytes - * read if omitted. - * @returns {!ByteBuffer} this - * @expose - * @example A relative `<01 02>03.append(<04 05>)` will result in `<01 02 04 05>, 04 05|` - * @example An absolute `<01 02>03.append(04 05>, 1)` will result in `<01 04>05, 04 05|` - */ - ByteBufferPrototype.append = function(source, encoding, offset) { - if (typeof encoding === 'number' || typeof encoding !== 'string') { - offset = encoding; - encoding = undefined; - } + } + var temp = this.readVarint32(offset), + start = offset, + str; + offset += temp['length']; + temp = temp['value']; + var k = offset + temp, + sd = stringDestination(); + utfx.decodeUTF8toUTF16(function() { + return offset < k ? this.view.getUint8(offset++) : null; + }.bind(this), sd, this.noAssert); + str = sd(); + if (relative) { + this.offset = offset; + return str; + } else { + return { + 'string': str, + 'length': offset - start + }; + } + }; + + + /** + * Appends some data to this ByteBuffer. This will overwrite any contents behind the specified offset up to the appended + * data's length. + * @param {!ByteBuffer|!ArrayBuffer|!Uint8Array|string} source Data to append. If `source` is a ByteBuffer, its offsets + * will be modified according to the performed read operation. + * @param {(string|number)=} encoding Encoding if `data` is a string ("base64", "hex", "binary", defaults to "utf8") + * @param {number=} offset Offset to append at. Will use and increase {@link ByteBuffer#offset} by the number of bytes + * read if omitted. + * @returns {!ByteBuffer} this + * @expose + * @example A relative `<01 02>03.append(<04 05>)` will result in `<01 02 04 05>, 04 05|` + * @example An absolute `<01 02>03.append(04 05>, 1)` will result in `<01 04>05, 04 05|` + */ + ByteBufferPrototype.append = function(source, encoding, offset) { + if (typeof encoding === 'number' || typeof encoding !== 'string') { + offset = encoding; + encoding = undefined; + } var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; - if (!this.noAssert) { + if (!this.noAssert) { if (typeof offset !== 'number' || offset % 1 !== 0) throw TypeError("Illegal offset: "+offset+" (not an integer)"); offset >>>= 0; if (offset < 0 || offset + 0 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.byteLength); - } - if (!(source instanceof ByteBuffer)) - source = ByteBuffer.wrap(source, encoding); - var length = source.limit - source.offset; - if (length <= 0) return this; // Nothing to append + } + if (!(source instanceof ByteBuffer)) + source = ByteBuffer.wrap(source, encoding); + var length = source.limit - source.offset; + if (length <= 0) return this; // Nothing to append offset += length; var capacity16 = this.buffer.byteLength; if (offset > capacity16) this.resize((capacity16 *= 2) > offset ? capacity16 : offset); offset -= length; - new Uint8Array(this.buffer, offset).set(new Uint8Array(source.buffer).subarray(source.offset, source.limit)); - source.offset += length; + new Uint8Array(this.buffer, offset).set(new Uint8Array(source.buffer).subarray(source.offset, source.limit)); + source.offset += length; if (relative) this.offset += length; - return this; - }; - - /** - * Appends this ByteBuffer's contents to another ByteBuffer. This will overwrite any contents at and after the - specified offset up to the length of this ByteBuffer's data. - * @param {!ByteBuffer} target Target ByteBuffer - * @param {number=} offset Offset to append to. Will use and increase {@link ByteBuffer#offset} by the number of bytes - * read if omitted. - * @returns {!ByteBuffer} this - * @expose - * @see ByteBuffer#append - */ - ByteBufferPrototype.appendTo = function(target, offset) { - target.append(this, offset); - return this; - }; - - /** - * Enables or disables assertions of argument types and offsets. Assertions are enabled by default but you can opt to - * disable them if your code already makes sure that everything is valid. - * @param {boolean} assert `true` to enable assertions, otherwise `false` - * @returns {!ByteBuffer} this - * @expose - */ - ByteBufferPrototype.assert = function(assert) { - this.noAssert = !assert; - return this; - }; - - /** - * Gets the capacity of this ByteBuffer's backing buffer. - * @returns {number} Capacity of the backing buffer - * @expose - */ - ByteBufferPrototype.capacity = function() { - return this.buffer.byteLength; - }; - - /** - * Clears this ByteBuffer's offsets by setting {@link ByteBuffer#offset} to `0` and {@link ByteBuffer#limit} to the - * backing buffer's capacity. Discards {@link ByteBuffer#markedOffset}. - * @returns {!ByteBuffer} this - * @expose - */ - ByteBufferPrototype.clear = function() { - this.offset = 0; - this.limit = this.buffer.byteLength; - this.markedOffset = -1; - return this; - }; - - /** - * Creates a cloned instance of this ByteBuffer, preset with this ByteBuffer's values for {@link ByteBuffer#offset}, - * {@link ByteBuffer#markedOffset} and {@link ByteBuffer#limit}. - * @param {boolean=} copy Whether to copy the backing buffer or to return another view on the same, defaults to `false` - * @returns {!ByteBuffer} Cloned instance - * @expose - */ - ByteBufferPrototype.clone = function(copy) { - var bb = new ByteBuffer(0, this.littleEndian, this.noAssert); - if (copy) { - var buffer = new ArrayBuffer(this.buffer.byteLength); - new Uint8Array(buffer).set(this.buffer); - bb.buffer = buffer; - bb.view = new DataView(buffer); - } else { - bb.buffer = this.buffer; - bb.view = this.view; - } - bb.offset = this.offset; - bb.markedOffset = this.markedOffset; - bb.limit = this.limit; - return bb; - }; - - /** - * Compacts this ByteBuffer to be backed by a {@link ByteBuffer#buffer} of its contents' length. Contents are the bytes - * between {@link ByteBuffer#offset} and {@link ByteBuffer#limit}. Will set `offset = 0` and `limit = capacity` and - * adapt {@link ByteBuffer#markedOffset} to the same relative position if set. - * @param {number=} begin Offset to start at, defaults to {@link ByteBuffer#offset} - * @param {number=} end Offset to end at, defaults to {@link ByteBuffer#limit} - * @returns {!ByteBuffer} this - * @expose - */ - ByteBufferPrototype.compact = function(begin, end) { - if (typeof begin === 'undefined') begin = this.offset; - if (typeof end === 'undefined') end = this.limit; - if (!this.noAssert) { + return this; + }; + + /** + * Appends this ByteBuffer's contents to another ByteBuffer. This will overwrite any contents at and after the + specified offset up to the length of this ByteBuffer's data. + * @param {!ByteBuffer} target Target ByteBuffer + * @param {number=} offset Offset to append to. Will use and increase {@link ByteBuffer#offset} by the number of bytes + * read if omitted. + * @returns {!ByteBuffer} this + * @expose + * @see ByteBuffer#append + */ + ByteBufferPrototype.appendTo = function(target, offset) { + target.append(this, offset); + return this; + }; + + /** + * Enables or disables assertions of argument types and offsets. Assertions are enabled by default but you can opt to + * disable them if your code already makes sure that everything is valid. + * @param {boolean} assert `true` to enable assertions, otherwise `false` + * @returns {!ByteBuffer} this + * @expose + */ + ByteBufferPrototype.assert = function(assert) { + this.noAssert = !assert; + return this; + }; + + /** + * Gets the capacity of this ByteBuffer's backing buffer. + * @returns {number} Capacity of the backing buffer + * @expose + */ + ByteBufferPrototype.capacity = function() { + return this.buffer.byteLength; + }; + + /** + * Clears this ByteBuffer's offsets by setting {@link ByteBuffer#offset} to `0` and {@link ByteBuffer#limit} to the + * backing buffer's capacity. Discards {@link ByteBuffer#markedOffset}. + * @returns {!ByteBuffer} this + * @expose + */ + ByteBufferPrototype.clear = function() { + this.offset = 0; + this.limit = this.buffer.byteLength; + this.markedOffset = -1; + return this; + }; + + /** + * Creates a cloned instance of this ByteBuffer, preset with this ByteBuffer's values for {@link ByteBuffer#offset}, + * {@link ByteBuffer#markedOffset} and {@link ByteBuffer#limit}. + * @param {boolean=} copy Whether to copy the backing buffer or to return another view on the same, defaults to `false` + * @returns {!ByteBuffer} Cloned instance + * @expose + */ + ByteBufferPrototype.clone = function(copy) { + var bb = new ByteBuffer(0, this.littleEndian, this.noAssert); + if (copy) { + var buffer = new ArrayBuffer(this.buffer.byteLength); + new Uint8Array(buffer).set(this.buffer); + bb.buffer = buffer; + bb.view = new DataView(buffer); + } else { + bb.buffer = this.buffer; + bb.view = this.view; + } + bb.offset = this.offset; + bb.markedOffset = this.markedOffset; + bb.limit = this.limit; + return bb; + }; + + /** + * Compacts this ByteBuffer to be backed by a {@link ByteBuffer#buffer} of its contents' length. Contents are the bytes + * between {@link ByteBuffer#offset} and {@link ByteBuffer#limit}. Will set `offset = 0` and `limit = capacity` and + * adapt {@link ByteBuffer#markedOffset} to the same relative position if set. + * @param {number=} begin Offset to start at, defaults to {@link ByteBuffer#offset} + * @param {number=} end Offset to end at, defaults to {@link ByteBuffer#limit} + * @returns {!ByteBuffer} this + * @expose + */ + ByteBufferPrototype.compact = function(begin, end) { + if (typeof begin === 'undefined') begin = this.offset; + if (typeof end === 'undefined') end = this.limit; + if (!this.noAssert) { if (typeof begin !== 'number' || begin % 1 !== 0) throw TypeError("Illegal begin: Not an integer"); begin >>>= 0; @@ -28608,40 +28594,40 @@ Curve25519Worker.prototype = { end >>>= 0; if (begin < 0 || begin > end || end > this.buffer.byteLength) throw RangeError("Illegal range: 0 <= "+begin+" <= "+end+" <= "+this.buffer.byteLength); - } - if (begin === 0 && end === this.buffer.byteLength) - return this; // Already compacted - var len = end - begin; - if (len === 0) { - this.buffer = EMPTY_BUFFER; - this.view = null; - if (this.markedOffset >= 0) this.markedOffset -= begin; - this.offset = 0; - this.limit = 0; - return this; - } - var buffer = new ArrayBuffer(len); - new Uint8Array(buffer).set(new Uint8Array(this.buffer).subarray(begin, end)); - this.buffer = buffer; - this.view = new DataView(buffer); - if (this.markedOffset >= 0) this.markedOffset -= begin; - this.offset = 0; - this.limit = len; - return this; - }; - - /** - * Creates a copy of this ByteBuffer's contents. Contents are the bytes between {@link ByteBuffer#offset} and - * {@link ByteBuffer#limit}. - * @param {number=} begin Begin offset, defaults to {@link ByteBuffer#offset}. - * @param {number=} end End offset, defaults to {@link ByteBuffer#limit}. - * @returns {!ByteBuffer} Copy - * @expose - */ - ByteBufferPrototype.copy = function(begin, end) { - if (typeof begin === 'undefined') begin = this.offset; - if (typeof end === 'undefined') end = this.limit; - if (!this.noAssert) { + } + if (begin === 0 && end === this.buffer.byteLength) + return this; // Already compacted + var len = end - begin; + if (len === 0) { + this.buffer = EMPTY_BUFFER; + this.view = null; + if (this.markedOffset >= 0) this.markedOffset -= begin; + this.offset = 0; + this.limit = 0; + return this; + } + var buffer = new ArrayBuffer(len); + new Uint8Array(buffer).set(new Uint8Array(this.buffer).subarray(begin, end)); + this.buffer = buffer; + this.view = new DataView(buffer); + if (this.markedOffset >= 0) this.markedOffset -= begin; + this.offset = 0; + this.limit = len; + return this; + }; + + /** + * Creates a copy of this ByteBuffer's contents. Contents are the bytes between {@link ByteBuffer#offset} and + * {@link ByteBuffer#limit}. + * @param {number=} begin Begin offset, defaults to {@link ByteBuffer#offset}. + * @param {number=} end End offset, defaults to {@link ByteBuffer#limit}. + * @returns {!ByteBuffer} Copy + * @expose + */ + ByteBufferPrototype.copy = function(begin, end) { + if (typeof begin === 'undefined') begin = this.offset; + if (typeof end === 'undefined') end = this.limit; + if (!this.noAssert) { if (typeof begin !== 'number' || begin % 1 !== 0) throw TypeError("Illegal begin: Not an integer"); begin >>>= 0; @@ -28650,94 +28636,94 @@ Curve25519Worker.prototype = { end >>>= 0; if (begin < 0 || begin > end || end > this.buffer.byteLength) throw RangeError("Illegal range: 0 <= "+begin+" <= "+end+" <= "+this.buffer.byteLength); - } - if (begin === end) - return new ByteBuffer(0, this.littleEndian, this.noAssert); - var capacity = end - begin, - bb = new ByteBuffer(capacity, this.littleEndian, this.noAssert); - bb.offset = 0; - bb.limit = capacity; - if (bb.markedOffset >= 0) bb.markedOffset -= begin; - this.copyTo(bb, 0, begin, end); - return bb; - }; - - /** - * Copies this ByteBuffer's contents to another ByteBuffer. Contents are the bytes between {@link ByteBuffer#offset} and - * {@link ByteBuffer#limit}. - * @param {!ByteBuffer} target Target ByteBuffer - * @param {number=} targetOffset Offset to copy to. Will use and increase the target's {@link ByteBuffer#offset} - * by the number of bytes copied if omitted. - * @param {number=} sourceOffset Offset to start copying from. Will use and increase {@link ByteBuffer#offset} by the - * number of bytes copied if omitted. - * @param {number=} sourceLimit Offset to end copying from, defaults to {@link ByteBuffer#limit} - * @returns {!ByteBuffer} this - * @expose - */ - ByteBufferPrototype.copyTo = function(target, targetOffset, sourceOffset, sourceLimit) { - var relative, - targetRelative; - if (!this.noAssert) { - if (!ByteBuffer.isByteBuffer(target)) - throw TypeError("Illegal target: Not a ByteBuffer"); - } - targetOffset = (targetRelative = typeof targetOffset === 'undefined') ? target.offset : targetOffset | 0; - sourceOffset = (relative = typeof sourceOffset === 'undefined') ? this.offset : sourceOffset | 0; - sourceLimit = typeof sourceLimit === 'undefined' ? this.limit : sourceLimit | 0; - - if (targetOffset < 0 || targetOffset > target.buffer.byteLength) - throw RangeError("Illegal target range: 0 <= "+targetOffset+" <= "+target.buffer.byteLength); - if (sourceOffset < 0 || sourceLimit > this.buffer.byteLength) - throw RangeError("Illegal source range: 0 <= "+sourceOffset+" <= "+this.buffer.byteLength); - - var len = sourceLimit - sourceOffset; - if (len === 0) - return target; // Nothing to copy - - target.ensureCapacity(targetOffset + len); - - new Uint8Array(target.buffer).set(new Uint8Array(this.buffer).subarray(sourceOffset, sourceLimit), targetOffset); - - if (relative) this.offset += len; - if (targetRelative) target.offset += len; - - return this; - }; - - /** - * Makes sure that this ByteBuffer is backed by a {@link ByteBuffer#buffer} of at least the specified capacity. If the - * current capacity is exceeded, it will be doubled. If double the current capacity is less than the required capacity, - * the required capacity will be used instead. - * @param {number} capacity Required capacity - * @returns {!ByteBuffer} this - * @expose - */ - ByteBufferPrototype.ensureCapacity = function(capacity) { - var current = this.buffer.byteLength; - if (current < capacity) - return this.resize((current *= 2) > capacity ? current : capacity); - return this; - }; - - /** - * Overwrites this ByteBuffer's contents with the specified value. Contents are the bytes between - * {@link ByteBuffer#offset} and {@link ByteBuffer#limit}. - * @param {number|string} value Byte value to fill with. If given as a string, the first character is used. - * @param {number=} begin Begin offset. Will use and increase {@link ByteBuffer#offset} by the number of bytes - * written if omitted. defaults to {@link ByteBuffer#offset}. - * @param {number=} end End offset, defaults to {@link ByteBuffer#limit}. - * @returns {!ByteBuffer} this - * @expose - * @example `someByteBuffer.clear().fill(0)` fills the entire backing buffer with zeroes - */ - ByteBufferPrototype.fill = function(value, begin, end) { + } + if (begin === end) + return new ByteBuffer(0, this.littleEndian, this.noAssert); + var capacity = end - begin, + bb = new ByteBuffer(capacity, this.littleEndian, this.noAssert); + bb.offset = 0; + bb.limit = capacity; + if (bb.markedOffset >= 0) bb.markedOffset -= begin; + this.copyTo(bb, 0, begin, end); + return bb; + }; + + /** + * Copies this ByteBuffer's contents to another ByteBuffer. Contents are the bytes between {@link ByteBuffer#offset} and + * {@link ByteBuffer#limit}. + * @param {!ByteBuffer} target Target ByteBuffer + * @param {number=} targetOffset Offset to copy to. Will use and increase the target's {@link ByteBuffer#offset} + * by the number of bytes copied if omitted. + * @param {number=} sourceOffset Offset to start copying from. Will use and increase {@link ByteBuffer#offset} by the + * number of bytes copied if omitted. + * @param {number=} sourceLimit Offset to end copying from, defaults to {@link ByteBuffer#limit} + * @returns {!ByteBuffer} this + * @expose + */ + ByteBufferPrototype.copyTo = function(target, targetOffset, sourceOffset, sourceLimit) { + var relative, + targetRelative; + if (!this.noAssert) { + if (!ByteBuffer.isByteBuffer(target)) + throw TypeError("Illegal target: Not a ByteBuffer"); + } + targetOffset = (targetRelative = typeof targetOffset === 'undefined') ? target.offset : targetOffset | 0; + sourceOffset = (relative = typeof sourceOffset === 'undefined') ? this.offset : sourceOffset | 0; + sourceLimit = typeof sourceLimit === 'undefined' ? this.limit : sourceLimit | 0; + + if (targetOffset < 0 || targetOffset > target.buffer.byteLength) + throw RangeError("Illegal target range: 0 <= "+targetOffset+" <= "+target.buffer.byteLength); + if (sourceOffset < 0 || sourceLimit > this.buffer.byteLength) + throw RangeError("Illegal source range: 0 <= "+sourceOffset+" <= "+this.buffer.byteLength); + + var len = sourceLimit - sourceOffset; + if (len === 0) + return target; // Nothing to copy + + target.ensureCapacity(targetOffset + len); + + new Uint8Array(target.buffer).set(new Uint8Array(this.buffer).subarray(sourceOffset, sourceLimit), targetOffset); + + if (relative) this.offset += len; + if (targetRelative) target.offset += len; + + return this; + }; + + /** + * Makes sure that this ByteBuffer is backed by a {@link ByteBuffer#buffer} of at least the specified capacity. If the + * current capacity is exceeded, it will be doubled. If double the current capacity is less than the required capacity, + * the required capacity will be used instead. + * @param {number} capacity Required capacity + * @returns {!ByteBuffer} this + * @expose + */ + ByteBufferPrototype.ensureCapacity = function(capacity) { + var current = this.buffer.byteLength; + if (current < capacity) + return this.resize((current *= 2) > capacity ? current : capacity); + return this; + }; + + /** + * Overwrites this ByteBuffer's contents with the specified value. Contents are the bytes between + * {@link ByteBuffer#offset} and {@link ByteBuffer#limit}. + * @param {number|string} value Byte value to fill with. If given as a string, the first character is used. + * @param {number=} begin Begin offset. Will use and increase {@link ByteBuffer#offset} by the number of bytes + * written if omitted. defaults to {@link ByteBuffer#offset}. + * @param {number=} end End offset, defaults to {@link ByteBuffer#limit}. + * @returns {!ByteBuffer} this + * @expose + * @example `someByteBuffer.clear().fill(0)` fills the entire backing buffer with zeroes + */ + ByteBufferPrototype.fill = function(value, begin, end) { var relative = typeof begin === 'undefined'; if (relative) begin = this.offset; - if (typeof value === 'string' && value.length > 0) - value = value.charCodeAt(0); - if (typeof begin === 'undefined') begin = this.offset; - if (typeof end === 'undefined') end = this.limit; - if (!this.noAssert) { + if (typeof value === 'string' && value.length > 0) + value = value.charCodeAt(0); + if (typeof begin === 'undefined') begin = this.offset; + if (typeof end === 'undefined') end = this.limit; + if (!this.noAssert) { if (typeof value !== 'number' || value % 1 !== 0) throw TypeError("Illegal value: "+value+" (not an integer)"); value |= 0; @@ -28749,227 +28735,227 @@ Curve25519Worker.prototype = { end >>>= 0; if (begin < 0 || begin > end || end > this.buffer.byteLength) throw RangeError("Illegal range: 0 <= "+begin+" <= "+end+" <= "+this.buffer.byteLength); - } - if (begin >= end) - return this; // Nothing to fill - while (begin < end) this.view.setUint8(begin++, value); - if (relative) this.offset = begin; - return this; - }; - - /** - * Makes this ByteBuffer ready for a new sequence of write or relative read operations. Sets `limit = offset` and - * `offset = 0`. Make sure always to flip a ByteBuffer when all relative read or write operations are complete. - * @returns {!ByteBuffer} this - * @expose - */ - ByteBufferPrototype.flip = function() { - this.limit = this.offset; - this.offset = 0; - return this; - }; - /** - * Marks an offset on this ByteBuffer to be used later. - * @param {number=} offset Offset to mark. Defaults to {@link ByteBuffer#offset}. - * @returns {!ByteBuffer} this - * @throws {TypeError} If `offset` is not a valid number - * @throws {RangeError} If `offset` is out of bounds - * @see ByteBuffer#reset - * @expose - */ - ByteBufferPrototype.mark = function(offset) { - offset = typeof offset === 'undefined' ? this.offset : offset; - if (!this.noAssert) { + } + if (begin >= end) + return this; // Nothing to fill + while (begin < end) this.view.setUint8(begin++, value); + if (relative) this.offset = begin; + return this; + }; + + /** + * Makes this ByteBuffer ready for a new sequence of write or relative read operations. Sets `limit = offset` and + * `offset = 0`. Make sure always to flip a ByteBuffer when all relative read or write operations are complete. + * @returns {!ByteBuffer} this + * @expose + */ + ByteBufferPrototype.flip = function() { + this.limit = this.offset; + this.offset = 0; + return this; + }; + /** + * Marks an offset on this ByteBuffer to be used later. + * @param {number=} offset Offset to mark. Defaults to {@link ByteBuffer#offset}. + * @returns {!ByteBuffer} this + * @throws {TypeError} If `offset` is not a valid number + * @throws {RangeError} If `offset` is out of bounds + * @see ByteBuffer#reset + * @expose + */ + ByteBufferPrototype.mark = function(offset) { + offset = typeof offset === 'undefined' ? this.offset : offset; + if (!this.noAssert) { if (typeof offset !== 'number' || offset % 1 !== 0) throw TypeError("Illegal offset: "+offset+" (not an integer)"); offset >>>= 0; if (offset < 0 || offset + 0 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.byteLength); - } - this.markedOffset = offset; - return this; - }; - /** - * Sets the byte order. - * @param {boolean} littleEndian `true` for little endian byte order, `false` for big endian - * @returns {!ByteBuffer} this - * @expose - */ - ByteBufferPrototype.order = function(littleEndian) { - if (!this.noAssert) { - if (typeof littleEndian !== 'boolean') - throw TypeError("Illegal littleEndian: Not a boolean"); - } - this.littleEndian = !!littleEndian; - return this; - }; - - /** - * Switches (to) little endian byte order. - * @param {boolean=} littleEndian Defaults to `true`, otherwise uses big endian - * @returns {!ByteBuffer} this - * @expose - */ - ByteBufferPrototype.LE = function(littleEndian) { - this.littleEndian = typeof littleEndian !== 'undefined' ? !!littleEndian : true; - return this; - }; - - /** - * Switches (to) big endian byte order. - * @param {boolean=} bigEndian Defaults to `true`, otherwise uses little endian - * @returns {!ByteBuffer} this - * @expose - */ - ByteBufferPrototype.BE = function(bigEndian) { - this.littleEndian = typeof bigEndian !== 'undefined' ? !bigEndian : false; - return this; - }; - /** - * Prepends some data to this ByteBuffer. This will overwrite any contents before the specified offset up to the - * prepended data's length. If there is not enough space available before the specified `offset`, the backing buffer - * will be resized and its contents moved accordingly. - * @param {!ByteBuffer|string|!ArrayBuffer} source Data to prepend. If `source` is a ByteBuffer, its offset will be - * modified according to the performed read operation. - * @param {(string|number)=} encoding Encoding if `data` is a string ("base64", "hex", "binary", defaults to "utf8") - * @param {number=} offset Offset to prepend at. Will use and decrease {@link ByteBuffer#offset} by the number of bytes - * prepended if omitted. - * @returns {!ByteBuffer} this - * @expose - * @example A relative `00<01 02 03>.prepend(<04 05>)` results in `<04 05 01 02 03>, 04 05|` - * @example An absolute `00<01 02 03>.prepend(<04 05>, 2)` results in `04<05 02 03>, 04 05|` - */ - ByteBufferPrototype.prepend = function(source, encoding, offset) { - if (typeof encoding === 'number' || typeof encoding !== 'string') { - offset = encoding; - encoding = undefined; - } + } + this.markedOffset = offset; + return this; + }; + /** + * Sets the byte order. + * @param {boolean} littleEndian `true` for little endian byte order, `false` for big endian + * @returns {!ByteBuffer} this + * @expose + */ + ByteBufferPrototype.order = function(littleEndian) { + if (!this.noAssert) { + if (typeof littleEndian !== 'boolean') + throw TypeError("Illegal littleEndian: Not a boolean"); + } + this.littleEndian = !!littleEndian; + return this; + }; + + /** + * Switches (to) little endian byte order. + * @param {boolean=} littleEndian Defaults to `true`, otherwise uses big endian + * @returns {!ByteBuffer} this + * @expose + */ + ByteBufferPrototype.LE = function(littleEndian) { + this.littleEndian = typeof littleEndian !== 'undefined' ? !!littleEndian : true; + return this; + }; + + /** + * Switches (to) big endian byte order. + * @param {boolean=} bigEndian Defaults to `true`, otherwise uses little endian + * @returns {!ByteBuffer} this + * @expose + */ + ByteBufferPrototype.BE = function(bigEndian) { + this.littleEndian = typeof bigEndian !== 'undefined' ? !bigEndian : false; + return this; + }; + /** + * Prepends some data to this ByteBuffer. This will overwrite any contents before the specified offset up to the + * prepended data's length. If there is not enough space available before the specified `offset`, the backing buffer + * will be resized and its contents moved accordingly. + * @param {!ByteBuffer|string|!ArrayBuffer} source Data to prepend. If `source` is a ByteBuffer, its offset will be + * modified according to the performed read operation. + * @param {(string|number)=} encoding Encoding if `data` is a string ("base64", "hex", "binary", defaults to "utf8") + * @param {number=} offset Offset to prepend at. Will use and decrease {@link ByteBuffer#offset} by the number of bytes + * prepended if omitted. + * @returns {!ByteBuffer} this + * @expose + * @example A relative `00<01 02 03>.prepend(<04 05>)` results in `<04 05 01 02 03>, 04 05|` + * @example An absolute `00<01 02 03>.prepend(<04 05>, 2)` results in `04<05 02 03>, 04 05|` + */ + ByteBufferPrototype.prepend = function(source, encoding, offset) { + if (typeof encoding === 'number' || typeof encoding !== 'string') { + offset = encoding; + encoding = undefined; + } var relative = typeof offset === 'undefined'; if (relative) offset = this.offset; - if (!this.noAssert) { + if (!this.noAssert) { if (typeof offset !== 'number' || offset % 1 !== 0) throw TypeError("Illegal offset: "+offset+" (not an integer)"); offset >>>= 0; if (offset < 0 || offset + 0 > this.buffer.byteLength) throw RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.byteLength); - } - if (!(source instanceof ByteBuffer)) - source = ByteBuffer.wrap(source, encoding); - var len = source.limit - source.offset; - if (len <= 0) return this; // Nothing to prepend - var diff = len - offset; - var arrayView; - if (diff > 0) { // Not enough space before offset, so resize + move - var buffer = new ArrayBuffer(this.buffer.byteLength + diff); - arrayView = new Uint8Array(buffer); - arrayView.set(new Uint8Array(this.buffer).subarray(offset, this.buffer.byteLength), len); - this.buffer = buffer; - this.view = new DataView(buffer); - this.offset += diff; - if (this.markedOffset >= 0) this.markedOffset += diff; - this.limit += diff; - offset += diff; - } else { - arrayView = new Uint8Array(this.buffer); - } - arrayView.set(new Uint8Array(source.buffer).subarray(source.offset, source.limit), offset - len); - source.offset = source.limit; - if (relative) - this.offset -= len; - return this; - }; - - /** - * Prepends this ByteBuffer to another ByteBuffer. This will overwrite any contents before the specified offset up to the - * prepended data's length. If there is not enough space available before the specified `offset`, the backing buffer - * will be resized and its contents moved accordingly. - * @param {!ByteBuffer} target Target ByteBuffer - * @param {number=} offset Offset to prepend at. Will use and decrease {@link ByteBuffer#offset} by the number of bytes - * prepended if omitted. - * @returns {!ByteBuffer} this - * @expose - * @see ByteBuffer#prepend - */ - ByteBufferPrototype.prependTo = function(target, offset) { - target.prepend(this, offset); - return this; - }; - /** - * Prints debug information about this ByteBuffer's contents. - * @param {function(string)=} out Output function to call, defaults to console.log - * @expose - */ - ByteBufferPrototype.printDebug = function(out) { - if (typeof out !== 'function') out = console.log.bind(console); - out( - this.toString()+"\n"+ - "-------------------------------------------------------------------\n"+ - this.toDebug(/* columns */ true) - ); - }; - - /** - * Gets the number of remaining readable bytes. Contents are the bytes between {@link ByteBuffer#offset} and - * {@link ByteBuffer#limit}, so this returns `limit - offset`. - * @returns {number} Remaining readable bytes. May be negative if `offset > limit`. - * @expose - */ - ByteBufferPrototype.remaining = function() { - return this.limit - this.offset; - }; - /** - * Resets this ByteBuffer's {@link ByteBuffer#offset}. If an offset has been marked through {@link ByteBuffer#mark} - * before, `offset` will be set to {@link ByteBuffer#markedOffset}, which will then be discarded. If no offset has been - * marked, sets `offset = 0`. - * @returns {!ByteBuffer} this - * @see ByteBuffer#mark - * @expose - */ - ByteBufferPrototype.reset = function() { - if (this.markedOffset >= 0) { - this.offset = this.markedOffset; - this.markedOffset = -1; - } else { - this.offset = 0; - } - return this; - }; - /** - * Resizes this ByteBuffer to be backed by a buffer of at least the given capacity. Will do nothing if already that - * large or larger. - * @param {number} capacity Capacity required - * @returns {!ByteBuffer} this - * @throws {TypeError} If `capacity` is not a number - * @throws {RangeError} If `capacity < 0` - * @expose - */ - ByteBufferPrototype.resize = function(capacity) { - if (!this.noAssert) { + } + if (!(source instanceof ByteBuffer)) + source = ByteBuffer.wrap(source, encoding); + var len = source.limit - source.offset; + if (len <= 0) return this; // Nothing to prepend + var diff = len - offset; + var arrayView; + if (diff > 0) { // Not enough space before offset, so resize + move + var buffer = new ArrayBuffer(this.buffer.byteLength + diff); + arrayView = new Uint8Array(buffer); + arrayView.set(new Uint8Array(this.buffer).subarray(offset, this.buffer.byteLength), len); + this.buffer = buffer; + this.view = new DataView(buffer); + this.offset += diff; + if (this.markedOffset >= 0) this.markedOffset += diff; + this.limit += diff; + offset += diff; + } else { + arrayView = new Uint8Array(this.buffer); + } + arrayView.set(new Uint8Array(source.buffer).subarray(source.offset, source.limit), offset - len); + source.offset = source.limit; + if (relative) + this.offset -= len; + return this; + }; + + /** + * Prepends this ByteBuffer to another ByteBuffer. This will overwrite any contents before the specified offset up to the + * prepended data's length. If there is not enough space available before the specified `offset`, the backing buffer + * will be resized and its contents moved accordingly. + * @param {!ByteBuffer} target Target ByteBuffer + * @param {number=} offset Offset to prepend at. Will use and decrease {@link ByteBuffer#offset} by the number of bytes + * prepended if omitted. + * @returns {!ByteBuffer} this + * @expose + * @see ByteBuffer#prepend + */ + ByteBufferPrototype.prependTo = function(target, offset) { + target.prepend(this, offset); + return this; + }; + /** + * Prints debug information about this ByteBuffer's contents. + * @param {function(string)=} out Output function to call, defaults to console.log + * @expose + */ + ByteBufferPrototype.printDebug = function(out) { + if (typeof out !== 'function') out = console.log.bind(console); + out( + this.toString()+"\n"+ + "-------------------------------------------------------------------\n"+ + this.toDebug(/* columns */ true) + ); + }; + + /** + * Gets the number of remaining readable bytes. Contents are the bytes between {@link ByteBuffer#offset} and + * {@link ByteBuffer#limit}, so this returns `limit - offset`. + * @returns {number} Remaining readable bytes. May be negative if `offset > limit`. + * @expose + */ + ByteBufferPrototype.remaining = function() { + return this.limit - this.offset; + }; + /** + * Resets this ByteBuffer's {@link ByteBuffer#offset}. If an offset has been marked through {@link ByteBuffer#mark} + * before, `offset` will be set to {@link ByteBuffer#markedOffset}, which will then be discarded. If no offset has been + * marked, sets `offset = 0`. + * @returns {!ByteBuffer} this + * @see ByteBuffer#mark + * @expose + */ + ByteBufferPrototype.reset = function() { + if (this.markedOffset >= 0) { + this.offset = this.markedOffset; + this.markedOffset = -1; + } else { + this.offset = 0; + } + return this; + }; + /** + * Resizes this ByteBuffer to be backed by a buffer of at least the given capacity. Will do nothing if already that + * large or larger. + * @param {number} capacity Capacity required + * @returns {!ByteBuffer} this + * @throws {TypeError} If `capacity` is not a number + * @throws {RangeError} If `capacity < 0` + * @expose + */ + ByteBufferPrototype.resize = function(capacity) { + if (!this.noAssert) { if (typeof capacity !== 'number' || capacity % 1 !== 0) throw TypeError("Illegal capacity: "+capacity+" (not an integer)"); capacity |= 0; - if (capacity < 0) - throw RangeError("Illegal capacity: 0 <= "+capacity); - } - if (this.buffer.byteLength < capacity) { - var buffer = new ArrayBuffer(capacity); - new Uint8Array(buffer).set(new Uint8Array(this.buffer)); - this.buffer = buffer; - this.view = new DataView(buffer); - } - return this; - }; - /** - * Reverses this ByteBuffer's contents. - * @param {number=} begin Offset to start at, defaults to {@link ByteBuffer#offset} - * @param {number=} end Offset to end at, defaults to {@link ByteBuffer#limit} - * @returns {!ByteBuffer} this - * @expose - */ - ByteBufferPrototype.reverse = function(begin, end) { - if (typeof begin === 'undefined') begin = this.offset; - if (typeof end === 'undefined') end = this.limit; - if (!this.noAssert) { + if (capacity < 0) + throw RangeError("Illegal capacity: 0 <= "+capacity); + } + if (this.buffer.byteLength < capacity) { + var buffer = new ArrayBuffer(capacity); + new Uint8Array(buffer).set(new Uint8Array(this.buffer)); + this.buffer = buffer; + this.view = new DataView(buffer); + } + return this; + }; + /** + * Reverses this ByteBuffer's contents. + * @param {number=} begin Offset to start at, defaults to {@link ByteBuffer#offset} + * @param {number=} end Offset to end at, defaults to {@link ByteBuffer#limit} + * @returns {!ByteBuffer} this + * @expose + */ + ByteBufferPrototype.reverse = function(begin, end) { + if (typeof begin === 'undefined') begin = this.offset; + if (typeof end === 'undefined') end = this.limit; + if (!this.noAssert) { if (typeof begin !== 'number' || begin % 1 !== 0) throw TypeError("Illegal begin: Not an integer"); begin >>>= 0; @@ -28978,45 +28964,45 @@ Curve25519Worker.prototype = { end >>>= 0; if (begin < 0 || begin > end || end > this.buffer.byteLength) throw RangeError("Illegal range: 0 <= "+begin+" <= "+end+" <= "+this.buffer.byteLength); - } - if (begin === end) - return this; // Nothing to reverse - Array.prototype.reverse.call(new Uint8Array(this.buffer).subarray(begin, end)); - this.view = new DataView(this.buffer); // FIXME: Why exactly is this necessary? - return this; - }; - /** - * Skips the next `length` bytes. This will just advance - * @param {number} length Number of bytes to skip. May also be negative to move the offset back. - * @returns {!ByteBuffer} this - * @expose - */ - ByteBufferPrototype.skip = function(length) { - if (!this.noAssert) { + } + if (begin === end) + return this; // Nothing to reverse + Array.prototype.reverse.call(new Uint8Array(this.buffer).subarray(begin, end)); + this.view = new DataView(this.buffer); // FIXME: Why exactly is this necessary? + return this; + }; + /** + * Skips the next `length` bytes. This will just advance + * @param {number} length Number of bytes to skip. May also be negative to move the offset back. + * @returns {!ByteBuffer} this + * @expose + */ + ByteBufferPrototype.skip = function(length) { + if (!this.noAssert) { if (typeof length !== 'number' || length % 1 !== 0) throw TypeError("Illegal length: "+length+" (not an integer)"); length |= 0; - } - var offset = this.offset + length; - if (!this.noAssert) { - if (offset < 0 || offset > this.buffer.byteLength) - throw RangeError("Illegal length: 0 <= "+this.offset+" + "+length+" <= "+this.buffer.byteLength); - } - this.offset = offset; - return this; - }; - - /** - * Slices this ByteBuffer by creating a cloned instance with `offset = begin` and `limit = end`. - * @param {number=} begin Begin offset, defaults to {@link ByteBuffer#offset}. - * @param {number=} end End offset, defaults to {@link ByteBuffer#limit}. - * @returns {!ByteBuffer} Clone of this ByteBuffer with slicing applied, backed by the same {@link ByteBuffer#buffer} - * @expose - */ - ByteBufferPrototype.slice = function(begin, end) { - if (typeof begin === 'undefined') begin = this.offset; - if (typeof end === 'undefined') end = this.limit; - if (!this.noAssert) { + } + var offset = this.offset + length; + if (!this.noAssert) { + if (offset < 0 || offset > this.buffer.byteLength) + throw RangeError("Illegal length: 0 <= "+this.offset+" + "+length+" <= "+this.buffer.byteLength); + } + this.offset = offset; + return this; + }; + + /** + * Slices this ByteBuffer by creating a cloned instance with `offset = begin` and `limit = end`. + * @param {number=} begin Begin offset, defaults to {@link ByteBuffer#offset}. + * @param {number=} end End offset, defaults to {@link ByteBuffer#limit}. + * @returns {!ByteBuffer} Clone of this ByteBuffer with slicing applied, backed by the same {@link ByteBuffer#buffer} + * @expose + */ + ByteBufferPrototype.slice = function(begin, end) { + if (typeof begin === 'undefined') begin = this.offset; + if (typeof end === 'undefined') end = this.limit; + if (!this.noAssert) { if (typeof begin !== 'number' || begin % 1 !== 0) throw TypeError("Illegal begin: Not an integer"); begin >>>= 0; @@ -29025,30 +29011,30 @@ Curve25519Worker.prototype = { end >>>= 0; if (begin < 0 || begin > end || end > this.buffer.byteLength) throw RangeError("Illegal range: 0 <= "+begin+" <= "+end+" <= "+this.buffer.byteLength); - } - var bb = this.clone(); - bb.offset = begin; - bb.limit = end; - return bb; - }; - /** - * Returns a copy of the backing buffer that contains this ByteBuffer's contents. Contents are the bytes between - * {@link ByteBuffer#offset} and {@link ByteBuffer#limit}. Will transparently {@link ByteBuffer#flip} this - * ByteBuffer if `offset > limit` but the actual offsets remain untouched. - * @param {boolean=} forceCopy If `true` returns a copy, otherwise returns a view referencing the same memory if - * possible. Defaults to `false` - * @returns {!ArrayBuffer} Contents as an ArrayBuffer - * @expose - */ - ByteBufferPrototype.toBuffer = function(forceCopy) { - var offset = this.offset, - limit = this.limit; - if (offset > limit) { - var t = offset; - offset = limit; - limit = t; - } - if (!this.noAssert) { + } + var bb = this.clone(); + bb.offset = begin; + bb.limit = end; + return bb; + }; + /** + * Returns a copy of the backing buffer that contains this ByteBuffer's contents. Contents are the bytes between + * {@link ByteBuffer#offset} and {@link ByteBuffer#limit}. Will transparently {@link ByteBuffer#flip} this + * ByteBuffer if `offset > limit` but the actual offsets remain untouched. + * @param {boolean=} forceCopy If `true` returns a copy, otherwise returns a view referencing the same memory if + * possible. Defaults to `false` + * @returns {!ArrayBuffer} Contents as an ArrayBuffer + * @expose + */ + ByteBufferPrototype.toBuffer = function(forceCopy) { + var offset = this.offset, + limit = this.limit; + if (offset > limit) { + var t = offset; + offset = limit; + limit = t; + } + if (!this.noAssert) { if (typeof offset !== 'number' || offset % 1 !== 0) throw TypeError("Illegal offset: Not an integer"); offset >>>= 0; @@ -29057,199 +29043,199 @@ Curve25519Worker.prototype = { limit >>>= 0; if (offset < 0 || offset > limit || limit > this.buffer.byteLength) throw RangeError("Illegal range: 0 <= "+offset+" <= "+limit+" <= "+this.buffer.byteLength); - } - // NOTE: It's not possible to have another ArrayBuffer reference the same memory as the backing buffer. This is - // possible with Uint8Array#subarray only, but we have to return an ArrayBuffer by contract. So: - if (!forceCopy && offset === 0 && limit === this.buffer.byteLength) { - return this.buffer; - } - if (offset === limit) { - return EMPTY_BUFFER; - } - var buffer = new ArrayBuffer(limit - offset); - new Uint8Array(buffer).set(new Uint8Array(this.buffer).subarray(offset, limit), 0); - return buffer; - }; - - /** - * Returns a raw buffer compacted to contain this ByteBuffer's contents. Contents are the bytes between - * {@link ByteBuffer#offset} and {@link ByteBuffer#limit}. Will transparently {@link ByteBuffer#flip} this - * ByteBuffer if `offset > limit` but the actual offsets remain untouched. This is an alias of - * {@link ByteBuffer#toBuffer}. - * @function - * @param {boolean=} forceCopy If `true` returns a copy, otherwise returns a view referencing the same memory. - * Defaults to `false` - * @returns {!ArrayBuffer} Contents as an ArrayBuffer - * @expose - */ - ByteBufferPrototype.toArrayBuffer = ByteBufferPrototype.toBuffer; - - - /** - * Converts the ByteBuffer's contents to a string. - * @param {string=} encoding Output encoding. Returns an informative string representation if omitted but also allows - * direct conversion to "utf8", "hex", "base64" and "binary" encoding. "debug" returns a hex representation with - * highlighted offsets. - * @param {number=} begin Offset to begin at, defaults to {@link ByteBuffer#offset} - * @param {number=} end Offset to end at, defaults to {@link ByteBuffer#limit} - * @returns {string} String representation - * @throws {Error} If `encoding` is invalid - * @expose - */ - ByteBufferPrototype.toString = function(encoding, begin, end) { - if (typeof encoding === 'undefined') - return "ByteBufferAB(offset="+this.offset+",markedOffset="+this.markedOffset+",limit="+this.limit+",capacity="+this.capacity()+")"; - if (typeof encoding === 'number') - encoding = "utf8", - begin = encoding, - end = begin; - switch (encoding) { - case "utf8": - return this.toUTF8(begin, end); - case "base64": - return this.toBase64(begin, end); - case "hex": - return this.toHex(begin, end); - case "binary": - return this.toBinary(begin, end); - case "debug": - return this.toDebug(); - case "columns": - return this.toColumns(); - default: - throw Error("Unsupported encoding: "+encoding); - } - }; - - // lxiv-embeddable - - /** - * lxiv-embeddable (c) 2014 Daniel Wirtz - * Released under the Apache License, Version 2.0 - * see: https://github.com/dcodeIO/lxiv for details - */ - var lxiv = function() { - "use strict"; - - /** - * lxiv namespace. - * @type {!Object.} - * @exports lxiv - */ - var lxiv = {}; - - /** - * Character codes for output. - * @type {!Array.} - * @inner - */ - var aout = [ - 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, - 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 97, 98, 99, 100, 101, 102, - 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, - 119, 120, 121, 122, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 43, 47 - ]; - - /** - * Character codes for input. - * @type {!Array.} - * @inner - */ - var ain = []; - for (var i=0, k=aout.length; i>2)&0x3f]); - t = (b&0x3)<<4; - if ((b = src()) !== null) { - t |= (b>>4)&0xf; - dst(aout[(t|((b>>4)&0xf))&0x3f]); - t = (b&0xf)<<2; - if ((b = src()) !== null) - dst(aout[(t|((b>>6)&0x3))&0x3f]), - dst(aout[b&0x3f]); - else - dst(aout[t&0x3f]), - dst(61); - } else - dst(aout[t&0x3f]), - dst(61), - dst(61); - } - }; - - /** - * Decodes base64 char codes to bytes. - * @param {!function():number|null} src Characters source as a function returning the next char code respectively - * `null` if there are no more characters left. - * @param {!function(number)} dst Bytes destination as a function successively called with the next byte. - * @throws {Error} If a character code is invalid - */ - lxiv.decode = function(src, dst) { - var c, t1, t2; - function fail(c) { - throw Error("Illegal character code: "+c); - } - while ((c = src()) !== null) { - t1 = ain[c]; - if (typeof t1 === 'undefined') fail(c); - if ((c = src()) !== null) { - t2 = ain[c]; - if (typeof t2 === 'undefined') fail(c); - dst((t1<<2)>>>0|(t2&0x30)>>4); - if ((c = src()) !== null) { - t1 = ain[c]; - if (typeof t1 === 'undefined') - if (c === 61) break; else fail(c); - dst(((t2&0xf)<<4)>>>0|(t1&0x3c)>>2); - if ((c = src()) !== null) { - t2 = ain[c]; - if (typeof t2 === 'undefined') - if (c === 61) break; else fail(c); - dst(((t1&0x3)<<6)>>>0|t2); - } - } - } - } - }; - - /** - * Tests if a string is valid base64. - * @param {string} str String to test - * @returns {boolean} `true` if valid, otherwise `false` - */ - lxiv.test = function(str) { - return /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(str); - }; - - return lxiv; - }(); - - // encodings/base64 - - /** - * Encodes this ByteBuffer's contents to a base64 encoded string. - * @param {number=} begin Offset to begin at, defaults to {@link ByteBuffer#offset}. - * @param {number=} end Offset to end at, defaults to {@link ByteBuffer#limit}. - * @returns {string} Base64 encoded string - * @expose - */ - ByteBufferPrototype.toBase64 = function(begin, end) { - if (typeof begin === 'undefined') - begin = this.offset; - if (typeof end === 'undefined') - end = this.limit; - if (!this.noAssert) { + } + // NOTE: It's not possible to have another ArrayBuffer reference the same memory as the backing buffer. This is + // possible with Uint8Array#subarray only, but we have to return an ArrayBuffer by contract. So: + if (!forceCopy && offset === 0 && limit === this.buffer.byteLength) { + return this.buffer; + } + if (offset === limit) { + return EMPTY_BUFFER; + } + var buffer = new ArrayBuffer(limit - offset); + new Uint8Array(buffer).set(new Uint8Array(this.buffer).subarray(offset, limit), 0); + return buffer; + }; + + /** + * Returns a raw buffer compacted to contain this ByteBuffer's contents. Contents are the bytes between + * {@link ByteBuffer#offset} and {@link ByteBuffer#limit}. Will transparently {@link ByteBuffer#flip} this + * ByteBuffer if `offset > limit` but the actual offsets remain untouched. This is an alias of + * {@link ByteBuffer#toBuffer}. + * @function + * @param {boolean=} forceCopy If `true` returns a copy, otherwise returns a view referencing the same memory. + * Defaults to `false` + * @returns {!ArrayBuffer} Contents as an ArrayBuffer + * @expose + */ + ByteBufferPrototype.toArrayBuffer = ByteBufferPrototype.toBuffer; + + + /** + * Converts the ByteBuffer's contents to a string. + * @param {string=} encoding Output encoding. Returns an informative string representation if omitted but also allows + * direct conversion to "utf8", "hex", "base64" and "binary" encoding. "debug" returns a hex representation with + * highlighted offsets. + * @param {number=} begin Offset to begin at, defaults to {@link ByteBuffer#offset} + * @param {number=} end Offset to end at, defaults to {@link ByteBuffer#limit} + * @returns {string} String representation + * @throws {Error} If `encoding` is invalid + * @expose + */ + ByteBufferPrototype.toString = function(encoding, begin, end) { + if (typeof encoding === 'undefined') + return "ByteBufferAB(offset="+this.offset+",markedOffset="+this.markedOffset+",limit="+this.limit+",capacity="+this.capacity()+")"; + if (typeof encoding === 'number') + encoding = "utf8", + begin = encoding, + end = begin; + switch (encoding) { + case "utf8": + return this.toUTF8(begin, end); + case "base64": + return this.toBase64(begin, end); + case "hex": + return this.toHex(begin, end); + case "binary": + return this.toBinary(begin, end); + case "debug": + return this.toDebug(); + case "columns": + return this.toColumns(); + default: + throw Error("Unsupported encoding: "+encoding); + } + }; + + // lxiv-embeddable + + /** + * lxiv-embeddable (c) 2014 Daniel Wirtz + * Released under the Apache License, Version 2.0 + * see: https://github.com/dcodeIO/lxiv for details + */ + var lxiv = function() { + "use strict"; + + /** + * lxiv namespace. + * @type {!Object.} + * @exports lxiv + */ + var lxiv = {}; + + /** + * Character codes for output. + * @type {!Array.} + * @inner + */ + var aout = [ + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, + 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 97, 98, 99, 100, 101, 102, + 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, + 119, 120, 121, 122, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 43, 47 + ]; + + /** + * Character codes for input. + * @type {!Array.} + * @inner + */ + var ain = []; + for (var i=0, k=aout.length; i>2)&0x3f]); + t = (b&0x3)<<4; + if ((b = src()) !== null) { + t |= (b>>4)&0xf; + dst(aout[(t|((b>>4)&0xf))&0x3f]); + t = (b&0xf)<<2; + if ((b = src()) !== null) + dst(aout[(t|((b>>6)&0x3))&0x3f]), + dst(aout[b&0x3f]); + else + dst(aout[t&0x3f]), + dst(61); + } else + dst(aout[t&0x3f]), + dst(61), + dst(61); + } + }; + + /** + * Decodes base64 char codes to bytes. + * @param {!function():number|null} src Characters source as a function returning the next char code respectively + * `null` if there are no more characters left. + * @param {!function(number)} dst Bytes destination as a function successively called with the next byte. + * @throws {Error} If a character code is invalid + */ + lxiv.decode = function(src, dst) { + var c, t1, t2; + function fail(c) { + throw Error("Illegal character code: "+c); + } + while ((c = src()) !== null) { + t1 = ain[c]; + if (typeof t1 === 'undefined') fail(c); + if ((c = src()) !== null) { + t2 = ain[c]; + if (typeof t2 === 'undefined') fail(c); + dst((t1<<2)>>>0|(t2&0x30)>>4); + if ((c = src()) !== null) { + t1 = ain[c]; + if (typeof t1 === 'undefined') + if (c === 61) break; else fail(c); + dst(((t2&0xf)<<4)>>>0|(t1&0x3c)>>2); + if ((c = src()) !== null) { + t2 = ain[c]; + if (typeof t2 === 'undefined') + if (c === 61) break; else fail(c); + dst(((t1&0x3)<<6)>>>0|t2); + } + } + } + } + }; + + /** + * Tests if a string is valid base64. + * @param {string} str String to test + * @returns {boolean} `true` if valid, otherwise `false` + */ + lxiv.test = function(str) { + return /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(str); + }; + + return lxiv; + }(); + + // encodings/base64 + + /** + * Encodes this ByteBuffer's contents to a base64 encoded string. + * @param {number=} begin Offset to begin at, defaults to {@link ByteBuffer#offset}. + * @param {number=} end Offset to end at, defaults to {@link ByteBuffer#limit}. + * @returns {string} Base64 encoded string + * @expose + */ + ByteBufferPrototype.toBase64 = function(begin, end) { + if (typeof begin === 'undefined') + begin = this.offset; + if (typeof end === 'undefined') + end = this.limit; + if (!this.noAssert) { if (typeof begin !== 'number' || begin % 1 !== 0) throw TypeError("Illegal begin: Not an integer"); begin >>>= 0; @@ -29258,75 +29244,75 @@ Curve25519Worker.prototype = { end >>>= 0; if (begin < 0 || begin > end || end > this.buffer.byteLength) throw RangeError("Illegal range: 0 <= "+begin+" <= "+end+" <= "+this.buffer.byteLength); - } - var sd; lxiv.encode(function() { - return begin < end ? this.view.getUint8(begin++) : null; - }.bind(this), sd = stringDestination()); - return sd(); - }; - - /** - * Decodes a base64 encoded string to a ByteBuffer. - * @param {string} str String to decode - * @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} ByteBuffer - * @expose - */ - ByteBuffer.fromBase64 = function(str, littleEndian, noAssert) { - if (!noAssert) { - if (typeof str !== 'string') - throw TypeError("Illegal str: Not a string"); - if (str.length % 4 !== 0) - throw TypeError("Illegal str: Length not a multiple of 4"); - } - var bb = new ByteBuffer(str.length/4*3, littleEndian, noAssert), - i = 0; - lxiv.decode(stringSource(str), function(b) { - bb.view.setUint8(i++, b); - }); - bb.limit = i; - return bb; - }; - - /** - * Encodes a binary string to base64 like `window.btoa` does. - * @param {string} str Binary string - * @returns {string} Base64 encoded string - * @see https://developer.mozilla.org/en-US/docs/Web/API/Window.btoa - * @expose - */ - ByteBuffer.btoa = function(str) { - return ByteBuffer.fromBinary(str).toBase64(); - }; - - /** - * Decodes a base64 encoded string to binary like `window.atob` does. - * @param {string} b64 Base64 encoded string - * @returns {string} Binary string - * @see https://developer.mozilla.org/en-US/docs/Web/API/Window.atob - * @expose - */ - ByteBuffer.atob = function(b64) { - return ByteBuffer.fromBase64(b64).toBinary(); - }; - - // encodings/binary - - /** - * Encodes this ByteBuffer to a binary encoded string, that is using only characters 0x00-0xFF as bytes. - * @param {number=} begin Offset to begin at. Defaults to {@link ByteBuffer#offset}. - * @param {number=} end Offset to end at. Defaults to {@link ByteBuffer#limit}. - * @returns {string} Binary encoded string - * @throws {RangeError} If `offset > limit` - * @expose - */ - ByteBufferPrototype.toBinary = function(begin, end) { - begin = typeof begin === 'undefined' ? this.offset : begin; - end = typeof end === 'undefined' ? this.limit : end; - if (!this.noAssert) { + } + var sd; lxiv.encode(function() { + return begin < end ? this.view.getUint8(begin++) : null; + }.bind(this), sd = stringDestination()); + return sd(); + }; + + /** + * Decodes a base64 encoded string to a ByteBuffer. + * @param {string} str String to decode + * @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} ByteBuffer + * @expose + */ + ByteBuffer.fromBase64 = function(str, littleEndian, noAssert) { + if (!noAssert) { + if (typeof str !== 'string') + throw TypeError("Illegal str: Not a string"); + if (str.length % 4 !== 0) + throw TypeError("Illegal str: Length not a multiple of 4"); + } + var bb = new ByteBuffer(str.length/4*3, littleEndian, noAssert), + i = 0; + lxiv.decode(stringSource(str), function(b) { + bb.view.setUint8(i++, b); + }); + bb.limit = i; + return bb; + }; + + /** + * Encodes a binary string to base64 like `window.btoa` does. + * @param {string} str Binary string + * @returns {string} Base64 encoded string + * @see https://developer.mozilla.org/en-US/docs/Web/API/Window.btoa + * @expose + */ + ByteBuffer.btoa = function(str) { + return ByteBuffer.fromBinary(str).toBase64(); + }; + + /** + * Decodes a base64 encoded string to binary like `window.atob` does. + * @param {string} b64 Base64 encoded string + * @returns {string} Binary string + * @see https://developer.mozilla.org/en-US/docs/Web/API/Window.atob + * @expose + */ + ByteBuffer.atob = function(b64) { + return ByteBuffer.fromBase64(b64).toBinary(); + }; + + // encodings/binary + + /** + * Encodes this ByteBuffer to a binary encoded string, that is using only characters 0x00-0xFF as bytes. + * @param {number=} begin Offset to begin at. Defaults to {@link ByteBuffer#offset}. + * @param {number=} end Offset to end at. Defaults to {@link ByteBuffer#limit}. + * @returns {string} Binary encoded string + * @throws {RangeError} If `offset > limit` + * @expose + */ + ByteBufferPrototype.toBinary = function(begin, end) { + begin = typeof begin === 'undefined' ? this.offset : begin; + end = typeof end === 'undefined' ? this.limit : end; + if (!this.noAssert) { if (typeof begin !== 'number' || begin % 1 !== 0) throw TypeError("Illegal begin: Not an integer"); begin >>>= 0; @@ -29335,237 +29321,237 @@ Curve25519Worker.prototype = { end >>>= 0; if (begin < 0 || begin > end || end > this.buffer.byteLength) throw RangeError("Illegal range: 0 <= "+begin+" <= "+end+" <= "+this.buffer.byteLength); - } - if (begin === end) - return ""; - var cc = [], pt = []; - while (begin < end) { - cc.push(this.view.getUint8(begin++)); - if (cc.length >= 1024) - pt.push(String.fromCharCode.apply(String, cc)), - cc = []; - } - return pt.join('') + String.fromCharCode.apply(String, cc); - }; - - /** - * Decodes a binary encoded string, that is using only characters 0x00-0xFF as bytes, to a ByteBuffer. - * @param {string} str String to decode - * @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} ByteBuffer - * @expose - */ - ByteBuffer.fromBinary = function(str, littleEndian, noAssert) { - if (!noAssert) { - if (typeof str !== 'string') - throw TypeError("Illegal str: Not a string"); - } - var i = 0, k = str.length, charCode, - bb = new ByteBuffer(k, littleEndian, noAssert); - while (i 255) - throw RangeError("Illegal charCode at "+i+": 0 <= "+charCode+" <= 255"); - bb.view.setUint8(i++, charCode); - } - bb.limit = k; - return bb; - }; - - // encodings/debug - - /** - * Encodes this ByteBuffer to a hex encoded string with marked offsets. Offset symbols are: - * * `<` : offset, - * * `'` : markedOffset, - * * `>` : limit, - * * `|` : offset and limit, - * * `[` : offset and markedOffset, - * * `]` : markedOffset and limit, - * * `!` : offset, markedOffset and limit - * @param {boolean=} columns If `true` returns two columns hex + ascii, defaults to `false` - * @returns {string|!Array.} Debug string or array of lines if `asArray = true` - * @expose - * @example `>00'01 02<03` contains four bytes with `limit=0, markedOffset=1, offset=3` - * @example `00[01 02 03>` contains four bytes with `offset=markedOffset=1, limit=4` - * @example `00|01 02 03` contains four bytes with `offset=limit=1, markedOffset=-1` - * @example `|` contains zero bytes with `offset=limit=0, markedOffset=-1` - */ - ByteBufferPrototype.toDebug = function(columns) { - var i = -1, - k = this.buffer.byteLength, - b, - hex = "", - asc = "", - out = ""; - while (i 32 && b < 127 ? String.fromCharCode(b) : '.'; - } - } - ++i; - if (columns) { - if (i > 0 && i % 16 === 0 && i !== k) { - while (hex.length < 3*16+3) hex += " "; - out += hex+asc+"\n"; - hex = asc = ""; - } - } - if (i === this.offset && i === this.limit) - hex += i === this.markedOffset ? "!" : "|"; - else if (i === this.offset) - hex += i === this.markedOffset ? "[" : "<"; - else if (i === this.limit) - hex += i === this.markedOffset ? "]" : ">"; - else - hex += i === this.markedOffset ? "'" : (columns || (i !== 0 && i !== k) ? " " : ""); - } - if (columns && hex !== " ") { - while (hex.length < 3*16+3) hex += " "; - out += hex+asc+"\n"; - } - return columns ? out : hex; - }; - - /** - * Decodes a hex encoded string with marked offsets to a ByteBuffer. - * @param {string} str Debug string to decode (not be generated with `columns = true`) - * @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} ByteBuffer - * @expose - * @see ByteBuffer#toDebug - */ - ByteBuffer.fromDebug = function(str, littleEndian, noAssert) { - var k = str.length, - bb = new ByteBuffer(((k+1)/3)|0, littleEndian, noAssert); - var i = 0, j = 0, ch, b, - rs = false, // Require symbol next - ho = false, hm = false, hl = false, // Already has offset, markedOffset, limit? - fail = false; - while (i': - if (!noAssert) { - if (hl) { - fail = true; break; - } - hl = true; - } - bb.limit = j; - rs = false; - break; - case "'": - if (!noAssert) { - if (hm) { - fail = true; break; - } - hm = true; - } - bb.markedOffset = j; - rs = false; - break; - case ' ': - rs = false; - break; - default: - if (!noAssert) { - if (rs) { - fail = true; break; - } - } - b = parseInt(ch+str.charAt(i++), 16); - if (!noAssert) { - if (isNaN(b) || b < 0 || b > 255) - throw TypeError("Illegal str: Not a debug encoded string"); - } - bb.view.setUint8(j++, b); - rs = true; - } - if (fail) - throw TypeError("Illegal str: Invalid symbol at "+i); - } - if (!noAssert) { - if (!ho || !hl) - throw TypeError("Illegal str: Missing offset or limit"); - if (j= 1024) + pt.push(String.fromCharCode.apply(String, cc)), + cc = []; + } + return pt.join('') + String.fromCharCode.apply(String, cc); + }; + + /** + * Decodes a binary encoded string, that is using only characters 0x00-0xFF as bytes, to a ByteBuffer. + * @param {string} str String to decode + * @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} ByteBuffer + * @expose + */ + ByteBuffer.fromBinary = function(str, littleEndian, noAssert) { + if (!noAssert) { + if (typeof str !== 'string') + throw TypeError("Illegal str: Not a string"); + } + var i = 0, k = str.length, charCode, + bb = new ByteBuffer(k, littleEndian, noAssert); + while (i 255) + throw RangeError("Illegal charCode at "+i+": 0 <= "+charCode+" <= 255"); + bb.view.setUint8(i++, charCode); + } + bb.limit = k; + return bb; + }; + + // encodings/debug + + /** + * Encodes this ByteBuffer to a hex encoded string with marked offsets. Offset symbols are: + * * `<` : offset, + * * `'` : markedOffset, + * * `>` : limit, + * * `|` : offset and limit, + * * `[` : offset and markedOffset, + * * `]` : markedOffset and limit, + * * `!` : offset, markedOffset and limit + * @param {boolean=} columns If `true` returns two columns hex + ascii, defaults to `false` + * @returns {string|!Array.} Debug string or array of lines if `asArray = true` + * @expose + * @example `>00'01 02<03` contains four bytes with `limit=0, markedOffset=1, offset=3` + * @example `00[01 02 03>` contains four bytes with `offset=markedOffset=1, limit=4` + * @example `00|01 02 03` contains four bytes with `offset=limit=1, markedOffset=-1` + * @example `|` contains zero bytes with `offset=limit=0, markedOffset=-1` + */ + ByteBufferPrototype.toDebug = function(columns) { + var i = -1, + k = this.buffer.byteLength, + b, + hex = "", + asc = "", + out = ""; + while (i 32 && b < 127 ? String.fromCharCode(b) : '.'; + } + } + ++i; + if (columns) { + if (i > 0 && i % 16 === 0 && i !== k) { + while (hex.length < 3*16+3) hex += " "; + out += hex+asc+"\n"; + hex = asc = ""; + } + } + if (i === this.offset && i === this.limit) + hex += i === this.markedOffset ? "!" : "|"; + else if (i === this.offset) + hex += i === this.markedOffset ? "[" : "<"; + else if (i === this.limit) + hex += i === this.markedOffset ? "]" : ">"; + else + hex += i === this.markedOffset ? "'" : (columns || (i !== 0 && i !== k) ? " " : ""); + } + if (columns && hex !== " ") { + while (hex.length < 3*16+3) hex += " "; + out += hex+asc+"\n"; + } + return columns ? out : hex; + }; + + /** + * Decodes a hex encoded string with marked offsets to a ByteBuffer. + * @param {string} str Debug string to decode (not be generated with `columns = true`) + * @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} ByteBuffer + * @expose + * @see ByteBuffer#toDebug + */ + ByteBuffer.fromDebug = function(str, littleEndian, noAssert) { + var k = str.length, + bb = new ByteBuffer(((k+1)/3)|0, littleEndian, noAssert); + var i = 0, j = 0, ch, b, + rs = false, // Require symbol next + ho = false, hm = false, hl = false, // Already has offset, markedOffset, limit? + fail = false; + while (i': + if (!noAssert) { + if (hl) { + fail = true; break; + } + hl = true; + } + bb.limit = j; + rs = false; + break; + case "'": + if (!noAssert) { + if (hm) { + fail = true; break; + } + hm = true; + } + bb.markedOffset = j; + rs = false; + break; + case ' ': + rs = false; + break; + default: + if (!noAssert) { + if (rs) { + fail = true; break; + } + } + b = parseInt(ch+str.charAt(i++), 16); + if (!noAssert) { + if (isNaN(b) || b < 0 || b > 255) + throw TypeError("Illegal str: Not a debug encoded string"); + } + bb.view.setUint8(j++, b); + rs = true; + } + if (fail) + throw TypeError("Illegal str: Invalid symbol at "+i); + } + if (!noAssert) { + if (!ho || !hl) + throw TypeError("Illegal str: Missing offset or limit"); + if (j>>= 0; @@ -29574,261 +29560,261 @@ Curve25519Worker.prototype = { end >>>= 0; if (begin < 0 || begin > end || end > this.buffer.byteLength) throw RangeError("Illegal range: 0 <= "+begin+" <= "+end+" <= "+this.buffer.byteLength); - } - var out = new Array(end - begin), - b; - while (begin < end) { - b = this.view.getUint8(begin++); - if (b < 0x10) - out.push("0", b.toString(16)); - else out.push(b.toString(16)); - } - return out.join(''); - }; - - /** - * Decodes a hex encoded string to a ByteBuffer. - * @param {string} str String to decode - * @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} ByteBuffer - * @expose - */ - ByteBuffer.fromHex = function(str, littleEndian, noAssert) { - if (!noAssert) { - if (typeof str !== 'string') - throw TypeError("Illegal str: Not a string"); - if (str.length % 2 !== 0) - throw TypeError("Illegal str: Length not a multiple of 2"); - } - var k = str.length, - bb = new ByteBuffer((k / 2) | 0, littleEndian), - b; - for (var i=0, j=0; i 255) - throw TypeError("Illegal str: Contains non-hex characters"); - bb.view.setUint8(j++, b); - } - bb.limit = j; - return bb; - }; - - // utfx-embeddable - - /** - * utfx-embeddable (c) 2014 Daniel Wirtz - * Released under the Apache License, Version 2.0 - * see: https://github.com/dcodeIO/utfx for details - */ - var utfx = function() { - "use strict"; - - /** - * utfx namespace. - * @inner - * @type {!Object.} - */ - var utfx = {}; - - /** - * Maximum valid code point. - * @type {number} - * @const - */ - utfx.MAX_CODEPOINT = 0x10FFFF; - - /** - * Encodes UTF8 code points to UTF8 bytes. - * @param {(!function():number|null) | number} src Code points source, either as a function returning the next code point - * respectively `null` if there are no more code points left or a single numeric code point. - * @param {!function(number)} dst Bytes destination as a function successively called with the next byte - */ - utfx.encodeUTF8 = function(src, dst) { - var cp = null; - if (typeof src === 'number') - cp = src, - src = function() { return null; }; - while (cp !== null || (cp = src()) !== null) { - if (cp < 0x80) - dst(cp&0x7F); - else if (cp < 0x800) - dst(((cp>>6)&0x1F)|0xC0), - dst((cp&0x3F)|0x80); - else if (cp < 0x10000) - dst(((cp>>12)&0x0F)|0xE0), - dst(((cp>>6)&0x3F)|0x80), - dst((cp&0x3F)|0x80); - else - dst(((cp>>18)&0x07)|0xF0), - dst(((cp>>12)&0x3F)|0x80), - dst(((cp>>6)&0x3F)|0x80), - dst((cp&0x3F)|0x80); - cp = null; - } - }; - - /** - * Decodes UTF8 bytes to UTF8 code points. - * @param {!function():number|null} src Bytes source as a function returning the next byte respectively `null` if there - * are no more bytes left. - * @param {!function(number)} dst Code points destination as a function successively called with each decoded code point. - * @throws {RangeError} If a starting byte is invalid in UTF8 - * @throws {Error} If the last sequence is truncated. Has an array property `bytes` holding the - * remaining bytes. - */ - utfx.decodeUTF8 = function(src, dst) { - var a, b, c, d, fail = function(b) { - b = b.slice(0, b.indexOf(null)); - var err = Error(b.toString()); - err.name = "TruncatedError"; - err['bytes'] = b; - throw err; - }; - while ((a = src()) !== null) { - if ((a&0x80) === 0) - dst(a); - else if ((a&0xE0) === 0xC0) - ((b = src()) === null) && fail([a, b]), - dst(((a&0x1F)<<6) | (b&0x3F)); - else if ((a&0xF0) === 0xE0) - ((b=src()) === null || (c=src()) === null) && fail([a, b, c]), - dst(((a&0x0F)<<12) | ((b&0x3F)<<6) | (c&0x3F)); - else if ((a&0xF8) === 0xF0) - ((b=src()) === null || (c=src()) === null || (d=src()) === null) && fail([a, b, c ,d]), - dst(((a&0x07)<<18) | ((b&0x3F)<<12) | ((c&0x3F)<<6) | (d&0x3F)); - else throw RangeError("Illegal starting byte: "+a); - } - }; - - /** - * Converts UTF16 characters to UTF8 code points. - * @param {!function():number|null} src Characters source as a function returning the next char code respectively - * `null` if there are no more characters left. - * @param {!function(number)} dst Code points destination as a function successively called with each converted code - * point. - */ - utfx.UTF16toUTF8 = function(src, dst) { - var c1, c2 = null; - while (true) { - if ((c1 = c2 !== null ? c2 : src()) === null) - break; - if (c1 >= 0xD800 && c1 <= 0xDFFF) { - if ((c2 = src()) !== null) { - if (c2 >= 0xDC00 && c2 <= 0xDFFF) { - dst((c1-0xD800)*0x400+c2-0xDC00+0x10000); - c2 = null; continue; - } - } - } - dst(c1); - } - if (c2 !== null) dst(c2); - }; - - /** - * Converts UTF8 code points to UTF16 characters. - * @param {(!function():number|null) | number} src Code points source, either as a function returning the next code point - * respectively `null` if there are no more code points left or a single numeric code point. - * @param {!function(number)} dst Characters destination as a function successively called with each converted char code. - * @throws {RangeError} If a code point is out of range - */ - utfx.UTF8toUTF16 = function(src, dst) { - var cp = null; - if (typeof src === 'number') - cp = src, src = function() { return null; }; - while (cp !== null || (cp = src()) !== null) { - if (cp <= 0xFFFF) - dst(cp); - else - cp -= 0x10000, - dst((cp>>10)+0xD800), - dst((cp%0x400)+0xDC00); - cp = null; - } - }; - - /** - * Converts and encodes UTF16 characters to UTF8 bytes. - * @param {!function():number|null} src Characters source as a function returning the next char code respectively `null` - * if there are no more characters left. - * @param {!function(number)} dst Bytes destination as a function successively called with the next byte. - */ - utfx.encodeUTF16toUTF8 = function(src, dst) { - utfx.UTF16toUTF8(src, function(cp) { - utfx.encodeUTF8(cp, dst); - }); - }; - - /** - * Decodes and converts UTF8 bytes to UTF16 characters. - * @param {!function():number|null} src Bytes source as a function returning the next byte respectively `null` if there - * are no more bytes left. - * @param {!function(number)} dst Characters destination as a function successively called with each converted char code. - * @throws {RangeError} If a starting byte is invalid in UTF8 - * @throws {Error} If the last sequence is truncated. Has an array property `bytes` holding the remaining bytes. - */ - utfx.decodeUTF8toUTF16 = function(src, dst) { - utfx.decodeUTF8(src, function(cp) { - utfx.UTF8toUTF16(cp, dst); - }); - }; - - /** - * Calculates the byte length of an UTF8 code point. - * @param {number} cp UTF8 code point - * @returns {number} Byte length - */ - utfx.calculateCodePoint = function(cp) { - return (cp < 0x80) ? 1 : (cp < 0x800) ? 2 : (cp < 0x10000) ? 3 : 4; - }; - - /** - * Calculates the number of UTF8 bytes required to store UTF8 code points. - * @param {(!function():number|null)} src Code points source as a function returning the next code point respectively - * `null` if there are no more code points left. - * @returns {number} The number of UTF8 bytes required - */ - utfx.calculateUTF8 = function(src) { - var cp, l=0; - while ((cp = src()) !== null) - l += utfx.calculateCodePoint(cp); - return l; - }; - - /** - * Calculates the number of UTF8 code points respectively UTF8 bytes required to store UTF16 char codes. - * @param {(!function():number|null)} src Characters source as a function returning the next char code respectively - * `null` if there are no more characters left. - * @returns {!Array.} The number of UTF8 code points at index 0 and the number of UTF8 bytes required at index 1. - */ - utfx.calculateUTF16asUTF8 = function(src) { - var n=0, l=0; - utfx.UTF16toUTF8(src, function(cp) { - ++n; l += utfx.calculateCodePoint(cp); - }); - return [n,l]; - }; - - return utfx; - }(); - - // encodings/utf8 - - /** - * Encodes this ByteBuffer's contents between {@link ByteBuffer#offset} and {@link ByteBuffer#limit} to an UTF8 encoded - * string. - * @returns {string} Hex encoded string - * @throws {RangeError} If `offset > limit` - * @expose - */ - ByteBufferPrototype.toUTF8 = function(begin, end) { - if (typeof begin === 'undefined') begin = this.offset; - if (typeof end === 'undefined') end = this.limit; - if (!this.noAssert) { + } + var out = new Array(end - begin), + b; + while (begin < end) { + b = this.view.getUint8(begin++); + if (b < 0x10) + out.push("0", b.toString(16)); + else out.push(b.toString(16)); + } + return out.join(''); + }; + + /** + * Decodes a hex encoded string to a ByteBuffer. + * @param {string} str String to decode + * @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} ByteBuffer + * @expose + */ + ByteBuffer.fromHex = function(str, littleEndian, noAssert) { + if (!noAssert) { + if (typeof str !== 'string') + throw TypeError("Illegal str: Not a string"); + if (str.length % 2 !== 0) + throw TypeError("Illegal str: Length not a multiple of 2"); + } + var k = str.length, + bb = new ByteBuffer((k / 2) | 0, littleEndian), + b; + for (var i=0, j=0; i 255) + throw TypeError("Illegal str: Contains non-hex characters"); + bb.view.setUint8(j++, b); + } + bb.limit = j; + return bb; + }; + + // utfx-embeddable + + /** + * utfx-embeddable (c) 2014 Daniel Wirtz + * Released under the Apache License, Version 2.0 + * see: https://github.com/dcodeIO/utfx for details + */ + var utfx = function() { + "use strict"; + + /** + * utfx namespace. + * @inner + * @type {!Object.} + */ + var utfx = {}; + + /** + * Maximum valid code point. + * @type {number} + * @const + */ + utfx.MAX_CODEPOINT = 0x10FFFF; + + /** + * Encodes UTF8 code points to UTF8 bytes. + * @param {(!function():number|null) | number} src Code points source, either as a function returning the next code point + * respectively `null` if there are no more code points left or a single numeric code point. + * @param {!function(number)} dst Bytes destination as a function successively called with the next byte + */ + utfx.encodeUTF8 = function(src, dst) { + var cp = null; + if (typeof src === 'number') + cp = src, + src = function() { return null; }; + while (cp !== null || (cp = src()) !== null) { + if (cp < 0x80) + dst(cp&0x7F); + else if (cp < 0x800) + dst(((cp>>6)&0x1F)|0xC0), + dst((cp&0x3F)|0x80); + else if (cp < 0x10000) + dst(((cp>>12)&0x0F)|0xE0), + dst(((cp>>6)&0x3F)|0x80), + dst((cp&0x3F)|0x80); + else + dst(((cp>>18)&0x07)|0xF0), + dst(((cp>>12)&0x3F)|0x80), + dst(((cp>>6)&0x3F)|0x80), + dst((cp&0x3F)|0x80); + cp = null; + } + }; + + /** + * Decodes UTF8 bytes to UTF8 code points. + * @param {!function():number|null} src Bytes source as a function returning the next byte respectively `null` if there + * are no more bytes left. + * @param {!function(number)} dst Code points destination as a function successively called with each decoded code point. + * @throws {RangeError} If a starting byte is invalid in UTF8 + * @throws {Error} If the last sequence is truncated. Has an array property `bytes` holding the + * remaining bytes. + */ + utfx.decodeUTF8 = function(src, dst) { + var a, b, c, d, fail = function(b) { + b = b.slice(0, b.indexOf(null)); + var err = Error(b.toString()); + err.name = "TruncatedError"; + err['bytes'] = b; + throw err; + }; + while ((a = src()) !== null) { + if ((a&0x80) === 0) + dst(a); + else if ((a&0xE0) === 0xC0) + ((b = src()) === null) && fail([a, b]), + dst(((a&0x1F)<<6) | (b&0x3F)); + else if ((a&0xF0) === 0xE0) + ((b=src()) === null || (c=src()) === null) && fail([a, b, c]), + dst(((a&0x0F)<<12) | ((b&0x3F)<<6) | (c&0x3F)); + else if ((a&0xF8) === 0xF0) + ((b=src()) === null || (c=src()) === null || (d=src()) === null) && fail([a, b, c ,d]), + dst(((a&0x07)<<18) | ((b&0x3F)<<12) | ((c&0x3F)<<6) | (d&0x3F)); + else throw RangeError("Illegal starting byte: "+a); + } + }; + + /** + * Converts UTF16 characters to UTF8 code points. + * @param {!function():number|null} src Characters source as a function returning the next char code respectively + * `null` if there are no more characters left. + * @param {!function(number)} dst Code points destination as a function successively called with each converted code + * point. + */ + utfx.UTF16toUTF8 = function(src, dst) { + var c1, c2 = null; + while (true) { + if ((c1 = c2 !== null ? c2 : src()) === null) + break; + if (c1 >= 0xD800 && c1 <= 0xDFFF) { + if ((c2 = src()) !== null) { + if (c2 >= 0xDC00 && c2 <= 0xDFFF) { + dst((c1-0xD800)*0x400+c2-0xDC00+0x10000); + c2 = null; continue; + } + } + } + dst(c1); + } + if (c2 !== null) dst(c2); + }; + + /** + * Converts UTF8 code points to UTF16 characters. + * @param {(!function():number|null) | number} src Code points source, either as a function returning the next code point + * respectively `null` if there are no more code points left or a single numeric code point. + * @param {!function(number)} dst Characters destination as a function successively called with each converted char code. + * @throws {RangeError} If a code point is out of range + */ + utfx.UTF8toUTF16 = function(src, dst) { + var cp = null; + if (typeof src === 'number') + cp = src, src = function() { return null; }; + while (cp !== null || (cp = src()) !== null) { + if (cp <= 0xFFFF) + dst(cp); + else + cp -= 0x10000, + dst((cp>>10)+0xD800), + dst((cp%0x400)+0xDC00); + cp = null; + } + }; + + /** + * Converts and encodes UTF16 characters to UTF8 bytes. + * @param {!function():number|null} src Characters source as a function returning the next char code respectively `null` + * if there are no more characters left. + * @param {!function(number)} dst Bytes destination as a function successively called with the next byte. + */ + utfx.encodeUTF16toUTF8 = function(src, dst) { + utfx.UTF16toUTF8(src, function(cp) { + utfx.encodeUTF8(cp, dst); + }); + }; + + /** + * Decodes and converts UTF8 bytes to UTF16 characters. + * @param {!function():number|null} src Bytes source as a function returning the next byte respectively `null` if there + * are no more bytes left. + * @param {!function(number)} dst Characters destination as a function successively called with each converted char code. + * @throws {RangeError} If a starting byte is invalid in UTF8 + * @throws {Error} If the last sequence is truncated. Has an array property `bytes` holding the remaining bytes. + */ + utfx.decodeUTF8toUTF16 = function(src, dst) { + utfx.decodeUTF8(src, function(cp) { + utfx.UTF8toUTF16(cp, dst); + }); + }; + + /** + * Calculates the byte length of an UTF8 code point. + * @param {number} cp UTF8 code point + * @returns {number} Byte length + */ + utfx.calculateCodePoint = function(cp) { + return (cp < 0x80) ? 1 : (cp < 0x800) ? 2 : (cp < 0x10000) ? 3 : 4; + }; + + /** + * Calculates the number of UTF8 bytes required to store UTF8 code points. + * @param {(!function():number|null)} src Code points source as a function returning the next code point respectively + * `null` if there are no more code points left. + * @returns {number} The number of UTF8 bytes required + */ + utfx.calculateUTF8 = function(src) { + var cp, l=0; + while ((cp = src()) !== null) + l += utfx.calculateCodePoint(cp); + return l; + }; + + /** + * Calculates the number of UTF8 code points respectively UTF8 bytes required to store UTF16 char codes. + * @param {(!function():number|null)} src Characters source as a function returning the next char code respectively + * `null` if there are no more characters left. + * @returns {!Array.} The number of UTF8 code points at index 0 and the number of UTF8 bytes required at index 1. + */ + utfx.calculateUTF16asUTF8 = function(src) { + var n=0, l=0; + utfx.UTF16toUTF8(src, function(cp) { + ++n; l += utfx.calculateCodePoint(cp); + }); + return [n,l]; + }; + + return utfx; + }(); + + // encodings/utf8 + + /** + * Encodes this ByteBuffer's contents between {@link ByteBuffer#offset} and {@link ByteBuffer#limit} to an UTF8 encoded + * string. + * @returns {string} Hex encoded string + * @throws {RangeError} If `offset > limit` + * @expose + */ + ByteBufferPrototype.toUTF8 = function(begin, end) { + if (typeof begin === 'undefined') begin = this.offset; + if (typeof end === 'undefined') end = this.limit; + if (!this.noAssert) { if (typeof begin !== 'number' || begin % 1 !== 0) throw TypeError("Illegal begin: Not an integer"); begin >>>= 0; @@ -29837,348 +29823,348 @@ Curve25519Worker.prototype = { end >>>= 0; if (begin < 0 || begin > end || end > this.buffer.byteLength) throw RangeError("Illegal range: 0 <= "+begin+" <= "+end+" <= "+this.buffer.byteLength); - } - var sd; try { - utfx.decodeUTF8toUTF16(function() { - return begin < end ? this.view.getUint8(begin++) : null; - }.bind(this), sd = stringDestination()); - } catch (e) { - if (begin !== end) - throw RangeError("Illegal range: Truncated data, "+begin+" != "+end); - } - return sd(); - }; - - /** - * Decodes an UTF8 encoded string to a ByteBuffer. - * @param {string} str String to decode - * @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} ByteBuffer - * @expose - */ - ByteBuffer.fromUTF8 = function(str, littleEndian, noAssert) { - if (!noAssert) - if (typeof str !== 'string') - throw TypeError("Illegal str: Not a string"); - var bb = new ByteBuffer(utfx.calculateUTF16asUTF8(stringSource(str), true)[1], littleEndian, noAssert), - i = 0; - utfx.encodeUTF16toUTF8(stringSource(str), function(b) { - bb.view.setUint8(i++, b); - }); - bb.limit = i; - return bb; - }; - - - return ByteBuffer; - } - - /* CommonJS */ if (typeof require === 'function' && typeof module === 'object' && module && typeof exports === 'object' && exports) - module['exports'] = (function() { - var Long; try { Long = require("long"); } catch (e) {} - return loadByteBuffer(Long); - })(); - /* AMD */ else if (typeof define === 'function' && define["amd"]) - define("ByteBuffer", ["Long"], function(Long) { return loadByteBuffer(Long); }); - /* Global */ else - (global["dcodeIO"] = global["dcodeIO"] || {})["ByteBuffer"] = loadByteBuffer(global["dcodeIO"]["Long"]); - -})(this); - -/* - Copyright 2013 Daniel Wirtz - - 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 protobuf.js (c) 2013 Daniel Wirtz - * Released under the Apache License, Version 2.0 - * see: https://github.com/dcodeIO/protobuf.js for details - */ -(function(global, factory) { - - /* AMD */ if (typeof define === 'function' && define["amd"]) - define(["bytebuffer"], factory); - /* CommonJS */ else if (typeof require === "function" && typeof module === "object" && module && module["exports"]) - module["exports"] = factory(require("bytebuffer"), true); - /* Global */ else - (global["dcodeIO"] = global["dcodeIO"] || {})["ProtoBuf"] = factory(global["dcodeIO"]["ByteBuffer"]); - -})(this, function(ByteBuffer, isCommonJS) { - "use strict"; - - /** - * The ProtoBuf namespace. - * @exports ProtoBuf - * @namespace - * @expose - */ - var ProtoBuf = {}; - - /** - * @type {!function(new: ByteBuffer, ...[*])} - * @expose - */ - ProtoBuf.ByteBuffer = ByteBuffer; - - /** - * @type {?function(new: Long, ...[*])} - * @expose - */ - ProtoBuf.Long = ByteBuffer.Long || null; - - /** - * ProtoBuf.js version. - * @type {string} - * @const - * @expose - */ - ProtoBuf.VERSION = "5.0.1"; - - /** - * Wire types. - * @type {Object.} - * @const - * @expose - */ - ProtoBuf.WIRE_TYPES = {}; - - /** - * Varint wire type. - * @type {number} - * @expose - */ - ProtoBuf.WIRE_TYPES.VARINT = 0; - - /** - * Fixed 64 bits wire type. - * @type {number} - * @const - * @expose - */ - ProtoBuf.WIRE_TYPES.BITS64 = 1; - - /** - * Length delimited wire type. - * @type {number} - * @const - * @expose - */ - ProtoBuf.WIRE_TYPES.LDELIM = 2; - - /** - * Start group wire type. - * @type {number} - * @const - * @expose - */ - ProtoBuf.WIRE_TYPES.STARTGROUP = 3; - - /** - * End group wire type. - * @type {number} - * @const - * @expose - */ - ProtoBuf.WIRE_TYPES.ENDGROUP = 4; - - /** - * Fixed 32 bits wire type. - * @type {number} - * @const - * @expose - */ - ProtoBuf.WIRE_TYPES.BITS32 = 5; - - /** - * Packable wire types. - * @type {!Array.} - * @const - * @expose - */ - ProtoBuf.PACKABLE_WIRE_TYPES = [ - ProtoBuf.WIRE_TYPES.VARINT, - ProtoBuf.WIRE_TYPES.BITS64, - ProtoBuf.WIRE_TYPES.BITS32 - ]; - - /** - * Types. - * @dict - * @type {!Object.} - * @const - * @expose - */ - ProtoBuf.TYPES = { - // According to the protobuf spec. - "int32": { - name: "int32", - wireType: ProtoBuf.WIRE_TYPES.VARINT, - defaultValue: 0 - }, - "uint32": { - name: "uint32", - wireType: ProtoBuf.WIRE_TYPES.VARINT, - defaultValue: 0 - }, - "sint32": { - name: "sint32", - wireType: ProtoBuf.WIRE_TYPES.VARINT, - defaultValue: 0 - }, - "int64": { - name: "int64", - wireType: ProtoBuf.WIRE_TYPES.VARINT, - defaultValue: ProtoBuf.Long ? ProtoBuf.Long.ZERO : undefined - }, - "uint64": { - name: "uint64", - wireType: ProtoBuf.WIRE_TYPES.VARINT, - defaultValue: ProtoBuf.Long ? ProtoBuf.Long.UZERO : undefined - }, - "sint64": { - name: "sint64", - wireType: ProtoBuf.WIRE_TYPES.VARINT, - defaultValue: ProtoBuf.Long ? ProtoBuf.Long.ZERO : undefined - }, - "bool": { - name: "bool", - wireType: ProtoBuf.WIRE_TYPES.VARINT, - defaultValue: false - }, - "double": { - name: "double", - wireType: ProtoBuf.WIRE_TYPES.BITS64, - defaultValue: 0 - }, - "string": { - name: "string", - wireType: ProtoBuf.WIRE_TYPES.LDELIM, - defaultValue: "" - }, - "bytes": { - name: "bytes", - wireType: ProtoBuf.WIRE_TYPES.LDELIM, - defaultValue: null // overridden in the code, must be a unique instance - }, - "fixed32": { - name: "fixed32", - wireType: ProtoBuf.WIRE_TYPES.BITS32, - defaultValue: 0 - }, - "sfixed32": { - name: "sfixed32", - wireType: ProtoBuf.WIRE_TYPES.BITS32, - defaultValue: 0 - }, - "fixed64": { - name: "fixed64", - wireType: ProtoBuf.WIRE_TYPES.BITS64, - defaultValue: ProtoBuf.Long ? ProtoBuf.Long.UZERO : undefined - }, - "sfixed64": { - name: "sfixed64", - wireType: ProtoBuf.WIRE_TYPES.BITS64, - defaultValue: ProtoBuf.Long ? ProtoBuf.Long.ZERO : undefined - }, - "float": { - name: "float", - wireType: ProtoBuf.WIRE_TYPES.BITS32, - defaultValue: 0 - }, - "enum": { - name: "enum", - wireType: ProtoBuf.WIRE_TYPES.VARINT, - defaultValue: 0 - }, - "message": { - name: "message", - wireType: ProtoBuf.WIRE_TYPES.LDELIM, - defaultValue: null - }, - "group": { - name: "group", - wireType: ProtoBuf.WIRE_TYPES.STARTGROUP, - defaultValue: null - } - }; - - /** - * Valid map key types. - * @type {!Array.>} - * @const - * @expose - */ - ProtoBuf.MAP_KEY_TYPES = [ - ProtoBuf.TYPES["int32"], - ProtoBuf.TYPES["sint32"], - ProtoBuf.TYPES["sfixed32"], - ProtoBuf.TYPES["uint32"], - ProtoBuf.TYPES["fixed32"], - ProtoBuf.TYPES["int64"], - ProtoBuf.TYPES["sint64"], - ProtoBuf.TYPES["sfixed64"], - ProtoBuf.TYPES["uint64"], - ProtoBuf.TYPES["fixed64"], - ProtoBuf.TYPES["bool"], - ProtoBuf.TYPES["string"], - ProtoBuf.TYPES["bytes"] - ]; - - /** - * Minimum field id. - * @type {number} - * @const - * @expose - */ - ProtoBuf.ID_MIN = 1; - - /** - * Maximum field id. - * @type {number} - * @const - * @expose - */ - ProtoBuf.ID_MAX = 0x1FFFFFFF; - - /** - * If set to `true`, field names will be converted from underscore notation to camel case. Defaults to `false`. - * Must be set prior to parsing. - * @type {boolean} - * @expose - */ - ProtoBuf.convertFieldsToCamelCase = false; - - /** - * By default, messages are populated with (setX, set_x) accessors for each field. This can be disabled by - * setting this to `false` prior to building messages. - * @type {boolean} - * @expose - */ - ProtoBuf.populateAccessors = true; - - /** - * By default, messages are populated with default values if a field is not present on the wire. To disable - * this behavior, set this setting to `false`. - * @type {boolean} - * @expose - */ - ProtoBuf.populateDefaults = true; + } + var sd; try { + utfx.decodeUTF8toUTF16(function() { + return begin < end ? this.view.getUint8(begin++) : null; + }.bind(this), sd = stringDestination()); + } catch (e) { + if (begin !== end) + throw RangeError("Illegal range: Truncated data, "+begin+" != "+end); + } + return sd(); + }; + + /** + * Decodes an UTF8 encoded string to a ByteBuffer. + * @param {string} str String to decode + * @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} ByteBuffer + * @expose + */ + ByteBuffer.fromUTF8 = function(str, littleEndian, noAssert) { + if (!noAssert) + if (typeof str !== 'string') + throw TypeError("Illegal str: Not a string"); + var bb = new ByteBuffer(utfx.calculateUTF16asUTF8(stringSource(str), true)[1], littleEndian, noAssert), + i = 0; + utfx.encodeUTF16toUTF8(stringSource(str), function(b) { + bb.view.setUint8(i++, b); + }); + bb.limit = i; + return bb; + }; + + + return ByteBuffer; + } + + /* CommonJS */ if (typeof require === 'function' && typeof module === 'object' && module && typeof exports === 'object' && exports) + module['exports'] = (function() { + var Long; try { Long = require("long"); } catch (e) {} + return loadByteBuffer(Long); + })(); + /* AMD */ else if (typeof define === 'function' && define["amd"]) + define("ByteBuffer", ["Long"], function(Long) { return loadByteBuffer(Long); }); + /* Global */ else + (global["dcodeIO"] = global["dcodeIO"] || {})["ByteBuffer"] = loadByteBuffer(global["dcodeIO"]["Long"]); + +})(this); +/* + Copyright 2013 Daniel Wirtz + + 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 protobuf.js (c) 2013 Daniel Wirtz + * Released under the Apache License, Version 2.0 + * see: https://github.com/dcodeIO/protobuf.js for details + */ +(function(global, factory) { + + /* AMD */ if (typeof define === 'function' && define["amd"]) + define(["bytebuffer"], factory); + /* CommonJS */ else if (typeof require === "function" && typeof module === "object" && module && module["exports"]) + module["exports"] = factory(require("bytebuffer"), true); + /* Global */ else + (global["dcodeIO"] = global["dcodeIO"] || {})["ProtoBuf"] = factory(global["dcodeIO"]["ByteBuffer"]); + +})(this, function(ByteBuffer, isCommonJS) { + "use strict"; + + /** + * The ProtoBuf namespace. + * @exports ProtoBuf + * @namespace + * @expose + */ + var ProtoBuf = {}; + + /** + * @type {!function(new: ByteBuffer, ...[*])} + * @expose + */ + ProtoBuf.ByteBuffer = ByteBuffer; + + /** + * @type {?function(new: Long, ...[*])} + * @expose + */ + ProtoBuf.Long = ByteBuffer.Long || null; + + /** + * ProtoBuf.js version. + * @type {string} + * @const + * @expose + */ + ProtoBuf.VERSION = "5.0.1"; + + /** + * Wire types. + * @type {Object.} + * @const + * @expose + */ + ProtoBuf.WIRE_TYPES = {}; + + /** + * Varint wire type. + * @type {number} + * @expose + */ + ProtoBuf.WIRE_TYPES.VARINT = 0; + + /** + * Fixed 64 bits wire type. + * @type {number} + * @const + * @expose + */ + ProtoBuf.WIRE_TYPES.BITS64 = 1; + + /** + * Length delimited wire type. + * @type {number} + * @const + * @expose + */ + ProtoBuf.WIRE_TYPES.LDELIM = 2; + + /** + * Start group wire type. + * @type {number} + * @const + * @expose + */ + ProtoBuf.WIRE_TYPES.STARTGROUP = 3; + + /** + * End group wire type. + * @type {number} + * @const + * @expose + */ + ProtoBuf.WIRE_TYPES.ENDGROUP = 4; + + /** + * Fixed 32 bits wire type. + * @type {number} + * @const + * @expose + */ + ProtoBuf.WIRE_TYPES.BITS32 = 5; + + /** + * Packable wire types. + * @type {!Array.} + * @const + * @expose + */ + ProtoBuf.PACKABLE_WIRE_TYPES = [ + ProtoBuf.WIRE_TYPES.VARINT, + ProtoBuf.WIRE_TYPES.BITS64, + ProtoBuf.WIRE_TYPES.BITS32 + ]; + + /** + * Types. + * @dict + * @type {!Object.} + * @const + * @expose + */ + ProtoBuf.TYPES = { + // According to the protobuf spec. + "int32": { + name: "int32", + wireType: ProtoBuf.WIRE_TYPES.VARINT, + defaultValue: 0 + }, + "uint32": { + name: "uint32", + wireType: ProtoBuf.WIRE_TYPES.VARINT, + defaultValue: 0 + }, + "sint32": { + name: "sint32", + wireType: ProtoBuf.WIRE_TYPES.VARINT, + defaultValue: 0 + }, + "int64": { + name: "int64", + wireType: ProtoBuf.WIRE_TYPES.VARINT, + defaultValue: ProtoBuf.Long ? ProtoBuf.Long.ZERO : undefined + }, + "uint64": { + name: "uint64", + wireType: ProtoBuf.WIRE_TYPES.VARINT, + defaultValue: ProtoBuf.Long ? ProtoBuf.Long.UZERO : undefined + }, + "sint64": { + name: "sint64", + wireType: ProtoBuf.WIRE_TYPES.VARINT, + defaultValue: ProtoBuf.Long ? ProtoBuf.Long.ZERO : undefined + }, + "bool": { + name: "bool", + wireType: ProtoBuf.WIRE_TYPES.VARINT, + defaultValue: false + }, + "double": { + name: "double", + wireType: ProtoBuf.WIRE_TYPES.BITS64, + defaultValue: 0 + }, + "string": { + name: "string", + wireType: ProtoBuf.WIRE_TYPES.LDELIM, + defaultValue: "" + }, + "bytes": { + name: "bytes", + wireType: ProtoBuf.WIRE_TYPES.LDELIM, + defaultValue: null // overridden in the code, must be a unique instance + }, + "fixed32": { + name: "fixed32", + wireType: ProtoBuf.WIRE_TYPES.BITS32, + defaultValue: 0 + }, + "sfixed32": { + name: "sfixed32", + wireType: ProtoBuf.WIRE_TYPES.BITS32, + defaultValue: 0 + }, + "fixed64": { + name: "fixed64", + wireType: ProtoBuf.WIRE_TYPES.BITS64, + defaultValue: ProtoBuf.Long ? ProtoBuf.Long.UZERO : undefined + }, + "sfixed64": { + name: "sfixed64", + wireType: ProtoBuf.WIRE_TYPES.BITS64, + defaultValue: ProtoBuf.Long ? ProtoBuf.Long.ZERO : undefined + }, + "float": { + name: "float", + wireType: ProtoBuf.WIRE_TYPES.BITS32, + defaultValue: 0 + }, + "enum": { + name: "enum", + wireType: ProtoBuf.WIRE_TYPES.VARINT, + defaultValue: 0 + }, + "message": { + name: "message", + wireType: ProtoBuf.WIRE_TYPES.LDELIM, + defaultValue: null + }, + "group": { + name: "group", + wireType: ProtoBuf.WIRE_TYPES.STARTGROUP, + defaultValue: null + } + }; + + /** + * Valid map key types. + * @type {!Array.>} + * @const + * @expose + */ + ProtoBuf.MAP_KEY_TYPES = [ + ProtoBuf.TYPES["int32"], + ProtoBuf.TYPES["sint32"], + ProtoBuf.TYPES["sfixed32"], + ProtoBuf.TYPES["uint32"], + ProtoBuf.TYPES["fixed32"], + ProtoBuf.TYPES["int64"], + ProtoBuf.TYPES["sint64"], + ProtoBuf.TYPES["sfixed64"], + ProtoBuf.TYPES["uint64"], + ProtoBuf.TYPES["fixed64"], + ProtoBuf.TYPES["bool"], + ProtoBuf.TYPES["string"], + ProtoBuf.TYPES["bytes"] + ]; + + /** + * Minimum field id. + * @type {number} + * @const + * @expose + */ + ProtoBuf.ID_MIN = 1; + + /** + * Maximum field id. + * @type {number} + * @const + * @expose + */ + ProtoBuf.ID_MAX = 0x1FFFFFFF; + + /** + * If set to `true`, field names will be converted from underscore notation to camel case. Defaults to `false`. + * Must be set prior to parsing. + * @type {boolean} + * @expose + */ + ProtoBuf.convertFieldsToCamelCase = false; + + /** + * By default, messages are populated with (setX, set_x) accessors for each field. This can be disabled by + * setting this to `false` prior to building messages. + * @type {boolean} + * @expose + */ + ProtoBuf.populateAccessors = true; + + /** + * By default, messages are populated with default values if a field is not present on the wire. To disable + * this behavior, set this setting to `false`. + * @type {boolean} + * @expose + */ + ProtoBuf.populateDefaults = true; + /** * @alias ProtoBuf.Util * @expose @@ -30295,4822 +30281,4822 @@ Curve25519Worker.prototype = { return Util; })(); - - /** - * Language expressions. - * @type {!Object.} - * @expose - */ - ProtoBuf.Lang = { - - // Characters always ending a statement - DELIM: /[\s\{\}=;:\[\],'"\(\)<>]/g, - - // Field rules - RULE: /^(?:required|optional|repeated|map)$/, - - // Field types - TYPE: /^(?:double|float|int32|uint32|sint32|int64|uint64|sint64|fixed32|sfixed32|fixed64|sfixed64|bool|string|bytes)$/, - - // Names - NAME: /^[a-zA-Z_][a-zA-Z_0-9]*$/, - - // Type definitions - TYPEDEF: /^[a-zA-Z][a-zA-Z_0-9]*$/, - - // Type references - TYPEREF: /^(?:\.?[a-zA-Z_][a-zA-Z_0-9]*)+$/, - - // Fully qualified type references - FQTYPEREF: /^(?:\.[a-zA-Z][a-zA-Z_0-9]*)+$/, - - // All numbers - NUMBER: /^-?(?:[1-9][0-9]*|0|0[xX][0-9a-fA-F]+|0[0-7]+|([0-9]*(\.[0-9]*)?([Ee][+-]?[0-9]+)?)|inf|nan)$/, - - // Decimal numbers - NUMBER_DEC: /^(?:[1-9][0-9]*|0)$/, - - // Hexadecimal numbers - NUMBER_HEX: /^0[xX][0-9a-fA-F]+$/, - - // Octal numbers - NUMBER_OCT: /^0[0-7]+$/, - - // Floating point numbers - NUMBER_FLT: /^([0-9]*(\.[0-9]*)?([Ee][+-]?[0-9]+)?|inf|nan)$/, - - // Booleans - BOOL: /^(?:true|false)$/i, - - // Id numbers - ID: /^(?:[1-9][0-9]*|0|0[xX][0-9a-fA-F]+|0[0-7]+)$/, - - // Negative id numbers (enum values) - NEGID: /^\-?(?:[1-9][0-9]*|0|0[xX][0-9a-fA-F]+|0[0-7]+)$/, - - // Whitespaces - WHITESPACE: /\s/, - - // All strings - STRING: /(?:"([^"\\]*(?:\\.[^"\\]*)*)")|(?:'([^'\\]*(?:\\.[^'\\]*)*)')/g, - - // Double quoted strings - STRING_DQ: /(?:"([^"\\]*(?:\\.[^"\\]*)*)")/g, - - // Single quoted strings - STRING_SQ: /(?:'([^'\\]*(?:\\.[^'\\]*)*)')/g - }; - - /** - * @alias ProtoBuf.DotProto - * @expose - */ - ProtoBuf.DotProto = (function(ProtoBuf, Lang) { - "use strict"; - - /** - * Utilities to parse .proto files. - * @exports ProtoBuf.DotProto - * @namespace - */ - var DotProto = {}; - - /** - * Constructs a new Tokenizer. - * @exports ProtoBuf.DotProto.Tokenizer - * @class prototype tokenizer - * @param {string} proto Proto to tokenize - * @constructor - */ - var Tokenizer = function(proto) { - - /** - * Source to parse. - * @type {string} - * @expose - */ - this.source = proto+""; - - /** - * Current index. - * @type {number} - * @expose - */ - this.index = 0; - - /** - * Current line. - * @type {number} - * @expose - */ - this.line = 1; - - /** - * Token stack. - * @type {!Array.} - * @expose - */ - this.stack = []; - - /** - * Opening character of the current string read, if any. - * @type {?string} - * @private - */ - this._stringOpen = null; - }; - - /** - * @alias ProtoBuf.DotProto.Tokenizer.prototype - * @inner - */ - var TokenizerPrototype = Tokenizer.prototype; - - /** - * Reads a string beginning at the current index. - * @return {string} - * @private - */ - TokenizerPrototype._readString = function() { - var re = this._stringOpen === '"' - ? Lang.STRING_DQ - : Lang.STRING_SQ; - re.lastIndex = this.index - 1; // Include the open quote - var match = re.exec(this.source); - if (!match) - throw Error("unterminated string"); - this.index = re.lastIndex; - this.stack.push(this._stringOpen); - this._stringOpen = null; - return match[1]; - }; - - /** - * Gets the next token and advances by one. - * @return {?string} Token or `null` on EOF - * @expose - */ - TokenizerPrototype.next = function() { - if (this.stack.length > 0) - return this.stack.shift(); - if (this.index >= this.source.length) - return null; - if (this._stringOpen !== null) - return this._readString(); - - var repeat, - prev, - next; - do { - repeat = false; - - // Strip white spaces - while (Lang.WHITESPACE.test(next = this.source.charAt(this.index))) { - if (next === '\n') - ++this.line; - if (++this.index === this.source.length) - return null; - } - - // Strip comments - if (this.source.charAt(this.index) === '/') { - ++this.index; - if (this.source.charAt(this.index) === '/') { // Line - while (this.source.charAt(++this.index) !== '\n') - if (this.index == this.source.length) - return null; - ++this.index; - ++this.line; - repeat = true; - } else if ((next = this.source.charAt(this.index)) === '*') { /* Block */ - do { - if (next === '\n') - ++this.line; - if (++this.index === this.source.length) - return null; - prev = next; - next = this.source.charAt(this.index); - } while (prev !== '*' || next !== '/'); - ++this.index; - repeat = true; - } else - return '/'; - } - } while (repeat); - - if (this.index === this.source.length) - return null; - - // Read the next token - var end = this.index; - Lang.DELIM.lastIndex = 0; - var delim = Lang.DELIM.test(this.source.charAt(end++)); - if (!delim) - while(end < this.source.length && !Lang.DELIM.test(this.source.charAt(end))) - ++end; - var token = this.source.substring(this.index, this.index = end); - if (token === '"' || token === "'") - this._stringOpen = token; - return token; - }; - - /** - * Peeks for the next token. - * @return {?string} Token or `null` on EOF - * @expose - */ - TokenizerPrototype.peek = function() { - if (this.stack.length === 0) { - var token = this.next(); - if (token === null) - return null; - this.stack.push(token); - } - return this.stack[0]; - }; - - /** - * Skips a specific token and throws if it differs. - * @param {string} expected Expected token - * @throws {Error} If the actual token differs - */ - TokenizerPrototype.skip = function(expected) { - var actual = this.next(); - if (actual !== expected) - throw Error("illegal '"+actual+"', '"+expected+"' expected"); - }; - - /** - * Omits an optional token. - * @param {string} expected Expected optional token - * @returns {boolean} `true` if the token exists - */ - TokenizerPrototype.omit = function(expected) { - if (this.peek() === expected) { - this.next(); - return true; - } - return false; - }; - - /** - * Returns a string representation of this object. - * @return {string} String representation as of "Tokenizer(index/length)" - * @expose - */ - TokenizerPrototype.toString = function() { - return "Tokenizer ("+this.index+"/"+this.source.length+" at line "+this.line+")"; - }; - - /** - * @alias ProtoBuf.DotProto.Tokenizer - * @expose - */ - DotProto.Tokenizer = Tokenizer; - - /** - * Constructs a new Parser. - * @exports ProtoBuf.DotProto.Parser - * @class prototype parser - * @param {string} source Source - * @constructor - */ - var Parser = function(source) { - - /** - * Tokenizer. - * @type {!ProtoBuf.DotProto.Tokenizer} - * @expose - */ - this.tn = new Tokenizer(source); - - /** - * Whether parsing proto3 or not. - * @type {boolean} - */ - this.proto3 = false; - }; - - /** - * @alias ProtoBuf.DotProto.Parser.prototype - * @inner - */ - var ParserPrototype = Parser.prototype; - - /** - * Parses the source. - * @returns {!Object} - * @throws {Error} If the source cannot be parsed - * @expose - */ - ParserPrototype.parse = function() { - var topLevel = { - "name": "[ROOT]", // temporary - "package": null, - "messages": [], - "enums": [], - "imports": [], - "options": {}, - "services": [] - // "syntax": undefined - }; - var token, - head = true, - weak; - try { - while (token = this.tn.next()) { - switch (token) { - case 'package': - if (!head || topLevel["package"] !== null) - throw Error("unexpected 'package'"); - token = this.tn.next(); - if (!Lang.TYPEREF.test(token)) - throw Error("illegal package name: " + token); - this.tn.skip(";"); - topLevel["package"] = token; - break; - case 'import': - if (!head) - throw Error("unexpected 'import'"); - token = this.tn.peek(); - if (token === "public" || (weak = token === "weak")) // token ignored - this.tn.next(); - token = this._readString(); - this.tn.skip(";"); - if (!weak) // import ignored - topLevel["imports"].push(token); - break; - case 'syntax': - if (!head) - throw Error("unexpected 'syntax'"); - this.tn.skip("="); - if ((topLevel["syntax"] = this._readString()) === "proto3") - this.proto3 = true; - this.tn.skip(";"); - break; - case 'message': - this._parseMessage(topLevel, null); - head = false; - break; - case 'enum': - this._parseEnum(topLevel); - head = false; - break; - case 'option': - this._parseOption(topLevel); - break; - case 'service': - this._parseService(topLevel); - break; - case 'extend': - this._parseExtend(topLevel); - break; - default: - throw Error("unexpected '" + token + "'"); - } - } - } catch (e) { - e.message = "Parse error at line "+this.tn.line+": " + e.message; - throw e; - } - delete topLevel["name"]; - return topLevel; - }; - - /** - * Parses the specified source. - * @returns {!Object} - * @throws {Error} If the source cannot be parsed - * @expose - */ - Parser.parse = function(source) { - return new Parser(source).parse(); - }; - - // ----- Conversion ------ - - /** - * Converts a numerical string to an id. - * @param {string} value - * @param {boolean=} mayBeNegative - * @returns {number} - * @inner - */ - function mkId(value, mayBeNegative) { - var id = -1, - sign = 1; - if (value.charAt(0) == '-') { - sign = -1; - value = value.substring(1); - } - if (Lang.NUMBER_DEC.test(value)) - id = parseInt(value); - else if (Lang.NUMBER_HEX.test(value)) - id = parseInt(value.substring(2), 16); - else if (Lang.NUMBER_OCT.test(value)) - id = parseInt(value.substring(1), 8); - else - throw Error("illegal id value: " + (sign < 0 ? '-' : '') + value); - id = (sign*id)|0; // Force to 32bit - if (!mayBeNegative && id < 0) - throw Error("illegal id value: " + (sign < 0 ? '-' : '') + value); - return id; - } - - /** - * Converts a numerical string to a number. - * @param {string} val - * @returns {number} - * @inner - */ - function mkNumber(val) { - var sign = 1; - if (val.charAt(0) == '-') { - sign = -1; - val = val.substring(1); - } - if (Lang.NUMBER_DEC.test(val)) - return sign * parseInt(val, 10); - else if (Lang.NUMBER_HEX.test(val)) - return sign * parseInt(val.substring(2), 16); - else if (Lang.NUMBER_OCT.test(val)) - return sign * parseInt(val.substring(1), 8); - else if (val === 'inf') - return sign * Infinity; - else if (val === 'nan') - return NaN; - else if (Lang.NUMBER_FLT.test(val)) - return sign * parseFloat(val); - throw Error("illegal number value: " + (sign < 0 ? '-' : '') + val); - } - - // ----- Reading ------ - - /** - * Reads a string. - * @returns {string} - * @private - */ - ParserPrototype._readString = function() { - var value = "", - token, - delim; - do { - delim = this.tn.next(); - if (delim !== "'" && delim !== '"') - throw Error("illegal string delimiter: "+delim); - value += this.tn.next(); - this.tn.skip(delim); - token = this.tn.peek(); - } while (token === '"' || token === '"'); // multi line? - return value; - }; - - /** - * Reads a value. - * @param {boolean=} mayBeTypeRef - * @returns {number|boolean|string} - * @private - */ - ParserPrototype._readValue = function(mayBeTypeRef) { - var token = this.tn.peek(), - value; - if (token === '"' || token === "'") - return this._readString(); - this.tn.next(); - if (Lang.NUMBER.test(token)) - return mkNumber(token); - if (Lang.BOOL.test(token)) - return (token.toLowerCase() === 'true'); - if (mayBeTypeRef && Lang.TYPEREF.test(token)) - return token; - throw Error("illegal value: "+token); - - }; - - // ----- Parsing constructs ----- - - /** - * Parses a namespace option. - * @param {!Object} parent Parent definition - * @param {boolean=} isList - * @private - */ - ParserPrototype._parseOption = function(parent, isList) { - var token = this.tn.next(), - custom = false; - if (token === '(') { - custom = true; - token = this.tn.next(); - } - if (!Lang.TYPEREF.test(token)) - // we can allow options of the form google.protobuf.* since they will just get ignored anyways - // if (!/google\.protobuf\./.test(token)) // FIXME: Why should that not be a valid typeref? - throw Error("illegal option name: "+token); - var name = token; - if (custom) { // (my_method_option).foo, (my_method_option), some_method_option, (foo.my_option).bar - this.tn.skip(')'); - name = '('+name+')'; - token = this.tn.peek(); - if (Lang.FQTYPEREF.test(token)) { - name += token; - this.tn.next(); - } - } - this.tn.skip('='); - this._parseOptionValue(parent, name); - if (!isList) - this.tn.skip(";"); - }; - - /** - * Sets an option on the specified options object. - * @param {!Object.} options - * @param {string} name - * @param {string|number|boolean} value - * @inner - */ - function setOption(options, name, value) { - if (typeof options[name] === 'undefined') - options[name] = value; - else { - if (!Array.isArray(options[name])) - options[name] = [ options[name] ]; - options[name].push(value); - } - } - - /** - * Parses an option value. - * @param {!Object} parent - * @param {string} name - * @private - */ - ParserPrototype._parseOptionValue = function(parent, name) { - var token = this.tn.peek(); - if (token !== '{') { // Plain value - setOption(parent["options"], name, this._readValue(true)); - } else { // Aggregate options - this.tn.skip("{"); - while ((token = this.tn.next()) !== '}') { - if (!Lang.NAME.test(token)) - throw Error("illegal option name: " + name + "." + token); - if (this.tn.omit(":")) - setOption(parent["options"], name + "." + token, this._readValue(true)); - else - this._parseOptionValue(parent, name + "." + token); - } - } - }; - - /** - * Parses a service definition. - * @param {!Object} parent Parent definition - * @private - */ - ParserPrototype._parseService = function(parent) { - var token = this.tn.next(); - if (!Lang.NAME.test(token)) - throw Error("illegal service name at line "+this.tn.line+": "+token); - var name = token; - var svc = { - "name": name, - "rpc": {}, - "options": {} - }; - this.tn.skip("{"); - while ((token = this.tn.next()) !== '}') { - if (token === "option") - this._parseOption(svc); - else if (token === 'rpc') - this._parseServiceRPC(svc); - else - throw Error("illegal service token: "+token); - } - this.tn.omit(";"); - parent["services"].push(svc); - }; - - /** - * Parses a RPC service definition of the form ['rpc', name, (request), 'returns', (response)]. - * @param {!Object} svc Service definition - * @private - */ - ParserPrototype._parseServiceRPC = function(svc) { - var type = "rpc", - token = this.tn.next(); - if (!Lang.NAME.test(token)) - throw Error("illegal rpc service method name: "+token); - var name = token; - var method = { - "request": null, - "response": null, - "request_stream": false, - "response_stream": false, - "options": {} - }; - this.tn.skip("("); - token = this.tn.next(); - if (token.toLowerCase() === "stream") { - method["request_stream"] = true; - token = this.tn.next(); - } - if (!Lang.TYPEREF.test(token)) - throw Error("illegal rpc service request type: "+token); - method["request"] = token; - this.tn.skip(")"); - token = this.tn.next(); - if (token.toLowerCase() !== "returns") - throw Error("illegal rpc service request type delimiter: "+token); - this.tn.skip("("); - token = this.tn.next(); - if (token.toLowerCase() === "stream") { - method["response_stream"] = true; - token = this.tn.next(); - } - method["response"] = token; - this.tn.skip(")"); - token = this.tn.peek(); - if (token === '{') { - this.tn.next(); - while ((token = this.tn.next()) !== '}') { - if (token === 'option') - this._parseOption(method); - else - throw Error("illegal rpc service token: " + token); - } - this.tn.omit(";"); - } else - this.tn.skip(";"); - if (typeof svc[type] === 'undefined') - svc[type] = {}; - svc[type][name] = method; - }; - - /** - * Parses a message definition. - * @param {!Object} parent Parent definition - * @param {!Object=} fld Field definition if this is a group - * @returns {!Object} - * @private - */ - ParserPrototype._parseMessage = function(parent, fld) { - var isGroup = !!fld, - token = this.tn.next(); - var msg = { - "name": "", - "fields": [], - "enums": [], - "messages": [], - "options": {}, - "services": [], - "oneofs": {} - // "extensions": undefined - }; - if (!Lang.NAME.test(token)) - throw Error("illegal "+(isGroup ? "group" : "message")+" name: "+token); - msg["name"] = token; - if (isGroup) { - this.tn.skip("="); - fld["id"] = mkId(this.tn.next()); - msg["isGroup"] = true; - } - token = this.tn.peek(); - if (token === '[' && fld) - this._parseFieldOptions(fld); - this.tn.skip("{"); - while ((token = this.tn.next()) !== '}') { - if (Lang.RULE.test(token)) - this._parseMessageField(msg, token); - else if (token === "oneof") - this._parseMessageOneOf(msg); - else if (token === "enum") - this._parseEnum(msg); - else if (token === "message") - this._parseMessage(msg); - else if (token === "option") - this._parseOption(msg); - else if (token === "service") - this._parseService(msg); - else if (token === "extensions") - msg["extensions"] = this._parseExtensionRanges(); - else if (token === "reserved") - this._parseIgnored(); // TODO - else if (token === "extend") - this._parseExtend(msg); - else if (Lang.TYPEREF.test(token)) { - if (!this.proto3) - throw Error("illegal field rule: "+token); - this._parseMessageField(msg, "optional", token); - } else - throw Error("illegal message token: "+token); - } - this.tn.omit(";"); - parent["messages"].push(msg); - return msg; - }; - - /** - * Parses an ignored statement. - * @private - */ - ParserPrototype._parseIgnored = function() { - while (this.tn.peek() !== ';') - this.tn.next(); - this.tn.skip(";"); - }; - - /** - * Parses a message field. - * @param {!Object} msg Message definition - * @param {string} rule Field rule - * @param {string=} type Field type if already known (never known for maps) - * @returns {!Object} Field descriptor - * @private - */ - ParserPrototype._parseMessageField = function(msg, rule, type) { - if (!Lang.RULE.test(rule)) - throw Error("illegal message field rule: "+rule); - var fld = { - "rule": rule, - "type": "", - "name": "", - "options": {}, - "id": 0 - }; - var token; - if (rule === "map") { - - if (type) - throw Error("illegal type: " + type); - this.tn.skip('<'); - token = this.tn.next(); - if (!Lang.TYPE.test(token) && !Lang.TYPEREF.test(token)) - throw Error("illegal message field type: " + token); - fld["keytype"] = token; - this.tn.skip(','); - token = this.tn.next(); - if (!Lang.TYPE.test(token) && !Lang.TYPEREF.test(token)) - throw Error("illegal message field: " + token); - fld["type"] = token; - this.tn.skip('>'); - token = this.tn.next(); - if (!Lang.NAME.test(token)) - throw Error("illegal message field name: " + token); - fld["name"] = token; - this.tn.skip("="); - fld["id"] = mkId(this.tn.next()); - token = this.tn.peek(); - if (token === '[') - this._parseFieldOptions(fld); - this.tn.skip(";"); - - } else { - - type = typeof type !== 'undefined' ? type : this.tn.next(); - - if (type === "group") { - - // "A [legacy] group simply combines a nested message type and a field into a single declaration. In your - // code, you can treat this message just as if it had a Result type field called result (the latter name is - // converted to lower-case so that it does not conflict with the former)." - var grp = this._parseMessage(msg, fld); - if (!/^[A-Z]/.test(grp["name"])) - throw Error('illegal group name: '+grp["name"]); - fld["type"] = grp["name"]; - fld["name"] = grp["name"].toLowerCase(); - this.tn.omit(";"); - - } else { - - if (!Lang.TYPE.test(type) && !Lang.TYPEREF.test(type)) - throw Error("illegal message field type: " + type); - fld["type"] = type; - token = this.tn.next(); - if (!Lang.NAME.test(token)) - throw Error("illegal message field name: " + token); - fld["name"] = token; - this.tn.skip("="); - fld["id"] = mkId(this.tn.next()); - token = this.tn.peek(); - if (token === "[") - this._parseFieldOptions(fld); - this.tn.skip(";"); - - } - } - msg["fields"].push(fld); - return fld; - }; - - /** - * Parses a message oneof. - * @param {!Object} msg Message definition - * @private - */ - ParserPrototype._parseMessageOneOf = function(msg) { - var token = this.tn.next(); - if (!Lang.NAME.test(token)) - throw Error("illegal oneof name: "+token); - var name = token, - fld; - var fields = []; - this.tn.skip("{"); - while ((token = this.tn.next()) !== "}") { - fld = this._parseMessageField(msg, "optional", token); - fld["oneof"] = name; - fields.push(fld["id"]); - } - this.tn.omit(";"); - msg["oneofs"][name] = fields; - }; - - /** - * Parses a set of field option definitions. - * @param {!Object} fld Field definition - * @private - */ - ParserPrototype._parseFieldOptions = function(fld) { - this.tn.skip("["); - var token, - first = true; - while ((token = this.tn.peek()) !== ']') { - if (!first) - this.tn.skip(","); - this._parseOption(fld, true); - first = false; - } - this.tn.next(); - }; - - /** - * Parses an enum. - * @param {!Object} msg Message definition - * @private - */ - ParserPrototype._parseEnum = function(msg) { - var enm = { - "name": "", - "values": [], - "options": {} - }; - var token = this.tn.next(); - if (!Lang.NAME.test(token)) - throw Error("illegal name: "+token); - enm["name"] = token; - this.tn.skip("{"); - while ((token = this.tn.next()) !== '}') { - if (token === "option") - this._parseOption(enm); - else { - if (!Lang.NAME.test(token)) - throw Error("illegal name: "+token); - this.tn.skip("="); - var val = { - "name": token, - "id": mkId(this.tn.next(), true) - }; - token = this.tn.peek(); - if (token === "[") - this._parseFieldOptions({ "options": {} }); - this.tn.skip(";"); - enm["values"].push(val); - } - } - this.tn.omit(";"); - msg["enums"].push(enm); - }; - - /** - * Parses extension / reserved ranges. - * @returns {!Array.>} - * @private - */ - ParserPrototype._parseExtensionRanges = function() { - var ranges = []; - var token, - range, - value; - do { - range = []; - while (true) { - token = this.tn.next(); - switch (token) { - case "min": - value = ProtoBuf.ID_MIN; - break; - case "max": - value = ProtoBuf.ID_MAX; - break; - default: - value = mkNumber(token); - break; - } - range.push(value); - if (range.length === 2) - break; - if (this.tn.peek() !== "to") { - range.push(value); - break; - } - this.tn.next(); - } - ranges.push(range); - } while (this.tn.omit(",")); - this.tn.skip(";"); - return ranges; - }; - - /** - * Parses an extend block. - * @param {!Object} parent Parent object - * @private - */ - ParserPrototype._parseExtend = function(parent) { - var token = this.tn.next(); - if (!Lang.TYPEREF.test(token)) - throw Error("illegal extend reference: "+token); - var ext = { - "ref": token, - "fields": [] - }; - this.tn.skip("{"); - while ((token = this.tn.next()) !== '}') { - if (Lang.RULE.test(token)) - this._parseMessageField(ext, token); - else if (Lang.TYPEREF.test(token)) { - if (!this.proto3) - throw Error("illegal field rule: "+token); - this._parseMessageField(ext, "optional", token); - } else - throw Error("illegal extend token: "+token); - } - this.tn.omit(";"); - parent["messages"].push(ext); - return ext; - }; - - // ----- General ----- - - /** - * Returns a string representation of this parser. - * @returns {string} - */ - ParserPrototype.toString = function() { - return "Parser at line "+this.tn.line; - }; - - /** - * @alias ProtoBuf.DotProto.Parser - * @expose - */ - DotProto.Parser = Parser; - - return DotProto; - - })(ProtoBuf, ProtoBuf.Lang); - - /** - * @alias ProtoBuf.Reflect - * @expose - */ - ProtoBuf.Reflect = (function(ProtoBuf) { - "use strict"; - - /** - * Reflection types. - * @exports ProtoBuf.Reflect - * @namespace - */ - var Reflect = {}; - - /** - * Constructs a Reflect base class. - * @exports ProtoBuf.Reflect.T - * @constructor - * @abstract - * @param {!ProtoBuf.Builder} builder Builder reference - * @param {?ProtoBuf.Reflect.T} parent Parent object - * @param {string} name Object name - */ - var T = function(builder, parent, name) { - - /** - * Builder reference. - * @type {!ProtoBuf.Builder} - * @expose - */ - this.builder = builder; - - /** - * Parent object. - * @type {?ProtoBuf.Reflect.T} - * @expose - */ - this.parent = parent; - - /** - * Object name in namespace. - * @type {string} - * @expose - */ - this.name = name; - - /** - * Fully qualified class name - * @type {string} - * @expose - */ - this.className; - }; - - /** - * @alias ProtoBuf.Reflect.T.prototype - * @inner - */ - var TPrototype = T.prototype; - - /** - * Returns the fully qualified name of this object. - * @returns {string} Fully qualified name as of ".PATH.TO.THIS" - * @expose - */ - TPrototype.fqn = function() { - var name = this.name, - ptr = this; - do { - ptr = ptr.parent; - if (ptr == null) - break; - name = ptr.name+"."+name; - } while (true); - return name; - }; - - /** - * Returns a string representation of this Reflect object (its fully qualified name). - * @param {boolean=} includeClass Set to true to include the class name. Defaults to false. - * @return String representation - * @expose - */ - TPrototype.toString = function(includeClass) { - return (includeClass ? this.className + " " : "") + this.fqn(); - }; - - /** - * Builds this type. - * @throws {Error} If this type cannot be built directly - * @expose - */ - TPrototype.build = function() { - throw Error(this.toString(true)+" cannot be built directly"); - }; - - /** - * @alias ProtoBuf.Reflect.T - * @expose - */ - Reflect.T = T; - - /** - * Constructs a new Namespace. - * @exports ProtoBuf.Reflect.Namespace - * @param {!ProtoBuf.Builder} builder Builder reference - * @param {?ProtoBuf.Reflect.Namespace} parent Namespace parent - * @param {string} name Namespace name - * @param {Object.=} options Namespace options - * @param {string?} syntax The syntax level of this definition (e.g., proto3) - * @constructor - * @extends ProtoBuf.Reflect.T - */ - var Namespace = function(builder, parent, name, options, syntax) { - T.call(this, builder, parent, name); - - /** - * @override - */ - this.className = "Namespace"; - - /** - * Children inside the namespace. - * @type {!Array.} - */ - this.children = []; - - /** - * Options. - * @type {!Object.} - */ - this.options = options || {}; - - /** - * Syntax level (e.g., proto2 or proto3). - * @type {!string} - */ - this.syntax = syntax || "proto2"; - }; - - /** - * @alias ProtoBuf.Reflect.Namespace.prototype - * @inner - */ - var NamespacePrototype = Namespace.prototype = Object.create(T.prototype); - - /** - * Returns an array of the namespace's children. - * @param {ProtoBuf.Reflect.T=} type Filter type (returns instances of this type only). Defaults to null (all children). - * @return {Array.} - * @expose - */ - NamespacePrototype.getChildren = function(type) { - type = type || null; - if (type == null) - return this.children.slice(); - var children = []; - for (var i=0, k=this.children.length; i} qn Qualified name to resolve - * @param {boolean=} excludeNonNamespace Excludes non-namespace types, defaults to `false` - * @return {?ProtoBuf.Reflect.Namespace} The resolved type or null if not found - * @expose - */ - NamespacePrototype.resolve = function(qn, excludeNonNamespace) { - var part = typeof qn === 'string' ? qn.split(".") : qn, - ptr = this, - i = 0; - if (part[i] === "") { // Fully qualified name, e.g. ".My.Message' - while (ptr.parent !== null) - ptr = ptr.parent; - i++; - } - var child; - do { - do { - if (!(ptr instanceof Reflect.Namespace)) { - ptr = null; - break; - } - child = ptr.getChild(part[i]); - if (!child || !(child instanceof Reflect.T) || (excludeNonNamespace && !(child instanceof Reflect.Namespace))) { - ptr = null; - break; - } - ptr = child; i++; - } while (i < part.length); - if (ptr != null) - break; // Found - // Else search the parent - if (this.parent !== null) - return this.parent.resolve(qn, excludeNonNamespace); - } while (ptr != null); - return ptr; - }; - - /** - * Determines the shortest qualified name of the specified type, if any, relative to this namespace. - * @param {!ProtoBuf.Reflect.T} t Reflection type - * @returns {string} The shortest qualified name or, if there is none, the fqn - * @expose - */ - NamespacePrototype.qn = function(t) { - var part = [], ptr = t; - do { - part.unshift(ptr.name); - ptr = ptr.parent; - } while (ptr !== null); - for (var len=1; len <= part.length; len++) { - var qn = part.slice(part.length-len); - if (t === this.resolve(qn, t instanceof Reflect.Namespace)) - return qn.join("."); - } - return t.fqn(); - }; - - /** - * Builds the namespace and returns the runtime counterpart. - * @return {Object.} Runtime namespace - * @expose - */ - NamespacePrototype.build = function() { - /** @dict */ - var ns = {}; - var children = this.children; - for (var i=0, k=children.length, child; i} - */ - NamespacePrototype.buildOpt = function() { - var opt = {}, - keys = Object.keys(this.options); - for (var i=0, k=keys.length; i}null} Option value or NULL if there is no such option - */ - NamespacePrototype.getOption = function(name) { - if (typeof name === 'undefined') - return this.options; - return typeof this.options[name] !== 'undefined' ? this.options[name] : null; - }; - - /** - * @alias ProtoBuf.Reflect.Namespace - * @expose - */ - Reflect.Namespace = Namespace; - - /** - * Constructs a new Element implementation that checks and converts values for a - * particular field type, as appropriate. - * - * An Element represents a single value: either the value of a singular field, - * or a value contained in one entry of a repeated field or map field. This - * class does not implement these higher-level concepts; it only encapsulates - * the low-level typechecking and conversion. - * - * @exports ProtoBuf.Reflect.Element - * @param {{name: string, wireType: number}} type Resolved data type - * @param {ProtoBuf.Reflect.T|null} resolvedType Resolved type, if relevant - * (e.g. submessage field). - * @param {boolean} isMapKey Is this element a Map key? The value will be - * converted to string form if so. - * @param {string} syntax Syntax level of defining message type, e.g., - * proto2 or proto3. - * @constructor - */ - var Element = function(type, resolvedType, isMapKey, syntax) { - - /** - * Element type, as a string (e.g., int32). - * @type {{name: string, wireType: number}} - */ - this.type = type; - - /** - * Element type reference to submessage or enum definition, if needed. - * @type {ProtoBuf.Reflect.T|null} - */ - this.resolvedType = resolvedType; - - /** - * Element is a map key. - * @type {boolean} - */ - this.isMapKey = isMapKey; - - /** - * Syntax level of defining message type, e.g., proto2 or proto3. - * @type {string} - */ - this.syntax = syntax; - - if (isMapKey && ProtoBuf.MAP_KEY_TYPES.indexOf(type) < 0) - throw Error("Invalid map key type: " + type.name); - }; - - var ElementPrototype = Element.prototype; - - /** - * Obtains a (new) default value for the specified type. - * @param type {string|{name: string, wireType: number}} Field type - * @returns {*} Default value - * @inner - */ - function mkDefault(type) { - if (typeof type === 'string') - type = ProtoBuf.TYPES[type]; - if (typeof type.defaultValue === 'undefined') - throw Error("default value for type "+type.name+" is not supported"); - if (type == ProtoBuf.TYPES["bytes"]) - return new ByteBuffer(0); - return type.defaultValue; - } - - /** - * Returns the default value for this field in proto3. - * @function - * @param type {string|{name: string, wireType: number}} the field type - * @returns {*} Default value - */ - Element.defaultFieldValue = mkDefault; - - /** - * Makes a Long from a value. - * @param {{low: number, high: number, unsigned: boolean}|string|number} value Value - * @param {boolean=} unsigned Whether unsigned or not, defaults to reuse it from Long-like objects or to signed for - * strings and numbers - * @returns {!Long} - * @throws {Error} If the value cannot be converted to a Long - * @inner - */ - function mkLong(value, unsigned) { - if (value && typeof value.low === 'number' && typeof value.high === 'number' && typeof value.unsigned === 'boolean' - && value.low === value.low && value.high === value.high) - return new ProtoBuf.Long(value.low, value.high, typeof unsigned === 'undefined' ? value.unsigned : unsigned); - if (typeof value === 'string') - return ProtoBuf.Long.fromString(value, unsigned || false, 10); - if (typeof value === 'number') - return ProtoBuf.Long.fromNumber(value, unsigned || false); - throw Error("not convertible to Long"); - } - - /** - * Checks if the given value can be set for an element of this type (singular - * field or one element of a repeated field or map). - * @param {*} value Value to check - * @return {*} Verified, maybe adjusted, value - * @throws {Error} If the value cannot be verified for this element slot - * @expose - */ - ElementPrototype.verifyValue = function(value) { - var self = this; - function fail(val, msg) { - throw Error("Illegal value for "+self.toString(true)+" of type "+self.type.name+": "+val+" ("+msg+")"); - } - switch (this.type) { - // Signed 32bit - case ProtoBuf.TYPES["int32"]: - case ProtoBuf.TYPES["sint32"]: - case ProtoBuf.TYPES["sfixed32"]: - // Account for !NaN: value === value - if (typeof value !== 'number' || (value === value && value % 1 !== 0)) - fail(typeof value, "not an integer"); - return value > 4294967295 ? value | 0 : value; - - // Unsigned 32bit - case ProtoBuf.TYPES["uint32"]: - case ProtoBuf.TYPES["fixed32"]: - if (typeof value !== 'number' || (value === value && value % 1 !== 0)) - fail(typeof value, "not an integer"); - return value < 0 ? value >>> 0 : value; - - // Signed 64bit - case ProtoBuf.TYPES["int64"]: - case ProtoBuf.TYPES["sint64"]: - case ProtoBuf.TYPES["sfixed64"]: { - if (ProtoBuf.Long) - try { - return mkLong(value, false); - } catch (e) { - fail(typeof value, e.message); - } - else - fail(typeof value, "requires Long.js"); - } - - // Unsigned 64bit - case ProtoBuf.TYPES["uint64"]: - case ProtoBuf.TYPES["fixed64"]: { - if (ProtoBuf.Long) - try { - return mkLong(value, true); - } catch (e) { - fail(typeof value, e.message); - } - else - fail(typeof value, "requires Long.js"); - } - - // Bool - case ProtoBuf.TYPES["bool"]: - if (typeof value !== 'boolean') - fail(typeof value, "not a boolean"); - return value; - - // Float - case ProtoBuf.TYPES["float"]: - case ProtoBuf.TYPES["double"]: - if (typeof value !== 'number') - fail(typeof value, "not a number"); - return value; - - // Length-delimited string - case ProtoBuf.TYPES["string"]: - if (typeof value !== 'string' && !(value && value instanceof String)) - fail(typeof value, "not a string"); - return ""+value; // Convert String object to string - - // Length-delimited bytes - case ProtoBuf.TYPES["bytes"]: - if (ByteBuffer.isByteBuffer(value)) - return value; - return ByteBuffer.wrap(value, "base64"); - - // Constant enum value - case ProtoBuf.TYPES["enum"]: { - var values = this.resolvedType.getChildren(ProtoBuf.Reflect.Enum.Value); - for (i=0; i 4294967295 || value < 0) - fail(typeof value, "not in range for uint32") - return value; - } else { - // proto2 requires enum values to be valid. - fail(value, "not a valid enum value"); - } - } - // Embedded message - case ProtoBuf.TYPES["group"]: - case ProtoBuf.TYPES["message"]: { - if (!value || typeof value !== 'object') - fail(typeof value, "object expected"); - if (value instanceof this.resolvedType.clazz) - return value; - if (value instanceof ProtoBuf.Builder.Message) { - // Mismatched type: Convert to object (see: https://github.com/dcodeIO/ProtoBuf.js/issues/180) - var obj = {}; - for (var i in value) - if (value.hasOwnProperty(i)) - obj[i] = value[i]; - value = obj; - } - // Else let's try to construct one from a key-value object - return new (this.resolvedType.clazz)(value); // May throw for a hundred of reasons - } - } - - // We should never end here - throw Error("[INTERNAL] Illegal value for "+this.toString(true)+": "+value+" (undefined type "+this.type+")"); - }; - - /** - * Calculates the byte length of an element on the wire. - * @param {number} id Field number - * @param {*} value Field value - * @returns {number} Byte length - * @throws {Error} If the value cannot be calculated - * @expose - */ - ElementPrototype.calculateLength = function(id, value) { - if (value === null) return 0; // Nothing to encode - // Tag has already been written - var n; - switch (this.type) { - case ProtoBuf.TYPES["int32"]: - return value < 0 ? ByteBuffer.calculateVarint64(value) : ByteBuffer.calculateVarint32(value); - case ProtoBuf.TYPES["uint32"]: - return ByteBuffer.calculateVarint32(value); - case ProtoBuf.TYPES["sint32"]: - return ByteBuffer.calculateVarint32(ByteBuffer.zigZagEncode32(value)); - case ProtoBuf.TYPES["fixed32"]: - case ProtoBuf.TYPES["sfixed32"]: - case ProtoBuf.TYPES["float"]: - return 4; - case ProtoBuf.TYPES["int64"]: - case ProtoBuf.TYPES["uint64"]: - return ByteBuffer.calculateVarint64(value); - case ProtoBuf.TYPES["sint64"]: - return ByteBuffer.calculateVarint64(ByteBuffer.zigZagEncode64(value)); - case ProtoBuf.TYPES["fixed64"]: - case ProtoBuf.TYPES["sfixed64"]: - return 8; - case ProtoBuf.TYPES["bool"]: - return 1; - case ProtoBuf.TYPES["enum"]: - return ByteBuffer.calculateVarint32(value); - case ProtoBuf.TYPES["double"]: - return 8; - case ProtoBuf.TYPES["string"]: - n = ByteBuffer.calculateUTF8Bytes(value); - return ByteBuffer.calculateVarint32(n) + n; - case ProtoBuf.TYPES["bytes"]: - if (value.remaining() < 0) - throw Error("Illegal value for "+this.toString(true)+": "+value.remaining()+" bytes remaining"); - return ByteBuffer.calculateVarint32(value.remaining()) + value.remaining(); - case ProtoBuf.TYPES["message"]: - n = this.resolvedType.calculate(value); - return ByteBuffer.calculateVarint32(n) + n; - case ProtoBuf.TYPES["group"]: - n = this.resolvedType.calculate(value); - return n + ByteBuffer.calculateVarint32((id << 3) | ProtoBuf.WIRE_TYPES.ENDGROUP); - } - // We should never end here - throw Error("[INTERNAL] Illegal value to encode in "+this.toString(true)+": "+value+" (unknown type)"); - }; - - /** - * Encodes a value to the specified buffer. Does not encode the key. - * @param {number} id Field number - * @param {*} value Field value - * @param {ByteBuffer} buffer ByteBuffer to encode to - * @return {ByteBuffer} The ByteBuffer for chaining - * @throws {Error} If the value cannot be encoded - * @expose - */ - ElementPrototype.encodeValue = function(id, value, buffer) { - if (value === null) return buffer; // Nothing to encode - // Tag has already been written - - switch (this.type) { - // 32bit signed varint - case ProtoBuf.TYPES["int32"]: - // "If you use int32 or int64 as the type for a negative number, the resulting varint is always ten bytes - // long – it is, effectively, treated like a very large unsigned integer." (see #122) - if (value < 0) - buffer.writeVarint64(value); - else - buffer.writeVarint32(value); - break; - - // 32bit unsigned varint - case ProtoBuf.TYPES["uint32"]: - buffer.writeVarint32(value); - break; - - // 32bit varint zig-zag - case ProtoBuf.TYPES["sint32"]: - buffer.writeVarint32ZigZag(value); - break; - - // Fixed unsigned 32bit - case ProtoBuf.TYPES["fixed32"]: - buffer.writeUint32(value); - break; - - // Fixed signed 32bit - case ProtoBuf.TYPES["sfixed32"]: - buffer.writeInt32(value); - break; - - // 64bit varint as-is - case ProtoBuf.TYPES["int64"]: - case ProtoBuf.TYPES["uint64"]: - buffer.writeVarint64(value); // throws - break; - - // 64bit varint zig-zag - case ProtoBuf.TYPES["sint64"]: - buffer.writeVarint64ZigZag(value); // throws - break; - - // Fixed unsigned 64bit - case ProtoBuf.TYPES["fixed64"]: - buffer.writeUint64(value); // throws - break; - - // Fixed signed 64bit - case ProtoBuf.TYPES["sfixed64"]: - buffer.writeInt64(value); // throws - break; - - // Bool - case ProtoBuf.TYPES["bool"]: - if (typeof value === 'string') - buffer.writeVarint32(value.toLowerCase() === 'false' ? 0 : !!value); - else - buffer.writeVarint32(value ? 1 : 0); - break; - - // Constant enum value - case ProtoBuf.TYPES["enum"]: - buffer.writeVarint32(value); - break; - - // 32bit float - case ProtoBuf.TYPES["float"]: - buffer.writeFloat32(value); - break; - - // 64bit float - case ProtoBuf.TYPES["double"]: - buffer.writeFloat64(value); - break; - - // Length-delimited string - case ProtoBuf.TYPES["string"]: - buffer.writeVString(value); - break; - - // Length-delimited bytes - case ProtoBuf.TYPES["bytes"]: - if (value.remaining() < 0) - throw Error("Illegal value for "+this.toString(true)+": "+value.remaining()+" bytes remaining"); - var prevOffset = value.offset; - buffer.writeVarint32(value.remaining()); - buffer.append(value); - value.offset = prevOffset; - break; - - // Embedded message - case ProtoBuf.TYPES["message"]: - var bb = new ByteBuffer().LE(); - this.resolvedType.encode(value, bb); - buffer.writeVarint32(bb.offset); - buffer.append(bb.flip()); - break; - - // Legacy group - case ProtoBuf.TYPES["group"]: - this.resolvedType.encode(value, buffer); - buffer.writeVarint32((id << 3) | ProtoBuf.WIRE_TYPES.ENDGROUP); - break; - - default: - // We should never end here - throw Error("[INTERNAL] Illegal value to encode in "+this.toString(true)+": "+value+" (unknown type)"); - } - return buffer; - }; - - /** - * Decode one element value from the specified buffer. - * @param {ByteBuffer} buffer ByteBuffer to decode from - * @param {number} wireType The field wire type - * @param {number} id The field number - * @return {*} Decoded value - * @throws {Error} If the field cannot be decoded - * @expose - */ - ElementPrototype.decode = function(buffer, wireType, id) { - if (wireType != this.type.wireType) - throw Error("Unexpected wire type for element"); - - var value, nBytes; - switch (this.type) { - // 32bit signed varint - case ProtoBuf.TYPES["int32"]: - return buffer.readVarint32() | 0; - - // 32bit unsigned varint - case ProtoBuf.TYPES["uint32"]: - return buffer.readVarint32() >>> 0; - - // 32bit signed varint zig-zag - case ProtoBuf.TYPES["sint32"]: - return buffer.readVarint32ZigZag() | 0; - - // Fixed 32bit unsigned - case ProtoBuf.TYPES["fixed32"]: - return buffer.readUint32() >>> 0; - - case ProtoBuf.TYPES["sfixed32"]: - return buffer.readInt32() | 0; - - // 64bit signed varint - case ProtoBuf.TYPES["int64"]: - return buffer.readVarint64(); - - // 64bit unsigned varint - case ProtoBuf.TYPES["uint64"]: - return buffer.readVarint64().toUnsigned(); - - // 64bit signed varint zig-zag - case ProtoBuf.TYPES["sint64"]: - return buffer.readVarint64ZigZag(); - - // Fixed 64bit unsigned - case ProtoBuf.TYPES["fixed64"]: - return buffer.readUint64(); - - // Fixed 64bit signed - case ProtoBuf.TYPES["sfixed64"]: - return buffer.readInt64(); - - // Bool varint - case ProtoBuf.TYPES["bool"]: - return !!buffer.readVarint32(); - - // Constant enum value (varint) - case ProtoBuf.TYPES["enum"]: - // The following Builder.Message#set will already throw - return buffer.readVarint32(); - - // 32bit float - case ProtoBuf.TYPES["float"]: - return buffer.readFloat(); - - // 64bit float - case ProtoBuf.TYPES["double"]: - return buffer.readDouble(); - - // Length-delimited string - case ProtoBuf.TYPES["string"]: - return buffer.readVString(); - - // Length-delimited bytes - case ProtoBuf.TYPES["bytes"]: { - nBytes = buffer.readVarint32(); - if (buffer.remaining() < nBytes) - throw Error("Illegal number of bytes for "+this.toString(true)+": "+nBytes+" required but got only "+buffer.remaining()); - value = buffer.clone(); // Offset already set - value.limit = value.offset+nBytes; - buffer.offset += nBytes; - return value; - } - - // Length-delimited embedded message - case ProtoBuf.TYPES["message"]: { - nBytes = buffer.readVarint32(); - return this.resolvedType.decode(buffer, nBytes); - } - - // Legacy group - case ProtoBuf.TYPES["group"]: - return this.resolvedType.decode(buffer, -1, id); - } - - // We should never end here - throw Error("[INTERNAL] Illegal decode type"); - }; - - /** - * Converts a value from a string to the canonical element type. - * - * Legal only when isMapKey is true. - * - * @param {string} str The string value - * @returns {*} The value - */ - ElementPrototype.valueFromString = function(str) { - if (!this.isMapKey) { - throw Error("valueFromString() called on non-map-key element"); - } - - switch (this.type) { - case ProtoBuf.TYPES["int32"]: - case ProtoBuf.TYPES["sint32"]: - case ProtoBuf.TYPES["sfixed32"]: - case ProtoBuf.TYPES["uint32"]: - case ProtoBuf.TYPES["fixed32"]: - return this.verifyValue(parseInt(str)); - - case ProtoBuf.TYPES["int64"]: - case ProtoBuf.TYPES["sint64"]: - case ProtoBuf.TYPES["sfixed64"]: - case ProtoBuf.TYPES["uint64"]: - case ProtoBuf.TYPES["fixed64"]: - // Long-based fields support conversions from string already. - return this.verifyValue(str); - - case ProtoBuf.TYPES["bool"]: - return str === "true"; - - case ProtoBuf.TYPES["string"]: - return this.verifyValue(str); - - case ProtoBuf.TYPES["bytes"]: - return ByteBuffer.fromBinary(str); - } - }; - - /** - * Converts a value from the canonical element type to a string. - * - * It should be the case that `valueFromString(valueToString(val))` returns - * a value equivalent to `verifyValue(val)` for every legal value of `val` - * according to this element type. - * - * This may be used when the element must be stored or used as a string, - * e.g., as a map key on an Object. - * - * Legal only when isMapKey is true. - * - * @param {*} val The value - * @returns {string} The string form of the value. - */ - ElementPrototype.valueToString = function(value) { - if (!this.isMapKey) { - throw Error("valueToString() called on non-map-key element"); - } - - if (this.type === ProtoBuf.TYPES["bytes"]) { - return value.toString("binary"); - } else { - return value.toString(); - } - }; - - /** - * @alias ProtoBuf.Reflect.Element - * @expose - */ - Reflect.Element = Element; - - /** - * Constructs a new Message. - * @exports ProtoBuf.Reflect.Message - * @param {!ProtoBuf.Builder} builder Builder reference - * @param {!ProtoBuf.Reflect.Namespace} parent Parent message or namespace - * @param {string} name Message name - * @param {Object.=} options Message options - * @param {boolean=} isGroup `true` if this is a legacy group - * @param {string?} syntax The syntax level of this definition (e.g., proto3) - * @constructor - * @extends ProtoBuf.Reflect.Namespace - */ - var Message = function(builder, parent, name, options, isGroup, syntax) { - Namespace.call(this, builder, parent, name, options, syntax); - - /** - * @override - */ - this.className = "Message"; - - /** - * Extensions range. - * @type {!Array.|undefined} - * @expose - */ - this.extensions = undefined; - - /** - * Runtime message class. - * @type {?function(new:ProtoBuf.Builder.Message)} - * @expose - */ - this.clazz = null; - - /** - * Whether this is a legacy group or not. - * @type {boolean} - * @expose - */ - this.isGroup = !!isGroup; - - // The following cached collections are used to efficiently iterate over or look up fields when decoding. - - /** - * Cached fields. - * @type {?Array.} - * @private - */ - this._fields = null; - - /** - * Cached fields by id. - * @type {?Object.} - * @private - */ - this._fieldsById = null; - - /** - * Cached fields by name. - * @type {?Object.} - * @private - */ - this._fieldsByName = null; - }; - - /** - * @alias ProtoBuf.Reflect.Message.prototype - * @inner - */ - var MessagePrototype = Message.prototype = Object.create(Namespace.prototype); - - /** - * Builds the message and returns the runtime counterpart, which is a fully functional class. - * @see ProtoBuf.Builder.Message - * @param {boolean=} rebuild Whether to rebuild or not, defaults to false - * @return {ProtoBuf.Reflect.Message} Message class - * @throws {Error} If the message cannot be built - * @expose - */ - MessagePrototype.build = function(rebuild) { - if (this.clazz && !rebuild) - return this.clazz; - - // Create the runtime Message class in its own scope - var clazz = (function(ProtoBuf, T) { - - var fields = T.getChildren(ProtoBuf.Reflect.Message.Field), - oneofs = T.getChildren(ProtoBuf.Reflect.Message.OneOf); - - /** - * Constructs a new runtime Message. - * @name ProtoBuf.Builder.Message - * @class Barebone of all runtime messages. - * @param {!Object.|string} values Preset values - * @param {...string} var_args - * @constructor - * @throws {Error} If the message cannot be created - */ - var Message = function(values, var_args) { - ProtoBuf.Builder.Message.call(this); - - // Create virtual oneof properties - for (var i=0, k=oneofs.length; i 0) { - var value; - // Set field values from a values object - if (arguments.length === 1 && values !== null && typeof values === 'object' && - /* not _another_ Message */ (typeof values.encode !== 'function' || values instanceof Message) && - /* not a repeated field */ !Array.isArray(values) && - /* not a Map */ !(values instanceof ProtoBuf.Map) && - /* not a ByteBuffer */ !ByteBuffer.isByteBuffer(values) && - /* not an ArrayBuffer */ !(values instanceof ArrayBuffer) && - /* not a Long */ !(ProtoBuf.Long && values instanceof ProtoBuf.Long)) { - this.$set(values); - } else // Set field values from arguments, in declaration order - for (i=0, k=arguments.length; i} keyOrObj String key or plain object holding multiple values - * @param {(*|boolean)=} value Value to set if key is a string, otherwise omitted - * @param {boolean=} noAssert Whether to not assert for an actual field / proper value type, defaults to `false` - * @returns {!ProtoBuf.Builder.Message} this - * @throws {Error} If the value cannot be set - * @expose - */ - MessagePrototype.set = function(keyOrObj, value, noAssert) { - if (keyOrObj && typeof keyOrObj === 'object') { - noAssert = value; - for (var ikey in keyOrObj) - if (keyOrObj.hasOwnProperty(ikey) && typeof (value = keyOrObj[ikey]) !== 'undefined') - this.$set(ikey, value, noAssert); - return this; - } - var field = T._fieldsByName[keyOrObj]; - if (!noAssert) { - if (!field) - throw Error(this+"#"+keyOrObj+" is not a field: undefined"); - if (!(field instanceof ProtoBuf.Reflect.Message.Field)) - throw Error(this+"#"+keyOrObj+" is not a field: "+field.toString(true)); - this[field.name] = (value = field.verifyValue(value)); // May throw - } else - this[keyOrObj] = value; - if (field && field.oneof) { // Field is part of an OneOf (not a virtual OneOf field) - var currentField = this[field.oneof.name]; // Virtual field references currently set field - if (value !== null) { - if (currentField !== null && currentField !== field.name) - this[currentField] = null; // Clear currently set field - this[field.oneof.name] = field.name; // Point virtual field at this field - } else if (/* value === null && */currentField === keyOrObj) - this[field.oneof.name] = null; // Clear virtual field (current field explicitly cleared) - } - return this; - }; - - /** - * Sets a field's value. This is an alias for [@link ProtoBuf.Builder.Message#set}. - * @name ProtoBuf.Builder.Message#$set - * @function - * @param {string|!Object.} keyOrObj String key or plain object holding multiple values - * @param {(*|boolean)=} value Value to set if key is a string, otherwise omitted - * @param {boolean=} noAssert Whether to not assert the value, defaults to `false` - * @throws {Error} If the value cannot be set - * @expose - */ - MessagePrototype.$set = MessagePrototype.set; - - /** - * Gets a field's value. - * @name ProtoBuf.Builder.Message#get - * @function - * @param {string} key Key - * @param {boolean=} noAssert Whether to not assert for an actual field, defaults to `false` - * @return {*} Value - * @throws {Error} If there is no such field - * @expose - */ - MessagePrototype.get = function(key, noAssert) { - if (noAssert) - return this[key]; - var field = T._fieldsByName[key]; - if (!field || !(field instanceof ProtoBuf.Reflect.Message.Field)) - throw Error(this+"#"+key+" is not a field: undefined"); - if (!(field instanceof ProtoBuf.Reflect.Message.Field)) - throw Error(this+"#"+key+" is not a field: "+field.toString(true)); - return this[field.name]; - }; - - /** - * Gets a field's value. This is an alias for {@link ProtoBuf.Builder.Message#$get}. - * @name ProtoBuf.Builder.Message#$get - * @function - * @param {string} key Key - * @return {*} Value - * @throws {Error} If there is no such field - * @expose - */ - MessagePrototype.$get = MessagePrototype.get; - - // Getters and setters - - for (var i=0; i} data Data payload - * @param {(!ByteBuffer|boolean)=} buffer ByteBuffer to encode to. Will create a new one and flip it if omitted. - * @param {boolean=} noVerify Whether to not verify field values, defaults to `false` - * @return {!ByteBuffer} Encoded message as a ByteBuffer - * @expose - */ - Message.encode = function(data, buffer, noVerify) { - return new Message(data).encode(buffer, noVerify); - }; - - /** - * Calculates the byte length of the message. - * @name ProtoBuf.Builder.Message#calculate - * @function - * @returns {number} Byte length - * @throws {Error} If the message cannot be calculated or if required fields are missing. - * @expose - */ - MessagePrototype.calculate = function() { - return T.calculate(this); - }; - - /** - * Encodes the varint32 length-delimited message. - * @name ProtoBuf.Builder.Message#encodeDelimited - * @function - * @param {(!ByteBuffer|boolean)=} buffer ByteBuffer to encode to. Will create a new one and flip it if omitted. - * @param {boolean=} noVerify Whether to not verify field values, defaults to `false` - * @return {!ByteBuffer} Encoded message as a ByteBuffer - * @throws {Error} If the message cannot be encoded or if required fields are missing. The later still - * returns the encoded ByteBuffer in the `encoded` property on the error. - * @expose - */ - MessagePrototype.encodeDelimited = function(buffer, noVerify) { - var isNew = false; - if (!buffer) - buffer = new ByteBuffer(), - isNew = true; - var enc = new ByteBuffer().LE(); - T.encode(this, enc, noVerify).flip(); - buffer.writeVarint32(enc.remaining()); - buffer.append(enc); - return isNew ? buffer.flip() : buffer; - }; - - /** - * Directly encodes the message to an ArrayBuffer. - * @name ProtoBuf.Builder.Message#encodeAB - * @function - * @return {ArrayBuffer} Encoded message as ArrayBuffer - * @throws {Error} If the message cannot be encoded or if required fields are missing. The later still - * returns the encoded ArrayBuffer in the `encoded` property on the error. - * @expose - */ - MessagePrototype.encodeAB = function() { - try { - return this.encode().toArrayBuffer(); - } catch (e) { - if (e["encoded"]) e["encoded"] = e["encoded"].toArrayBuffer(); - throw(e); - } - }; - - /** - * Returns the message as an ArrayBuffer. This is an alias for {@link ProtoBuf.Builder.Message#encodeAB}. - * @name ProtoBuf.Builder.Message#toArrayBuffer - * @function - * @return {ArrayBuffer} Encoded message as ArrayBuffer - * @throws {Error} If the message cannot be encoded or if required fields are missing. The later still - * returns the encoded ArrayBuffer in the `encoded` property on the error. - * @expose - */ - MessagePrototype.toArrayBuffer = MessagePrototype.encodeAB; - - /** - * Directly encodes the message to a node Buffer. - * @name ProtoBuf.Builder.Message#encodeNB - * @function - * @return {!Buffer} - * @throws {Error} If the message cannot be encoded, not running under node.js or if required fields are - * missing. The later still returns the encoded node Buffer in the `encoded` property on the error. - * @expose - */ - MessagePrototype.encodeNB = function() { - try { - return this.encode().toBuffer(); - } catch (e) { - if (e["encoded"]) e["encoded"] = e["encoded"].toBuffer(); - throw(e); - } - }; - - /** - * Returns the message as a node Buffer. This is an alias for {@link ProtoBuf.Builder.Message#encodeNB}. - * @name ProtoBuf.Builder.Message#toBuffer - * @function - * @return {!Buffer} - * @throws {Error} If the message cannot be encoded or if required fields are missing. The later still - * returns the encoded node Buffer in the `encoded` property on the error. - * @expose - */ - MessagePrototype.toBuffer = MessagePrototype.encodeNB; - - /** - * Directly encodes the message to a base64 encoded string. - * @name ProtoBuf.Builder.Message#encode64 - * @function - * @return {string} Base64 encoded string - * @throws {Error} If the underlying buffer cannot be encoded or if required fields are missing. The later - * still returns the encoded base64 string in the `encoded` property on the error. - * @expose - */ - MessagePrototype.encode64 = function() { - try { - return this.encode().toBase64(); - } catch (e) { - if (e["encoded"]) e["encoded"] = e["encoded"].toBase64(); - throw(e); - } - }; - - /** - * Returns the message as a base64 encoded string. This is an alias for {@link ProtoBuf.Builder.Message#encode64}. - * @name ProtoBuf.Builder.Message#toBase64 - * @function - * @return {string} Base64 encoded string - * @throws {Error} If the message cannot be encoded or if required fields are missing. The later still - * returns the encoded base64 string in the `encoded` property on the error. - * @expose - */ - MessagePrototype.toBase64 = MessagePrototype.encode64; - - /** - * Directly encodes the message to a hex encoded string. - * @name ProtoBuf.Builder.Message#encodeHex - * @function - * @return {string} Hex encoded string - * @throws {Error} If the underlying buffer cannot be encoded or if required fields are missing. The later - * still returns the encoded hex string in the `encoded` property on the error. - * @expose - */ - MessagePrototype.encodeHex = function() { - try { - return this.encode().toHex(); - } catch (e) { - if (e["encoded"]) e["encoded"] = e["encoded"].toHex(); - throw(e); - } - }; - - /** - * Returns the message as a hex encoded string. This is an alias for {@link ProtoBuf.Builder.Message#encodeHex}. - * @name ProtoBuf.Builder.Message#toHex - * @function - * @return {string} Hex encoded string - * @throws {Error} If the message cannot be encoded or if required fields are missing. The later still - * returns the encoded hex string in the `encoded` property on the error. - * @expose - */ - MessagePrototype.toHex = MessagePrototype.encodeHex; - - /** - * Clones a message object or field value to a raw object. - * @param {*} obj Object to clone - * @param {boolean} binaryAsBase64 Whether to include binary data as base64 strings or as a buffer otherwise - * @param {boolean} longsAsStrings Whether to encode longs as strings - * @param {!ProtoBuf.Reflect.T=} resolvedType The resolved field type if a field - * @returns {*} Cloned object - * @inner - */ - function cloneRaw(obj, binaryAsBase64, longsAsStrings, resolvedType) { - if (obj === null || typeof obj !== 'object') { - // Convert enum values to their respective names - if (resolvedType && resolvedType instanceof ProtoBuf.Reflect.Enum) { - var name = ProtoBuf.Reflect.Enum.getName(resolvedType.object, obj); - if (name !== null) - return name; - } - // Pass-through string, number, boolean, null... - return obj; - } - // Convert ByteBuffers to raw buffer or strings - if (ByteBuffer.isByteBuffer(obj)) - return binaryAsBase64 ? obj.toBase64() : obj.toBuffer(); - // Convert Longs to proper objects or strings - if (ProtoBuf.Long.isLong(obj)) - return longsAsStrings ? obj.toString() : ProtoBuf.Long.fromValue(obj); - var clone; - // Clone arrays - if (Array.isArray(obj)) { - clone = []; - obj.forEach(function(v, k) { - clone[k] = cloneRaw(v, binaryAsBase64, longsAsStrings, resolvedType); - }); - return clone; - } - clone = {}; - // Convert maps to objects - if (obj instanceof ProtoBuf.Map) { - var it = obj.entries(); - for (var e = it.next(); !e.done; e = it.next()) - clone[obj.keyElem.valueToString(e.value[0])] = cloneRaw(e.value[1], binaryAsBase64, longsAsStrings, obj.valueElem.resolvedType); - return clone; - } - // Everything else is a non-null object - var type = obj.$type, - field = undefined; - for (var i in obj) - if (obj.hasOwnProperty(i)) { - if (type && (field = type.getChild(i))) - clone[i] = cloneRaw(obj[i], binaryAsBase64, longsAsStrings, field.resolvedType); - else - clone[i] = cloneRaw(obj[i], binaryAsBase64, longsAsStrings); - } - return clone; - } - - /** - * Returns the message's raw payload. - * @param {boolean=} binaryAsBase64 Whether to include binary data as base64 strings instead of Buffers, defaults to `false` - * @param {boolean} longsAsStrings Whether to encode longs as strings - * @returns {Object.} Raw payload - * @expose - */ - MessagePrototype.toRaw = function(binaryAsBase64, longsAsStrings) { - return cloneRaw(this, !!binaryAsBase64, !!longsAsStrings, this.$type); - }; - - /** - * Encodes a message to JSON. - * @returns {string} JSON string - * @expose - */ - MessagePrototype.encodeJSON = function() { - return JSON.stringify( - cloneRaw(this, - /* binary-as-base64 */ true, - /* longs-as-strings */ true, - this.$type - ) - ); - }; - - /** - * Decodes a message from the specified buffer or string. - * @name ProtoBuf.Builder.Message.decode - * @function - * @param {!ByteBuffer|!ArrayBuffer|!Buffer|string} buffer Buffer to decode from - * @param {(number|string)=} length Message length. Defaults to decode all the remainig data. - * @param {string=} enc Encoding if buffer is a string: hex, utf8 (not recommended), defaults to base64 - * @return {!ProtoBuf.Builder.Message} Decoded message - * @throws {Error} If the message cannot be decoded or if required fields are missing. The later still - * returns the decoded message with missing fields in the `decoded` property on the error. - * @expose - * @see ProtoBuf.Builder.Message.decode64 - * @see ProtoBuf.Builder.Message.decodeHex - */ - Message.decode = function(buffer, length, enc) { - if (typeof length === 'string') - enc = length, - length = -1; - if (typeof buffer === 'string') - buffer = ByteBuffer.wrap(buffer, enc ? enc : "base64"); - buffer = ByteBuffer.isByteBuffer(buffer) ? buffer : ByteBuffer.wrap(buffer); // May throw - var le = buffer.littleEndian; - try { - var msg = T.decode(buffer.LE()); - buffer.LE(le); - return msg; - } catch (e) { - buffer.LE(le); - throw(e); - } - }; - - /** - * Decodes a varint32 length-delimited message from the specified buffer or string. - * @name ProtoBuf.Builder.Message.decodeDelimited - * @function - * @param {!ByteBuffer|!ArrayBuffer|!Buffer|string} buffer Buffer to decode from - * @param {string=} enc Encoding if buffer is a string: hex, utf8 (not recommended), defaults to base64 - * @return {ProtoBuf.Builder.Message} Decoded message or `null` if not enough bytes are available yet - * @throws {Error} If the message cannot be decoded or if required fields are missing. The later still - * returns the decoded message with missing fields in the `decoded` property on the error. - * @expose - */ - Message.decodeDelimited = function(buffer, enc) { - if (typeof buffer === 'string') - buffer = ByteBuffer.wrap(buffer, enc ? enc : "base64"); - buffer = ByteBuffer.isByteBuffer(buffer) ? buffer : ByteBuffer.wrap(buffer); // May throw - if (buffer.remaining() < 1) - return null; - var off = buffer.offset, - len = buffer.readVarint32(); - if (buffer.remaining() < len) { - buffer.offset = off; - return null; - } - try { - var msg = T.decode(buffer.slice(buffer.offset, buffer.offset + len).LE()); - buffer.offset += len; - return msg; - } catch (err) { - buffer.offset += len; - throw err; - } - }; - - /** - * Decodes the message from the specified base64 encoded string. - * @name ProtoBuf.Builder.Message.decode64 - * @function - * @param {string} str String to decode from - * @return {!ProtoBuf.Builder.Message} Decoded message - * @throws {Error} If the message cannot be decoded or if required fields are missing. The later still - * returns the decoded message with missing fields in the `decoded` property on the error. - * @expose - */ - Message.decode64 = function(str) { - return Message.decode(str, "base64"); - }; - - /** - * Decodes the message from the specified hex encoded string. - * @name ProtoBuf.Builder.Message.decodeHex - * @function - * @param {string} str String to decode from - * @return {!ProtoBuf.Builder.Message} Decoded message - * @throws {Error} If the message cannot be decoded or if required fields are missing. The later still - * returns the decoded message with missing fields in the `decoded` property on the error. - * @expose - */ - Message.decodeHex = function(str) { - return Message.decode(str, "hex"); - }; - - /** - * Decodes the message from a JSON string. - * @name ProtoBuf.Builder.Message.decodeJSON - * @function - * @param {string} str String to decode from - * @return {!ProtoBuf.Builder.Message} Decoded message - * @throws {Error} If the message cannot be decoded or if required fields are - * missing. - * @expose - */ - Message.decodeJSON = function(str) { - return new Message(JSON.parse(str)); - }; - - // Utility - - /** - * Returns a string representation of this Message. - * @name ProtoBuf.Builder.Message#toString - * @function - * @return {string} String representation as of ".Fully.Qualified.MessageName" - * @expose - */ - MessagePrototype.toString = function() { - return T.toString(); - }; - - // Properties - - /** - * Message options. - * @name ProtoBuf.Builder.Message.$options - * @type {Object.} - * @expose - */ - var $optionsS; // cc needs this - - /** - * Message options. - * @name ProtoBuf.Builder.Message#$options - * @type {Object.} - * @expose - */ - var $options; - - /** - * Reflection type. - * @name ProtoBuf.Builder.Message.$type - * @type {!ProtoBuf.Reflect.Message} - * @expose - */ - var $typeS; - - /** - * Reflection type. - * @name ProtoBuf.Builder.Message#$type - * @type {!ProtoBuf.Reflect.Message} - * @expose - */ - var $type; - - if (Object.defineProperty) - Object.defineProperty(Message, '$options', { "value": T.buildOpt() }), - Object.defineProperty(MessagePrototype, "$options", { "value": Message["$options"] }), - Object.defineProperty(Message, "$type", { "value": T }), - Object.defineProperty(MessagePrototype, "$type", { "value": T }); - - return Message; - - })(ProtoBuf, this); - - // Static enums and prototyped sub-messages / cached collections - this._fields = []; - this._fieldsById = {}; - this._fieldsByName = {}; - for (var i=0, k=this.children.length, child; i>> 3; - switch (wireType) { - case ProtoBuf.WIRE_TYPES.VARINT: - do tag = buf.readUint8(); - while ((tag & 0x80) === 0x80); - break; - case ProtoBuf.WIRE_TYPES.BITS64: - buf.offset += 8; - break; - case ProtoBuf.WIRE_TYPES.LDELIM: - tag = buf.readVarint32(); // reads the varint - buf.offset += tag; // skips n bytes - break; - case ProtoBuf.WIRE_TYPES.STARTGROUP: - skipTillGroupEnd(id, buf); - break; - case ProtoBuf.WIRE_TYPES.ENDGROUP: - if (id === expectedId) - return false; - else - throw Error("Illegal GROUPEND after unknown group: "+id+" ("+expectedId+" expected)"); - case ProtoBuf.WIRE_TYPES.BITS32: - buf.offset += 4; - break; - default: - throw Error("Illegal wire type in unknown group "+expectedId+": "+wireType); - } - return true; - } - - /** - * Decodes an encoded message and returns the decoded message. - * @param {ByteBuffer} buffer ByteBuffer to decode from - * @param {number=} length Message length. Defaults to decode all remaining data. - * @param {number=} expectedGroupEndId Expected GROUPEND id if this is a legacy group - * @return {ProtoBuf.Builder.Message} Decoded message - * @throws {Error} If the message cannot be decoded - * @expose - */ - MessagePrototype.decode = function(buffer, length, expectedGroupEndId) { - length = typeof length === 'number' ? length : -1; - var start = buffer.offset, - msg = new (this.clazz)(), - tag, wireType, id, field; - while (buffer.offset < start+length || (length === -1 && buffer.remaining() > 0)) { - tag = buffer.readVarint32(); - wireType = tag & 0x07; - id = tag >>> 3; - if (wireType === ProtoBuf.WIRE_TYPES.ENDGROUP) { - if (id !== expectedGroupEndId) - throw Error("Illegal group end indicator for "+this.toString(true)+": "+id+" ("+(expectedGroupEndId ? expectedGroupEndId+" expected" : "not a group")+")"); - break; - } - if (!(field = this._fieldsById[id])) { - // "messages created by your new code can be parsed by your old code: old binaries simply ignore the new field when parsing." - switch (wireType) { - case ProtoBuf.WIRE_TYPES.VARINT: - buffer.readVarint32(); - break; - case ProtoBuf.WIRE_TYPES.BITS32: - buffer.offset += 4; - break; - case ProtoBuf.WIRE_TYPES.BITS64: - buffer.offset += 8; - break; - case ProtoBuf.WIRE_TYPES.LDELIM: - var len = buffer.readVarint32(); - buffer.offset += len; - break; - case ProtoBuf.WIRE_TYPES.STARTGROUP: - while (skipTillGroupEnd(id, buffer)) {} - break; - default: - throw Error("Illegal wire type for unknown field "+id+" in "+this.toString(true)+"#decode: "+wireType); - } - continue; - } - if (field.repeated && !field.options["packed"]) { - msg[field.name].push(field.decode(wireType, buffer)); - } else if (field.map) { - var keyval = field.decode(wireType, buffer); - msg[field.name].set(keyval[0], keyval[1]); - } else { - msg[field.name] = field.decode(wireType, buffer); - if (field.oneof) { // Field is part of an OneOf (not a virtual OneOf field) - var currentField = msg[field.oneof.name]; // Virtual field references currently set field - if (currentField !== null && currentField !== field.name) - msg[currentField] = null; // Clear currently set field - msg[field.oneof.name] = field.name; // Point virtual field at this field - } - } - } - - // Check if all required fields are present and set default values for optional fields that are not - for (var i=0, k=this._fields.length; i=} options Options - * @param {!ProtoBuf.Reflect.Message.OneOf=} oneof Enclosing OneOf - * @param {string?} syntax The syntax level of this definition (e.g., proto3) - * @constructor - * @extends ProtoBuf.Reflect.T - */ - var Field = function(builder, message, rule, keytype, type, name, id, options, oneof, syntax) { - T.call(this, builder, message, name); - - /** - * @override - */ - this.className = "Message.Field"; - - /** - * Message field required flag. - * @type {boolean} - * @expose - */ - this.required = rule === "required"; - - /** - * Message field repeated flag. - * @type {boolean} - * @expose - */ - this.repeated = rule === "repeated"; - - /** - * Message field map flag. - * @type {boolean} - * @expose - */ - this.map = rule === "map"; - - /** - * Message field key type. Type reference string if unresolved, protobuf - * type if resolved. Valid only if this.map === true, null otherwise. - * @type {string|{name: string, wireType: number}|null} - * @expose - */ - this.keyType = keytype || null; - - /** - * Message field type. Type reference string if unresolved, protobuf type if - * resolved. In a map field, this is the value type. - * @type {string|{name: string, wireType: number}} - * @expose - */ - this.type = type; - - /** - * Resolved type reference inside the global namespace. - * @type {ProtoBuf.Reflect.T|null} - * @expose - */ - this.resolvedType = null; - - /** - * Unique message field id. - * @type {number} - * @expose - */ - this.id = id; - - /** - * Message field options. - * @type {!Object.} - * @dict - * @expose - */ - this.options = options || {}; - - /** - * Default value. - * @type {*} - * @expose - */ - this.defaultValue = null; - - /** - * Enclosing OneOf. - * @type {?ProtoBuf.Reflect.Message.OneOf} - * @expose - */ - this.oneof = oneof || null; - - /** - * Syntax level of this definition (e.g., proto3). - * @type {string} - * @expose - */ - this.syntax = syntax || 'proto2'; - - /** - * Original field name. - * @type {string} - * @expose - */ - this.originalName = this.name; // Used to revert camelcase transformation on naming collisions - - /** - * Element implementation. Created in build() after types are resolved. - * @type {ProtoBuf.Element} - * @expose - */ - this.element = null; - - /** - * Key element implementation, for map fields. Created in build() after - * types are resolved. - * @type {ProtoBuf.Element} - * @expose - */ - this.keyElement = null; - - // Convert field names to camel case notation if the override is set - if (this.builder.options['convertFieldsToCamelCase'] && !(this instanceof Message.ExtensionField)) - this.name = ProtoBuf.Util.toCamelCase(this.name); - }; - - /** - * @alias ProtoBuf.Reflect.Message.Field.prototype - * @inner - */ - var FieldPrototype = Field.prototype = Object.create(T.prototype); - - /** - * Builds the field. - * @override - * @expose - */ - FieldPrototype.build = function() { - this.element = new Element(this.type, this.resolvedType, false, this.syntax); - if (this.map) - this.keyElement = new Element(this.keyType, undefined, true, this.syntax); - - // In proto3, fields do not have field presence, and every field is set to - // its type's default value ("", 0, 0.0, or false). - if (this.syntax === 'proto3' && !this.repeated && !this.map) - this.defaultValue = Element.defaultFieldValue(this.type); - - // Otherwise, default values are present when explicitly specified - else if (typeof this.options['default'] !== 'undefined') - this.defaultValue = this.verifyValue(this.options['default']); - }; - - /** - * Checks if the given value can be set for this field. - * @param {*} value Value to check - * @param {boolean=} skipRepeated Whether to skip the repeated value check or not. Defaults to false. - * @return {*} Verified, maybe adjusted, value - * @throws {Error} If the value cannot be set for this field - * @expose - */ - FieldPrototype.verifyValue = function(value, skipRepeated) { - skipRepeated = skipRepeated || false; - var self = this; - function fail(val, msg) { - throw Error("Illegal value for "+self.toString(true)+" of type "+self.type.name+": "+val+" ("+msg+")"); - } - if (value === null) { // NULL values for optional fields - if (this.required) - fail(typeof value, "required"); - if (this.syntax === 'proto3' && this.type !== ProtoBuf.TYPES["message"]) - fail(typeof value, "proto3 field without field presence cannot be null"); - return null; - } - var i; - if (this.repeated && !skipRepeated) { // Repeated values as arrays - if (!Array.isArray(value)) - value = [value]; - var res = []; - for (i=0; i 0; - - case ProtoBuf.TYPES["bytes"]: - return value.remaining() > 0; - - case ProtoBuf.TYPES["enum"]: - return value !== 0; - - case ProtoBuf.TYPES["message"]: - return value !== null; - default: - return true; - } - }; - - /** - * Encodes the specified field value to the specified buffer. - * @param {*} value Verified field value - * @param {ByteBuffer} buffer ByteBuffer to encode to - * @param {!ProtoBuf.Builder.Message} message Runtime message - * @return {ByteBuffer} The ByteBuffer for chaining - * @throws {Error} If the field cannot be encoded - * @expose - */ - FieldPrototype.encode = function(value, buffer, message) { - if (this.type === null || typeof this.type !== 'object') - throw Error("[INTERNAL] Unresolved type in "+this.toString(true)+": "+this.type); - if (value === null || (this.repeated && value.length == 0)) - return buffer; // Optional omitted - try { - if (this.repeated) { - var i; - // "Only repeated fields of primitive numeric types (types which use the varint, 32-bit, or 64-bit wire - // types) can be declared 'packed'." - if (this.options["packed"] && ProtoBuf.PACKABLE_WIRE_TYPES.indexOf(this.type.wireType) >= 0) { - // "All of the elements of the field are packed into a single key-value pair with wire type 2 - // (length-delimited). Each element is encoded the same way it would be normally, except without a - // tag preceding it." - buffer.writeVarint32((this.id << 3) | ProtoBuf.WIRE_TYPES.LDELIM); - buffer.ensureCapacity(buffer.offset += 1); // We do not know the length yet, so let's assume a varint of length 1 - var start = buffer.offset; // Remember where the contents begin - for (i=0; i 1) { // We need to move the contents - var contents = buffer.slice(start, buffer.offset); - start += varintLen-1; - buffer.offset = start; - buffer.append(contents); - } - buffer.writeVarint32(len, start-varintLen); - } else { - // "If your message definition has repeated elements (without the [packed=true] option), the encoded - // message has zero or more key-value pairs with the same tag number" - for (i=0; i= 0) { - n += ByteBuffer.calculateVarint32((this.id << 3) | ProtoBuf.WIRE_TYPES.LDELIM); - ni = 0; - for (i=0; i= 0) { - if (!skipRepeated) { - nBytes = buffer.readVarint32(); - nBytes = buffer.offset + nBytes; // Limit - var values = []; - while (buffer.offset < nBytes) - values.push(this.decode(this.type.wireType, buffer, true)); - return values; - } - // Read the next value otherwise... - } - - // Handle maps. - if (this.map) { - // Read one (key, value) submessage, and return [key, value] - var key = Element.defaultFieldValue(this.keyType); - value = Element.defaultFieldValue(this.type); - - // Read the length - nBytes = buffer.readVarint32(); - if (buffer.remaining() < nBytes) - throw Error("Illegal number of bytes for "+this.toString(true)+": "+nBytes+" required but got only "+buffer.remaining()); - - // Get a sub-buffer of this key/value submessage - var msgbuf = buffer.clone(); - msgbuf.limit = msgbuf.offset + nBytes; - buffer.offset += nBytes; - - while (msgbuf.remaining() > 0) { - var tag = msgbuf.readVarint32(); - wireType = tag & 0x07; - var id = tag >>> 3; - if (id === 1) { - key = this.keyElement.decode(msgbuf, wireType, id); - } else if (id === 2) { - value = this.element.decode(msgbuf, wireType, id); - } else { - throw Error("Unexpected tag in map field key/value submessage"); - } - } - - return [key, value]; - } - - // Handle singular and non-packed repeated field values. - return this.element.decode(buffer, wireType, this.id); - }; - - /** - * @alias ProtoBuf.Reflect.Message.Field - * @expose - */ - Reflect.Message.Field = Field; - - /** - * Constructs a new Message ExtensionField. - * @exports ProtoBuf.Reflect.Message.ExtensionField - * @param {!ProtoBuf.Builder} builder Builder reference - * @param {!ProtoBuf.Reflect.Message} message Message reference - * @param {string} rule Rule, one of requried, optional, repeated - * @param {string} type Data type, e.g. int32 - * @param {string} name Field name - * @param {number} id Unique field id - * @param {!Object.=} options Options - * @constructor - * @extends ProtoBuf.Reflect.Message.Field - */ - var ExtensionField = function(builder, message, rule, type, name, id, options) { - Field.call(this, builder, message, rule, /* keytype = */ null, type, name, id, options); - - /** - * Extension reference. - * @type {!ProtoBuf.Reflect.Extension} - * @expose - */ - this.extension; - }; - - // Extends Field - ExtensionField.prototype = Object.create(Field.prototype); - - /** - * @alias ProtoBuf.Reflect.Message.ExtensionField - * @expose - */ - Reflect.Message.ExtensionField = ExtensionField; - - /** - * Constructs a new Message OneOf. - * @exports ProtoBuf.Reflect.Message.OneOf - * @param {!ProtoBuf.Builder} builder Builder reference - * @param {!ProtoBuf.Reflect.Message} message Message reference - * @param {string} name OneOf name - * @constructor - * @extends ProtoBuf.Reflect.T - */ - var OneOf = function(builder, message, name) { - T.call(this, builder, message, name); - - /** - * Enclosed fields. - * @type {!Array.} - * @expose - */ - this.fields = []; - }; - - /** - * @alias ProtoBuf.Reflect.Message.OneOf - * @expose - */ - Reflect.Message.OneOf = OneOf; - - /** - * Constructs a new Enum. - * @exports ProtoBuf.Reflect.Enum - * @param {!ProtoBuf.Builder} builder Builder reference - * @param {!ProtoBuf.Reflect.T} parent Parent Reflect object - * @param {string} name Enum name - * @param {Object.=} options Enum options - * @param {string?} syntax The syntax level (e.g., proto3) - * @constructor - * @extends ProtoBuf.Reflect.Namespace - */ - var Enum = function(builder, parent, name, options, syntax) { - Namespace.call(this, builder, parent, name, options, syntax); - - /** - * @override - */ - this.className = "Enum"; - - /** - * Runtime enum object. - * @type {Object.|null} - * @expose - */ - this.object = null; - }; - - /** - * Gets the string name of an enum value. - * @param {!ProtoBuf.Builder.Enum} enm Runtime enum - * @param {number} value Enum value - * @returns {?string} Name or `null` if not present - * @expose - */ - Enum.getName = function(enm, value) { - var keys = Object.keys(enm); - for (var i=0, key; i} - * @expose - */ - EnumPrototype.build = function(rebuild) { - if (this.object && !rebuild) - return this.object; - var enm = new ProtoBuf.Builder.Enum(), - values = this.getChildren(Enum.Value); - for (var i=0, k=values.length; i=} options Options - * @constructor - * @extends ProtoBuf.Reflect.Namespace - */ - var Service = function(builder, root, name, options) { - Namespace.call(this, builder, root, name, options); - - /** - * @override - */ - this.className = "Service"; - - /** - * Built runtime service class. - * @type {?function(new:ProtoBuf.Builder.Service)} - */ - this.clazz = null; - }; - - /** - * @alias ProtoBuf.Reflect.Service.prototype - * @inner - */ - var ServicePrototype = Service.prototype = Object.create(Namespace.prototype); - - /** - * Builds the service and returns the runtime counterpart, which is a fully functional class. - * @see ProtoBuf.Builder.Service - * @param {boolean=} rebuild Whether to rebuild or not - * @return {Function} Service class - * @throws {Error} If the message cannot be built - * @expose - */ - ServicePrototype.build = function(rebuild) { - if (this.clazz && !rebuild) - return this.clazz; - - // Create the runtime Service class in its own scope - return this.clazz = (function(ProtoBuf, T) { - - /** - * Constructs a new runtime Service. - * @name ProtoBuf.Builder.Service - * @param {function(string, ProtoBuf.Builder.Message, function(Error, ProtoBuf.Builder.Message=))=} rpcImpl RPC implementation receiving the method name and the message - * @class Barebone of all runtime services. - * @constructor - * @throws {Error} If the service cannot be created - */ - var Service = function(rpcImpl) { - ProtoBuf.Builder.Service.call(this); - - /** - * Service implementation. - * @name ProtoBuf.Builder.Service#rpcImpl - * @type {!function(string, ProtoBuf.Builder.Message, function(Error, ProtoBuf.Builder.Message=))} - * @expose - */ - this.rpcImpl = rpcImpl || function(name, msg, callback) { - // This is what a user has to implement: A function receiving the method name, the actual message to - // send (type checked) and the callback that's either provided with the error as its first - // argument or null and the actual response message. - setTimeout(callback.bind(this, Error("Not implemented, see: https://github.com/dcodeIO/ProtoBuf.js/wiki/Services")), 0); // Must be async! - }; - }; - - /** - * @alias ProtoBuf.Builder.Service.prototype - * @inner - */ - var ServicePrototype = Service.prototype = Object.create(ProtoBuf.Builder.Service.prototype); - - /** - * Asynchronously performs an RPC call using the given RPC implementation. - * @name ProtoBuf.Builder.Service.[Method] - * @function - * @param {!function(string, ProtoBuf.Builder.Message, function(Error, ProtoBuf.Builder.Message=))} rpcImpl RPC implementation - * @param {ProtoBuf.Builder.Message} req Request - * @param {function(Error, (ProtoBuf.Builder.Message|ByteBuffer|Buffer|string)=)} callback Callback receiving - * the error if any and the response either as a pre-parsed message or as its raw bytes - * @abstract - */ - - /** - * Asynchronously performs an RPC call using the instance's RPC implementation. - * @name ProtoBuf.Builder.Service#[Method] - * @function - * @param {ProtoBuf.Builder.Message} req Request - * @param {function(Error, (ProtoBuf.Builder.Message|ByteBuffer|Buffer|string)=)} callback Callback receiving - * the error if any and the response either as a pre-parsed message or as its raw bytes - * @abstract - */ - - var rpc = T.getChildren(ProtoBuf.Reflect.Service.RPCMethod); - for (var i=0; i} - * @expose - */ - var $optionsS; // cc needs this - - /** - * Service options. - * @name ProtoBuf.Builder.Service#$options - * @type {Object.} - * @expose - */ - var $options; - - /** - * Reflection type. - * @name ProtoBuf.Builder.Service.$type - * @type {!ProtoBuf.Reflect.Service} - * @expose - */ - var $typeS; - - /** - * Reflection type. - * @name ProtoBuf.Builder.Service#$type - * @type {!ProtoBuf.Reflect.Service} - * @expose - */ - var $type; - - if (Object.defineProperty) - Object.defineProperty(Service, "$options", { "value": T.buildOpt() }), - Object.defineProperty(ServicePrototype, "$options", { "value": Service["$options"] }), - Object.defineProperty(Service, "$type", { "value": T }), - Object.defineProperty(ServicePrototype, "$type", { "value": T }); - - return Service; - - })(ProtoBuf, this); - }; - - /** - * @alias ProtoBuf.Reflect.Service - * @expose - */ - Reflect.Service = Service; - - /** - * Abstract service method. - * @exports ProtoBuf.Reflect.Service.Method - * @param {!ProtoBuf.Builder} builder Builder reference - * @param {!ProtoBuf.Reflect.Service} svc Service - * @param {string} name Method name - * @param {Object.=} options Options - * @constructor - * @extends ProtoBuf.Reflect.T - */ - var Method = function(builder, svc, name, options) { - T.call(this, builder, svc, name); - - /** - * @override - */ - this.className = "Service.Method"; - - /** - * Options. - * @type {Object.} - * @expose - */ - this.options = options || {}; - }; - - /** - * @alias ProtoBuf.Reflect.Service.Method.prototype - * @inner - */ - var MethodPrototype = Method.prototype = Object.create(T.prototype); - - /** - * Builds the method's '$options' property. - * @name ProtoBuf.Reflect.Service.Method#buildOpt - * @function - * @return {Object.} - */ - MethodPrototype.buildOpt = NamespacePrototype.buildOpt; - - /** - * @alias ProtoBuf.Reflect.Service.Method - * @expose - */ - Reflect.Service.Method = Method; - - /** - * RPC service method. - * @exports ProtoBuf.Reflect.Service.RPCMethod - * @param {!ProtoBuf.Builder} builder Builder reference - * @param {!ProtoBuf.Reflect.Service} svc Service - * @param {string} name Method name - * @param {string} request Request message name - * @param {string} response Response message name - * @param {boolean} request_stream Whether requests are streamed - * @param {boolean} response_stream Whether responses are streamed - * @param {Object.=} options Options - * @constructor - * @extends ProtoBuf.Reflect.Service.Method - */ - var RPCMethod = function(builder, svc, name, request, response, request_stream, response_stream, options) { - Method.call(this, builder, svc, name, options); - - /** - * @override - */ - this.className = "Service.RPCMethod"; - - /** - * Request message name. - * @type {string} - * @expose - */ - this.requestName = request; - - /** - * Response message name. - * @type {string} - * @expose - */ - this.responseName = response; - - /** - * Whether requests are streamed - * @type {bool} - * @expose - */ - this.requestStream = request_stream; - - /** - * Whether responses are streamed - * @type {bool} - * @expose - */ - this.responseStream = response_stream; - - /** - * Resolved request message type. - * @type {ProtoBuf.Reflect.Message} - * @expose - */ - this.resolvedRequestType = null; - - /** - * Resolved response message type. - * @type {ProtoBuf.Reflect.Message} - * @expose - */ - this.resolvedResponseType = null; - }; - - // Extends Method - RPCMethod.prototype = Object.create(Method.prototype); - - /** - * @alias ProtoBuf.Reflect.Service.RPCMethod - * @expose - */ - Reflect.Service.RPCMethod = RPCMethod; - - return Reflect; - - })(ProtoBuf); - - /** - * @alias ProtoBuf.Builder - * @expose - */ - ProtoBuf.Builder = (function(ProtoBuf, Lang, Reflect) { - "use strict"; - - /** - * Constructs a new Builder. - * @exports ProtoBuf.Builder - * @class Provides the functionality to build protocol messages. - * @param {Object.=} options Options - * @constructor - */ - var Builder = function(options) { - - /** - * Namespace. - * @type {ProtoBuf.Reflect.Namespace} - * @expose - */ - this.ns = new Reflect.Namespace(this, null, ""); // Global namespace - - /** - * Namespace pointer. - * @type {ProtoBuf.Reflect.T} - * @expose - */ - this.ptr = this.ns; - - /** - * Resolved flag. - * @type {boolean} - * @expose - */ - this.resolved = false; - - /** - * The current building result. - * @type {Object.|null} - * @expose - */ - this.result = null; - - /** - * Imported files. - * @type {Array.} - * @expose - */ - this.files = {}; - - /** - * Import root override. - * @type {?string} - * @expose - */ - this.importRoot = null; - - /** - * Options. - * @type {!Object.} - * @expose - */ - this.options = options || {}; - }; - - /** - * @alias ProtoBuf.Builder.prototype - * @inner - */ - var BuilderPrototype = Builder.prototype; - - // ----- Definition tests ----- - - /** - * Tests if a definition most likely describes a message. - * @param {!Object} def - * @returns {boolean} - * @expose - */ - Builder.isMessage = function(def) { - // Messages require a string name - if (typeof def["name"] !== 'string') - return false; - // Messages do not contain values (enum) or rpc methods (service) - if (typeof def["values"] !== 'undefined' || typeof def["rpc"] !== 'undefined') - return false; - return true; - }; - - /** - * Tests if a definition most likely describes a message field. - * @param {!Object} def - * @returns {boolean} - * @expose - */ - Builder.isMessageField = function(def) { - // Message fields require a string rule, name and type and an id - if (typeof def["rule"] !== 'string' || typeof def["name"] !== 'string' || typeof def["type"] !== 'string' || typeof def["id"] === 'undefined') - return false; - return true; - }; - - /** - * Tests if a definition most likely describes an enum. - * @param {!Object} def - * @returns {boolean} - * @expose - */ - Builder.isEnum = function(def) { - // Enums require a string name - if (typeof def["name"] !== 'string') - return false; - // Enums require at least one value - if (typeof def["values"] === 'undefined' || !Array.isArray(def["values"]) || def["values"].length === 0) - return false; - return true; - }; - - /** - * Tests if a definition most likely describes a service. - * @param {!Object} def - * @returns {boolean} - * @expose - */ - Builder.isService = function(def) { - // Services require a string name and an rpc object - if (typeof def["name"] !== 'string' || typeof def["rpc"] !== 'object' || !def["rpc"]) - return false; - return true; - }; - - /** - * Tests if a definition most likely describes an extended message - * @param {!Object} def - * @returns {boolean} - * @expose - */ - Builder.isExtend = function(def) { - // Extends rquire a string ref - if (typeof def["ref"] !== 'string') - return false; - return true; - }; - - // ----- Building ----- - - /** - * Resets the pointer to the root namespace. - * @returns {!ProtoBuf.Builder} this - * @expose - */ - BuilderPrototype.reset = function() { - this.ptr = this.ns; - return this; - }; - - /** - * Defines a namespace on top of the current pointer position and places the pointer on it. - * @param {string} namespace - * @return {!ProtoBuf.Builder} this - * @expose - */ - BuilderPrototype.define = function(namespace) { - if (typeof namespace !== 'string' || !Lang.TYPEREF.test(namespace)) - throw Error("illegal namespace: "+namespace); - namespace.split(".").forEach(function(part) { - var ns = this.ptr.getChild(part); - if (ns === null) // Keep existing - this.ptr.addChild(ns = new Reflect.Namespace(this, this.ptr, part)); - this.ptr = ns; - }, this); - return this; - }; - - /** - * Creates the specified definitions at the current pointer position. - * @param {!Array.} defs Messages, enums or services to create - * @returns {!ProtoBuf.Builder} this - * @throws {Error} If a message definition is invalid - * @expose - */ - BuilderPrototype.create = function(defs) { - if (!defs) - return this; // Nothing to create - if (!Array.isArray(defs)) - defs = [defs]; - else { - if (defs.length === 0) - return this; - defs = defs.slice(); - } - - // It's quite hard to keep track of scopes and memory here, so let's do this iteratively. - var stack = [defs]; - while (stack.length > 0) { - defs = stack.pop(); - - if (!Array.isArray(defs)) // Stack always contains entire namespaces - throw Error("not a valid namespace: "+JSON.stringify(defs)); - - while (defs.length > 0) { - var def = defs.shift(); // Namespaces always contain an array of messages, enums and services - - if (Builder.isMessage(def)) { - var obj = new Reflect.Message(this, this.ptr, def["name"], def["options"], def["isGroup"], def["syntax"]); - - // Create OneOfs - var oneofs = {}; - if (def["oneofs"]) - Object.keys(def["oneofs"]).forEach(function(name) { - obj.addChild(oneofs[name] = new Reflect.Message.OneOf(this, obj, name)); - }, this); - - // Create fields - if (def["fields"]) - def["fields"].forEach(function(fld) { - if (obj.getChild(fld["id"]|0) !== null) - throw Error("duplicate or invalid field id in "+obj.name+": "+fld['id']); - if (fld["options"] && typeof fld["options"] !== 'object') - throw Error("illegal field options in "+obj.name+"#"+fld["name"]); - var oneof = null; - if (typeof fld["oneof"] === 'string' && !(oneof = oneofs[fld["oneof"]])) - throw Error("illegal oneof in "+obj.name+"#"+fld["name"]+": "+fld["oneof"]); - fld = new Reflect.Message.Field(this, obj, fld["rule"], fld["keytype"], fld["type"], fld["name"], fld["id"], fld["options"], oneof, def["syntax"]); - if (oneof) - oneof.fields.push(fld); - obj.addChild(fld); - }, this); - - // Push children to stack - var subObj = []; - if (def["enums"]) - def["enums"].forEach(function(enm) { - subObj.push(enm); - }); - if (def["messages"]) - def["messages"].forEach(function(msg) { - subObj.push(msg); - }); - if (def["services"]) - def["services"].forEach(function(svc) { - subObj.push(svc); - }); - - // Set extension ranges - if (def["extensions"]) { - if (typeof def["extensions"][0] === 'number') // pre 5.0.1 - obj.extensions = [ def["extensions"] ]; - else - obj.extensions = def["extensions"]; - } - - // Create on top of current namespace - this.ptr.addChild(obj); - if (subObj.length > 0) { - stack.push(defs); // Push the current level back - defs = subObj; // Continue processing sub level - subObj = null; - this.ptr = obj; // And move the pointer to this namespace - obj = null; - continue; - } - subObj = null; - - } else if (Builder.isEnum(def)) { - - obj = new Reflect.Enum(this, this.ptr, def["name"], def["options"], def["syntax"]); - def["values"].forEach(function(val) { - obj.addChild(new Reflect.Enum.Value(this, obj, val["name"], val["id"])); - }, this); - this.ptr.addChild(obj); - - } else if (Builder.isService(def)) { - - obj = new Reflect.Service(this, this.ptr, def["name"], def["options"]); - Object.keys(def["rpc"]).forEach(function(name) { - var mtd = def["rpc"][name]; - obj.addChild(new Reflect.Service.RPCMethod(this, obj, name, mtd["request"], mtd["response"], !!mtd["request_stream"], !!mtd["response_stream"], mtd["options"])); - }, this); - this.ptr.addChild(obj); - - } else if (Builder.isExtend(def)) { - - obj = this.ptr.resolve(def["ref"], true); - if (obj) { - def["fields"].forEach(function(fld) { - if (obj.getChild(fld['id']|0) !== null) - throw Error("duplicate extended field id in "+obj.name+": "+fld['id']); - // Check if field id is allowed to be extended - if (obj.extensions) { - var valid = false; - obj.extensions.forEach(function(range) { - if (fld["id"] >= range[0] && fld["id"] <= range[1]) - valid = true; - }); - if (!valid) - throw Error("illegal extended field id in "+obj.name+": "+fld['id']+" (not within valid ranges)"); - } - // Convert extension field names to camel case notation if the override is set - var name = fld["name"]; - if (this.options['convertFieldsToCamelCase']) - name = ProtoBuf.Util.toCamelCase(name); - // see #161: Extensions use their fully qualified name as their runtime key and... - var field = new Reflect.Message.ExtensionField(this, obj, fld["rule"], fld["type"], this.ptr.fqn()+'.'+name, fld["id"], fld["options"]); - // ...are added on top of the current namespace as an extension which is used for - // resolving their type later on (the extension always keeps the original name to - // prevent naming collisions) - var ext = new Reflect.Extension(this, this.ptr, fld["name"], field); - field.extension = ext; - this.ptr.addChild(ext); - obj.addChild(field); - }, this); - - } else if (!/\.?google\.protobuf\./.test(def["ref"])) // Silently skip internal extensions - throw Error("extended message "+def["ref"]+" is not defined"); - - } else - throw Error("not a valid definition: "+JSON.stringify(def)); - - def = null; - obj = null; - } - // Break goes here - defs = null; - this.ptr = this.ptr.parent; // Namespace done, continue at parent - } - this.resolved = false; // Require re-resolve - this.result = null; // Require re-build - return this; - }; - - /** - * Propagates syntax to all children. - * @param {!Object} parent - * @inner - */ - function propagateSyntax(parent) { - if (parent['messages']) { - parent['messages'].forEach(function(child) { - child["syntax"] = parent["syntax"]; - propagateSyntax(child); - }); - } - if (parent['enums']) { - parent['enums'].forEach(function(child) { - child["syntax"] = parent["syntax"]; - }); - } - } - - /** - * Imports another definition into this builder. - * @param {Object.} json Parsed import - * @param {(string|{root: string, file: string})=} filename Imported file name - * @returns {!ProtoBuf.Builder} this - * @throws {Error} If the definition or file cannot be imported - * @expose - */ - BuilderPrototype["import"] = function(json, filename) { - var delim = '/'; - - // Make sure to skip duplicate imports - - if (typeof filename === 'string') { - - if (ProtoBuf.Util.IS_NODE) - filename = require("path")['resolve'](filename); - if (this.files[filename] === true) - return this.reset(); - this.files[filename] = true; - - } else if (typeof filename === 'object') { // Object with root, file. - - var root = filename.root; - if (ProtoBuf.Util.IS_NODE) - root = require("path")['resolve'](root); - if (root.indexOf("\\") >= 0 || filename.file.indexOf("\\") >= 0) - delim = '\\'; - var fname = root + delim + filename.file; - if (this.files[fname] === true) - return this.reset(); - this.files[fname] = true; - } - - // Import imports - - if (json['imports'] && json['imports'].length > 0) { - var importRoot, - resetRoot = false; - - if (typeof filename === 'object') { // If an import root is specified, override - - this.importRoot = filename["root"]; resetRoot = true; // ... and reset afterwards - importRoot = this.importRoot; - filename = filename["file"]; - if (importRoot.indexOf("\\") >= 0 || filename.indexOf("\\") >= 0) - delim = '\\'; - - } else if (typeof filename === 'string') { - - if (this.importRoot) // If import root is overridden, use it - importRoot = this.importRoot; - else { // Otherwise compute from filename - if (filename.indexOf("/") >= 0) { // Unix - importRoot = filename.replace(/\/[^\/]*$/, ""); - if (/* /file.proto */ importRoot === "") - importRoot = "/"; - } else if (filename.indexOf("\\") >= 0) { // Windows - importRoot = filename.replace(/\\[^\\]*$/, ""); - delim = '\\'; - } else - importRoot = "."; - } - - } else - importRoot = null; - - for (var i=0; i)=} path Specifies what to return. If omitted, the entire namespace will be returned. - * @returns {!ProtoBuf.Builder.Message|!Object.} - * @throws {Error} If a type could not be resolved - * @expose - */ - BuilderPrototype.build = function(path) { - this.reset(); - if (!this.resolved) - this.resolveAll(), - this.resolved = true, - this.result = null; // Require re-build - if (this.result === null) // (Re-)Build - this.result = this.ns.build(); - if (!path) - return this.result; - var part = typeof path === 'string' ? path.split(".") : path, - ptr = this.result; // Build namespace pointer (no hasChild etc.) - for (var i=0; i=} contents Initial contents - * @constructor - */ - var Map = function(field, contents) { - if (!field.map) - throw Error("field is not a map"); - - /** - * The field corresponding to this map. - * @type {!ProtoBuf.Reflect.Field} - */ - this.field = field; - - /** - * Element instance corresponding to key type. - * @type {!ProtoBuf.Reflect.Element} - */ - this.keyElem = new Reflect.Element(field.keyType, null, true, field.syntax); - - /** - * Element instance corresponding to value type. - * @type {!ProtoBuf.Reflect.Element} - */ - this.valueElem = new Reflect.Element(field.type, field.resolvedType, false, field.syntax); - - /** - * Internal map: stores mapping of (string form of key) -> (key, value) - * pair. - * - * We provide map semantics for arbitrary key types, but we build on top - * of an Object, which has only string keys. In order to avoid the need - * to convert a string key back to its native type in many situations, - * we store the native key value alongside the value. Thus, we only need - * a one-way mapping from a key type to its string form that guarantees - * uniqueness and equality (i.e., str(K1) === str(K2) if and only if K1 - * === K2). - * - * @type {!Object} - */ - this.map = {}; - - /** - * Returns the number of elements in the map. - */ - Object.defineProperty(this, "size", { - get: function() { return Object.keys(this.map).length; } - }); - - // Fill initial contents from a raw object. - if (contents) { - var keys = Object.keys(contents); - for (var i = 0; i < keys.length; i++) { - var key = this.keyElem.valueFromString(keys[i]); - var val = this.valueElem.verifyValue(contents[keys[i]]); - this.map[this.keyElem.valueToString(key)] = - { key: key, value: val }; - } - } - }; - - var MapPrototype = Map.prototype; - - /** - * Helper: return an iterator over an array. - * @param {!Array<*>} arr the array - * @returns {!Object} an iterator - * @inner - */ - function arrayIterator(arr) { - var idx = 0; - return { - next: function() { - if (idx < arr.length) - return { done: false, value: arr[idx++] }; - return { done: true }; - } - } - } - - /** - * Clears the map. - */ - MapPrototype.clear = function() { - this.map = {}; - }; - - /** - * Deletes a particular key from the map. - * @returns {boolean} Whether any entry with this key was deleted. - */ - MapPrototype["delete"] = function(key) { - var keyValue = this.keyElem.valueToString(this.keyElem.verifyValue(key)); - var hadKey = keyValue in this.map; - delete this.map[keyValue]; - return hadKey; - }; - - /** - * Returns an iterator over [key, value] pairs in the map. - * @returns {Object} The iterator - */ - MapPrototype.entries = function() { - var entries = []; - var strKeys = Object.keys(this.map); - for (var i = 0, entry; i < strKeys.length; i++) - entries.push([(entry=this.map[strKeys[i]]).key, entry.value]); - return arrayIterator(entries); - }; - - /** - * Returns an iterator over keys in the map. - * @returns {Object} The iterator - */ - MapPrototype.keys = function() { - var keys = []; - var strKeys = Object.keys(this.map); - for (var i = 0; i < strKeys.length; i++) - keys.push(this.map[strKeys[i]].key); - return arrayIterator(keys); - }; - - /** - * Returns an iterator over values in the map. - * @returns {!Object} The iterator - */ - MapPrototype.values = function() { - var values = []; - var strKeys = Object.keys(this.map); - for (var i = 0; i < strKeys.length; i++) - values.push(this.map[strKeys[i]].value); - return arrayIterator(values); - }; - - /** - * Iterates over entries in the map, calling a function on each. - * @param {function(this:*, *, *, *)} cb The callback to invoke with value, key, and map arguments. - * @param {Object=} thisArg The `this` value for the callback - */ - MapPrototype.forEach = function(cb, thisArg) { - var strKeys = Object.keys(this.map); - for (var i = 0, entry; i < strKeys.length; i++) - cb.call(thisArg, (entry=this.map[strKeys[i]]).value, entry.key, this); - }; - - /** - * Sets a key in the map to the given value. - * @param {*} key The key - * @param {*} value The value - * @returns {!ProtoBuf.Map} The map instance - */ - MapPrototype.set = function(key, value) { - var keyValue = this.keyElem.verifyValue(key); - var valValue = this.valueElem.verifyValue(value); - this.map[this.keyElem.valueToString(keyValue)] = - { key: keyValue, value: valValue }; - return this; - }; - - /** - * Gets the value corresponding to a key in the map. - * @param {*} key The key - * @returns {*|undefined} The value, or `undefined` if key not present - */ - MapPrototype.get = function(key) { - var keyValue = this.keyElem.valueToString(this.keyElem.verifyValue(key)); - if (!(keyValue in this.map)) - return undefined; - return this.map[keyValue].value; - }; - - /** - * Determines whether the given key is present in the map. - * @param {*} key The key - * @returns {boolean} `true` if the key is present - */ - MapPrototype.has = function(key) { - var keyValue = this.keyElem.valueToString(this.keyElem.verifyValue(key)); - return (keyValue in this.map); - }; - - return Map; - })(ProtoBuf, ProtoBuf.Reflect); - - - /** - * Loads a .proto string and returns the Builder. - * @param {string} proto .proto file contents - * @param {(ProtoBuf.Builder|string|{root: string, file: string})=} builder Builder to append to. Will create a new one if omitted. - * @param {(string|{root: string, file: string})=} filename The corresponding file name if known. Must be specified for imports. - * @return {ProtoBuf.Builder} Builder to create new messages - * @throws {Error} If the definition cannot be parsed or built - * @expose - */ - ProtoBuf.loadProto = function(proto, builder, filename) { - if (typeof builder === 'string' || (builder && typeof builder["file"] === 'string' && typeof builder["root"] === 'string')) - filename = builder, - builder = undefined; - return ProtoBuf.loadJson(ProtoBuf.DotProto.Parser.parse(proto), builder, filename); - }; - - /** - * Loads a .proto string and returns the Builder. This is an alias of {@link ProtoBuf.loadProto}. - * @function - * @param {string} proto .proto file contents - * @param {(ProtoBuf.Builder|string)=} builder Builder to append to. Will create a new one if omitted. - * @param {(string|{root: string, file: string})=} filename The corresponding file name if known. Must be specified for imports. - * @return {ProtoBuf.Builder} Builder to create new messages - * @throws {Error} If the definition cannot be parsed or built - * @expose - */ - ProtoBuf.protoFromString = ProtoBuf.loadProto; // Legacy - - /** - * Loads a .proto file and returns the Builder. - * @param {string|{root: string, file: string}} filename Path to proto file or an object specifying 'file' with - * an overridden 'root' path for all imported files. - * @param {function(?Error, !ProtoBuf.Builder=)=} callback Callback that will receive `null` as the first and - * the Builder as its second argument on success, otherwise the error as its first argument. If omitted, the - * file will be read synchronously and this function will return the Builder. - * @param {ProtoBuf.Builder=} builder Builder to append to. Will create a new one if omitted. - * @return {?ProtoBuf.Builder|undefined} The Builder if synchronous (no callback specified, will be NULL if the - * request has failed), else undefined - * @expose - */ - ProtoBuf.loadProtoFile = function(filename, callback, builder) { - if (callback && typeof callback === 'object') - builder = callback, - callback = null; - else if (!callback || typeof callback !== 'function') - callback = null; - if (callback) - return ProtoBuf.Util.fetch(typeof filename === 'string' ? filename : filename["root"]+"/"+filename["file"], function(contents) { - if (contents === null) { - callback(Error("Failed to fetch file")); - return; - } - try { - callback(null, ProtoBuf.loadProto(contents, builder, filename)); - } catch (e) { - callback(e); - } - }); - var contents = ProtoBuf.Util.fetch(typeof filename === 'object' ? filename["root"]+"/"+filename["file"] : filename); - return contents === null ? null : ProtoBuf.loadProto(contents, builder, filename); - }; - - /** - * Loads a .proto file and returns the Builder. This is an alias of {@link ProtoBuf.loadProtoFile}. - * @function - * @param {string|{root: string, file: string}} filename Path to proto file or an object specifying 'file' with - * an overridden 'root' path for all imported files. - * @param {function(?Error, !ProtoBuf.Builder=)=} callback Callback that will receive `null` as the first and - * the Builder as its second argument on success, otherwise the error as its first argument. If omitted, the - * file will be read synchronously and this function will return the Builder. - * @param {ProtoBuf.Builder=} builder Builder to append to. Will create a new one if omitted. - * @return {!ProtoBuf.Builder|undefined} The Builder if synchronous (no callback specified, will be NULL if the - * request has failed), else undefined - * @expose - */ - ProtoBuf.protoFromFile = ProtoBuf.loadProtoFile; // Legacy - - - /** - * Constructs a new empty Builder. - * @param {Object.=} options Builder options, defaults to global options set on ProtoBuf - * @return {!ProtoBuf.Builder} Builder - * @expose - */ - ProtoBuf.newBuilder = function(options) { - options = options || {}; - if (typeof options['convertFieldsToCamelCase'] === 'undefined') - options['convertFieldsToCamelCase'] = ProtoBuf.convertFieldsToCamelCase; - if (typeof options['populateAccessors'] === 'undefined') - options['populateAccessors'] = ProtoBuf.populateAccessors; - return new ProtoBuf.Builder(options); - }; - - /** - * Loads a .json definition and returns the Builder. - * @param {!*|string} json JSON definition - * @param {(ProtoBuf.Builder|string|{root: string, file: string})=} builder Builder to append to. Will create a new one if omitted. - * @param {(string|{root: string, file: string})=} filename The corresponding file name if known. Must be specified for imports. - * @return {ProtoBuf.Builder} Builder to create new messages - * @throws {Error} If the definition cannot be parsed or built - * @expose - */ - ProtoBuf.loadJson = function(json, builder, filename) { - if (typeof builder === 'string' || (builder && typeof builder["file"] === 'string' && typeof builder["root"] === 'string')) - filename = builder, - builder = null; - if (!builder || typeof builder !== 'object') - builder = ProtoBuf.newBuilder(); - if (typeof json === 'string') - json = JSON.parse(json); - builder["import"](json, filename); - builder.resolveAll(); - return builder; - }; - - /** - * Loads a .json file and returns the Builder. - * @param {string|!{root: string, file: string}} filename Path to json file or an object specifying 'file' with - * an overridden 'root' path for all imported files. - * @param {function(?Error, !ProtoBuf.Builder=)=} callback Callback that will receive `null` as the first and - * the Builder as its second argument on success, otherwise the error as its first argument. If omitted, the - * file will be read synchronously and this function will return the Builder. - * @param {ProtoBuf.Builder=} builder Builder to append to. Will create a new one if omitted. - * @return {?ProtoBuf.Builder|undefined} The Builder if synchronous (no callback specified, will be NULL if the - * request has failed), else undefined - * @expose - */ - ProtoBuf.loadJsonFile = function(filename, callback, builder) { - if (callback && typeof callback === 'object') - builder = callback, - callback = null; - else if (!callback || typeof callback !== 'function') - callback = null; - if (callback) - return ProtoBuf.Util.fetch(typeof filename === 'string' ? filename : filename["root"]+"/"+filename["file"], function(contents) { - if (contents === null) { - callback(Error("Failed to fetch file")); - return; - } - try { - callback(null, ProtoBuf.loadJson(JSON.parse(contents), builder, filename)); - } catch (e) { - callback(e); - } - }); - var contents = ProtoBuf.Util.fetch(typeof filename === 'object' ? filename["root"]+"/"+filename["file"] : filename); - return contents === null ? null : ProtoBuf.loadJson(JSON.parse(contents), builder, filename); - }; - - return ProtoBuf; -}); + + /** + * Language expressions. + * @type {!Object.} + * @expose + */ + ProtoBuf.Lang = { + + // Characters always ending a statement + DELIM: /[\s\{\}=;:\[\],'"\(\)<>]/g, + + // Field rules + RULE: /^(?:required|optional|repeated|map)$/, + + // Field types + TYPE: /^(?:double|float|int32|uint32|sint32|int64|uint64|sint64|fixed32|sfixed32|fixed64|sfixed64|bool|string|bytes)$/, + + // Names + NAME: /^[a-zA-Z_][a-zA-Z_0-9]*$/, + + // Type definitions + TYPEDEF: /^[a-zA-Z][a-zA-Z_0-9]*$/, + + // Type references + TYPEREF: /^(?:\.?[a-zA-Z_][a-zA-Z_0-9]*)+$/, + + // Fully qualified type references + FQTYPEREF: /^(?:\.[a-zA-Z][a-zA-Z_0-9]*)+$/, + + // All numbers + NUMBER: /^-?(?:[1-9][0-9]*|0|0[xX][0-9a-fA-F]+|0[0-7]+|([0-9]*(\.[0-9]*)?([Ee][+-]?[0-9]+)?)|inf|nan)$/, + + // Decimal numbers + NUMBER_DEC: /^(?:[1-9][0-9]*|0)$/, + + // Hexadecimal numbers + NUMBER_HEX: /^0[xX][0-9a-fA-F]+$/, + + // Octal numbers + NUMBER_OCT: /^0[0-7]+$/, + + // Floating point numbers + NUMBER_FLT: /^([0-9]*(\.[0-9]*)?([Ee][+-]?[0-9]+)?|inf|nan)$/, + + // Booleans + BOOL: /^(?:true|false)$/i, + + // Id numbers + ID: /^(?:[1-9][0-9]*|0|0[xX][0-9a-fA-F]+|0[0-7]+)$/, + + // Negative id numbers (enum values) + NEGID: /^\-?(?:[1-9][0-9]*|0|0[xX][0-9a-fA-F]+|0[0-7]+)$/, + + // Whitespaces + WHITESPACE: /\s/, + + // All strings + STRING: /(?:"([^"\\]*(?:\\.[^"\\]*)*)")|(?:'([^'\\]*(?:\\.[^'\\]*)*)')/g, + + // Double quoted strings + STRING_DQ: /(?:"([^"\\]*(?:\\.[^"\\]*)*)")/g, + + // Single quoted strings + STRING_SQ: /(?:'([^'\\]*(?:\\.[^'\\]*)*)')/g + }; + + /** + * @alias ProtoBuf.DotProto + * @expose + */ + ProtoBuf.DotProto = (function(ProtoBuf, Lang) { + "use strict"; + + /** + * Utilities to parse .proto files. + * @exports ProtoBuf.DotProto + * @namespace + */ + var DotProto = {}; + + /** + * Constructs a new Tokenizer. + * @exports ProtoBuf.DotProto.Tokenizer + * @class prototype tokenizer + * @param {string} proto Proto to tokenize + * @constructor + */ + var Tokenizer = function(proto) { + + /** + * Source to parse. + * @type {string} + * @expose + */ + this.source = proto+""; + + /** + * Current index. + * @type {number} + * @expose + */ + this.index = 0; + + /** + * Current line. + * @type {number} + * @expose + */ + this.line = 1; + + /** + * Token stack. + * @type {!Array.} + * @expose + */ + this.stack = []; + + /** + * Opening character of the current string read, if any. + * @type {?string} + * @private + */ + this._stringOpen = null; + }; + + /** + * @alias ProtoBuf.DotProto.Tokenizer.prototype + * @inner + */ + var TokenizerPrototype = Tokenizer.prototype; + + /** + * Reads a string beginning at the current index. + * @return {string} + * @private + */ + TokenizerPrototype._readString = function() { + var re = this._stringOpen === '"' + ? Lang.STRING_DQ + : Lang.STRING_SQ; + re.lastIndex = this.index - 1; // Include the open quote + var match = re.exec(this.source); + if (!match) + throw Error("unterminated string"); + this.index = re.lastIndex; + this.stack.push(this._stringOpen); + this._stringOpen = null; + return match[1]; + }; + + /** + * Gets the next token and advances by one. + * @return {?string} Token or `null` on EOF + * @expose + */ + TokenizerPrototype.next = function() { + if (this.stack.length > 0) + return this.stack.shift(); + if (this.index >= this.source.length) + return null; + if (this._stringOpen !== null) + return this._readString(); + + var repeat, + prev, + next; + do { + repeat = false; + + // Strip white spaces + while (Lang.WHITESPACE.test(next = this.source.charAt(this.index))) { + if (next === '\n') + ++this.line; + if (++this.index === this.source.length) + return null; + } + + // Strip comments + if (this.source.charAt(this.index) === '/') { + ++this.index; + if (this.source.charAt(this.index) === '/') { // Line + while (this.source.charAt(++this.index) !== '\n') + if (this.index == this.source.length) + return null; + ++this.index; + ++this.line; + repeat = true; + } else if ((next = this.source.charAt(this.index)) === '*') { /* Block */ + do { + if (next === '\n') + ++this.line; + if (++this.index === this.source.length) + return null; + prev = next; + next = this.source.charAt(this.index); + } while (prev !== '*' || next !== '/'); + ++this.index; + repeat = true; + } else + return '/'; + } + } while (repeat); + + if (this.index === this.source.length) + return null; + + // Read the next token + var end = this.index; + Lang.DELIM.lastIndex = 0; + var delim = Lang.DELIM.test(this.source.charAt(end++)); + if (!delim) + while(end < this.source.length && !Lang.DELIM.test(this.source.charAt(end))) + ++end; + var token = this.source.substring(this.index, this.index = end); + if (token === '"' || token === "'") + this._stringOpen = token; + return token; + }; + + /** + * Peeks for the next token. + * @return {?string} Token or `null` on EOF + * @expose + */ + TokenizerPrototype.peek = function() { + if (this.stack.length === 0) { + var token = this.next(); + if (token === null) + return null; + this.stack.push(token); + } + return this.stack[0]; + }; + + /** + * Skips a specific token and throws if it differs. + * @param {string} expected Expected token + * @throws {Error} If the actual token differs + */ + TokenizerPrototype.skip = function(expected) { + var actual = this.next(); + if (actual !== expected) + throw Error("illegal '"+actual+"', '"+expected+"' expected"); + }; + + /** + * Omits an optional token. + * @param {string} expected Expected optional token + * @returns {boolean} `true` if the token exists + */ + TokenizerPrototype.omit = function(expected) { + if (this.peek() === expected) { + this.next(); + return true; + } + return false; + }; + + /** + * Returns a string representation of this object. + * @return {string} String representation as of "Tokenizer(index/length)" + * @expose + */ + TokenizerPrototype.toString = function() { + return "Tokenizer ("+this.index+"/"+this.source.length+" at line "+this.line+")"; + }; + + /** + * @alias ProtoBuf.DotProto.Tokenizer + * @expose + */ + DotProto.Tokenizer = Tokenizer; + + /** + * Constructs a new Parser. + * @exports ProtoBuf.DotProto.Parser + * @class prototype parser + * @param {string} source Source + * @constructor + */ + var Parser = function(source) { + + /** + * Tokenizer. + * @type {!ProtoBuf.DotProto.Tokenizer} + * @expose + */ + this.tn = new Tokenizer(source); + + /** + * Whether parsing proto3 or not. + * @type {boolean} + */ + this.proto3 = false; + }; + + /** + * @alias ProtoBuf.DotProto.Parser.prototype + * @inner + */ + var ParserPrototype = Parser.prototype; + + /** + * Parses the source. + * @returns {!Object} + * @throws {Error} If the source cannot be parsed + * @expose + */ + ParserPrototype.parse = function() { + var topLevel = { + "name": "[ROOT]", // temporary + "package": null, + "messages": [], + "enums": [], + "imports": [], + "options": {}, + "services": [] + // "syntax": undefined + }; + var token, + head = true, + weak; + try { + while (token = this.tn.next()) { + switch (token) { + case 'package': + if (!head || topLevel["package"] !== null) + throw Error("unexpected 'package'"); + token = this.tn.next(); + if (!Lang.TYPEREF.test(token)) + throw Error("illegal package name: " + token); + this.tn.skip(";"); + topLevel["package"] = token; + break; + case 'import': + if (!head) + throw Error("unexpected 'import'"); + token = this.tn.peek(); + if (token === "public" || (weak = token === "weak")) // token ignored + this.tn.next(); + token = this._readString(); + this.tn.skip(";"); + if (!weak) // import ignored + topLevel["imports"].push(token); + break; + case 'syntax': + if (!head) + throw Error("unexpected 'syntax'"); + this.tn.skip("="); + if ((topLevel["syntax"] = this._readString()) === "proto3") + this.proto3 = true; + this.tn.skip(";"); + break; + case 'message': + this._parseMessage(topLevel, null); + head = false; + break; + case 'enum': + this._parseEnum(topLevel); + head = false; + break; + case 'option': + this._parseOption(topLevel); + break; + case 'service': + this._parseService(topLevel); + break; + case 'extend': + this._parseExtend(topLevel); + break; + default: + throw Error("unexpected '" + token + "'"); + } + } + } catch (e) { + e.message = "Parse error at line "+this.tn.line+": " + e.message; + throw e; + } + delete topLevel["name"]; + return topLevel; + }; + + /** + * Parses the specified source. + * @returns {!Object} + * @throws {Error} If the source cannot be parsed + * @expose + */ + Parser.parse = function(source) { + return new Parser(source).parse(); + }; + + // ----- Conversion ------ + + /** + * Converts a numerical string to an id. + * @param {string} value + * @param {boolean=} mayBeNegative + * @returns {number} + * @inner + */ + function mkId(value, mayBeNegative) { + var id = -1, + sign = 1; + if (value.charAt(0) == '-') { + sign = -1; + value = value.substring(1); + } + if (Lang.NUMBER_DEC.test(value)) + id = parseInt(value); + else if (Lang.NUMBER_HEX.test(value)) + id = parseInt(value.substring(2), 16); + else if (Lang.NUMBER_OCT.test(value)) + id = parseInt(value.substring(1), 8); + else + throw Error("illegal id value: " + (sign < 0 ? '-' : '') + value); + id = (sign*id)|0; // Force to 32bit + if (!mayBeNegative && id < 0) + throw Error("illegal id value: " + (sign < 0 ? '-' : '') + value); + return id; + } + + /** + * Converts a numerical string to a number. + * @param {string} val + * @returns {number} + * @inner + */ + function mkNumber(val) { + var sign = 1; + if (val.charAt(0) == '-') { + sign = -1; + val = val.substring(1); + } + if (Lang.NUMBER_DEC.test(val)) + return sign * parseInt(val, 10); + else if (Lang.NUMBER_HEX.test(val)) + return sign * parseInt(val.substring(2), 16); + else if (Lang.NUMBER_OCT.test(val)) + return sign * parseInt(val.substring(1), 8); + else if (val === 'inf') + return sign * Infinity; + else if (val === 'nan') + return NaN; + else if (Lang.NUMBER_FLT.test(val)) + return sign * parseFloat(val); + throw Error("illegal number value: " + (sign < 0 ? '-' : '') + val); + } + + // ----- Reading ------ + + /** + * Reads a string. + * @returns {string} + * @private + */ + ParserPrototype._readString = function() { + var value = "", + token, + delim; + do { + delim = this.tn.next(); + if (delim !== "'" && delim !== '"') + throw Error("illegal string delimiter: "+delim); + value += this.tn.next(); + this.tn.skip(delim); + token = this.tn.peek(); + } while (token === '"' || token === '"'); // multi line? + return value; + }; + + /** + * Reads a value. + * @param {boolean=} mayBeTypeRef + * @returns {number|boolean|string} + * @private + */ + ParserPrototype._readValue = function(mayBeTypeRef) { + var token = this.tn.peek(), + value; + if (token === '"' || token === "'") + return this._readString(); + this.tn.next(); + if (Lang.NUMBER.test(token)) + return mkNumber(token); + if (Lang.BOOL.test(token)) + return (token.toLowerCase() === 'true'); + if (mayBeTypeRef && Lang.TYPEREF.test(token)) + return token; + throw Error("illegal value: "+token); + + }; + + // ----- Parsing constructs ----- + + /** + * Parses a namespace option. + * @param {!Object} parent Parent definition + * @param {boolean=} isList + * @private + */ + ParserPrototype._parseOption = function(parent, isList) { + var token = this.tn.next(), + custom = false; + if (token === '(') { + custom = true; + token = this.tn.next(); + } + if (!Lang.TYPEREF.test(token)) + // we can allow options of the form google.protobuf.* since they will just get ignored anyways + // if (!/google\.protobuf\./.test(token)) // FIXME: Why should that not be a valid typeref? + throw Error("illegal option name: "+token); + var name = token; + if (custom) { // (my_method_option).foo, (my_method_option), some_method_option, (foo.my_option).bar + this.tn.skip(')'); + name = '('+name+')'; + token = this.tn.peek(); + if (Lang.FQTYPEREF.test(token)) { + name += token; + this.tn.next(); + } + } + this.tn.skip('='); + this._parseOptionValue(parent, name); + if (!isList) + this.tn.skip(";"); + }; + + /** + * Sets an option on the specified options object. + * @param {!Object.} options + * @param {string} name + * @param {string|number|boolean} value + * @inner + */ + function setOption(options, name, value) { + if (typeof options[name] === 'undefined') + options[name] = value; + else { + if (!Array.isArray(options[name])) + options[name] = [ options[name] ]; + options[name].push(value); + } + } + + /** + * Parses an option value. + * @param {!Object} parent + * @param {string} name + * @private + */ + ParserPrototype._parseOptionValue = function(parent, name) { + var token = this.tn.peek(); + if (token !== '{') { // Plain value + setOption(parent["options"], name, this._readValue(true)); + } else { // Aggregate options + this.tn.skip("{"); + while ((token = this.tn.next()) !== '}') { + if (!Lang.NAME.test(token)) + throw Error("illegal option name: " + name + "." + token); + if (this.tn.omit(":")) + setOption(parent["options"], name + "." + token, this._readValue(true)); + else + this._parseOptionValue(parent, name + "." + token); + } + } + }; + + /** + * Parses a service definition. + * @param {!Object} parent Parent definition + * @private + */ + ParserPrototype._parseService = function(parent) { + var token = this.tn.next(); + if (!Lang.NAME.test(token)) + throw Error("illegal service name at line "+this.tn.line+": "+token); + var name = token; + var svc = { + "name": name, + "rpc": {}, + "options": {} + }; + this.tn.skip("{"); + while ((token = this.tn.next()) !== '}') { + if (token === "option") + this._parseOption(svc); + else if (token === 'rpc') + this._parseServiceRPC(svc); + else + throw Error("illegal service token: "+token); + } + this.tn.omit(";"); + parent["services"].push(svc); + }; + + /** + * Parses a RPC service definition of the form ['rpc', name, (request), 'returns', (response)]. + * @param {!Object} svc Service definition + * @private + */ + ParserPrototype._parseServiceRPC = function(svc) { + var type = "rpc", + token = this.tn.next(); + if (!Lang.NAME.test(token)) + throw Error("illegal rpc service method name: "+token); + var name = token; + var method = { + "request": null, + "response": null, + "request_stream": false, + "response_stream": false, + "options": {} + }; + this.tn.skip("("); + token = this.tn.next(); + if (token.toLowerCase() === "stream") { + method["request_stream"] = true; + token = this.tn.next(); + } + if (!Lang.TYPEREF.test(token)) + throw Error("illegal rpc service request type: "+token); + method["request"] = token; + this.tn.skip(")"); + token = this.tn.next(); + if (token.toLowerCase() !== "returns") + throw Error("illegal rpc service request type delimiter: "+token); + this.tn.skip("("); + token = this.tn.next(); + if (token.toLowerCase() === "stream") { + method["response_stream"] = true; + token = this.tn.next(); + } + method["response"] = token; + this.tn.skip(")"); + token = this.tn.peek(); + if (token === '{') { + this.tn.next(); + while ((token = this.tn.next()) !== '}') { + if (token === 'option') + this._parseOption(method); + else + throw Error("illegal rpc service token: " + token); + } + this.tn.omit(";"); + } else + this.tn.skip(";"); + if (typeof svc[type] === 'undefined') + svc[type] = {}; + svc[type][name] = method; + }; + + /** + * Parses a message definition. + * @param {!Object} parent Parent definition + * @param {!Object=} fld Field definition if this is a group + * @returns {!Object} + * @private + */ + ParserPrototype._parseMessage = function(parent, fld) { + var isGroup = !!fld, + token = this.tn.next(); + var msg = { + "name": "", + "fields": [], + "enums": [], + "messages": [], + "options": {}, + "services": [], + "oneofs": {} + // "extensions": undefined + }; + if (!Lang.NAME.test(token)) + throw Error("illegal "+(isGroup ? "group" : "message")+" name: "+token); + msg["name"] = token; + if (isGroup) { + this.tn.skip("="); + fld["id"] = mkId(this.tn.next()); + msg["isGroup"] = true; + } + token = this.tn.peek(); + if (token === '[' && fld) + this._parseFieldOptions(fld); + this.tn.skip("{"); + while ((token = this.tn.next()) !== '}') { + if (Lang.RULE.test(token)) + this._parseMessageField(msg, token); + else if (token === "oneof") + this._parseMessageOneOf(msg); + else if (token === "enum") + this._parseEnum(msg); + else if (token === "message") + this._parseMessage(msg); + else if (token === "option") + this._parseOption(msg); + else if (token === "service") + this._parseService(msg); + else if (token === "extensions") + msg["extensions"] = this._parseExtensionRanges(); + else if (token === "reserved") + this._parseIgnored(); // TODO + else if (token === "extend") + this._parseExtend(msg); + else if (Lang.TYPEREF.test(token)) { + if (!this.proto3) + throw Error("illegal field rule: "+token); + this._parseMessageField(msg, "optional", token); + } else + throw Error("illegal message token: "+token); + } + this.tn.omit(";"); + parent["messages"].push(msg); + return msg; + }; + + /** + * Parses an ignored statement. + * @private + */ + ParserPrototype._parseIgnored = function() { + while (this.tn.peek() !== ';') + this.tn.next(); + this.tn.skip(";"); + }; + + /** + * Parses a message field. + * @param {!Object} msg Message definition + * @param {string} rule Field rule + * @param {string=} type Field type if already known (never known for maps) + * @returns {!Object} Field descriptor + * @private + */ + ParserPrototype._parseMessageField = function(msg, rule, type) { + if (!Lang.RULE.test(rule)) + throw Error("illegal message field rule: "+rule); + var fld = { + "rule": rule, + "type": "", + "name": "", + "options": {}, + "id": 0 + }; + var token; + if (rule === "map") { + + if (type) + throw Error("illegal type: " + type); + this.tn.skip('<'); + token = this.tn.next(); + if (!Lang.TYPE.test(token) && !Lang.TYPEREF.test(token)) + throw Error("illegal message field type: " + token); + fld["keytype"] = token; + this.tn.skip(','); + token = this.tn.next(); + if (!Lang.TYPE.test(token) && !Lang.TYPEREF.test(token)) + throw Error("illegal message field: " + token); + fld["type"] = token; + this.tn.skip('>'); + token = this.tn.next(); + if (!Lang.NAME.test(token)) + throw Error("illegal message field name: " + token); + fld["name"] = token; + this.tn.skip("="); + fld["id"] = mkId(this.tn.next()); + token = this.tn.peek(); + if (token === '[') + this._parseFieldOptions(fld); + this.tn.skip(";"); + + } else { + + type = typeof type !== 'undefined' ? type : this.tn.next(); + + if (type === "group") { + + // "A [legacy] group simply combines a nested message type and a field into a single declaration. In your + // code, you can treat this message just as if it had a Result type field called result (the latter name is + // converted to lower-case so that it does not conflict with the former)." + var grp = this._parseMessage(msg, fld); + if (!/^[A-Z]/.test(grp["name"])) + throw Error('illegal group name: '+grp["name"]); + fld["type"] = grp["name"]; + fld["name"] = grp["name"].toLowerCase(); + this.tn.omit(";"); + + } else { + + if (!Lang.TYPE.test(type) && !Lang.TYPEREF.test(type)) + throw Error("illegal message field type: " + type); + fld["type"] = type; + token = this.tn.next(); + if (!Lang.NAME.test(token)) + throw Error("illegal message field name: " + token); + fld["name"] = token; + this.tn.skip("="); + fld["id"] = mkId(this.tn.next()); + token = this.tn.peek(); + if (token === "[") + this._parseFieldOptions(fld); + this.tn.skip(";"); + + } + } + msg["fields"].push(fld); + return fld; + }; + + /** + * Parses a message oneof. + * @param {!Object} msg Message definition + * @private + */ + ParserPrototype._parseMessageOneOf = function(msg) { + var token = this.tn.next(); + if (!Lang.NAME.test(token)) + throw Error("illegal oneof name: "+token); + var name = token, + fld; + var fields = []; + this.tn.skip("{"); + while ((token = this.tn.next()) !== "}") { + fld = this._parseMessageField(msg, "optional", token); + fld["oneof"] = name; + fields.push(fld["id"]); + } + this.tn.omit(";"); + msg["oneofs"][name] = fields; + }; + + /** + * Parses a set of field option definitions. + * @param {!Object} fld Field definition + * @private + */ + ParserPrototype._parseFieldOptions = function(fld) { + this.tn.skip("["); + var token, + first = true; + while ((token = this.tn.peek()) !== ']') { + if (!first) + this.tn.skip(","); + this._parseOption(fld, true); + first = false; + } + this.tn.next(); + }; + + /** + * Parses an enum. + * @param {!Object} msg Message definition + * @private + */ + ParserPrototype._parseEnum = function(msg) { + var enm = { + "name": "", + "values": [], + "options": {} + }; + var token = this.tn.next(); + if (!Lang.NAME.test(token)) + throw Error("illegal name: "+token); + enm["name"] = token; + this.tn.skip("{"); + while ((token = this.tn.next()) !== '}') { + if (token === "option") + this._parseOption(enm); + else { + if (!Lang.NAME.test(token)) + throw Error("illegal name: "+token); + this.tn.skip("="); + var val = { + "name": token, + "id": mkId(this.tn.next(), true) + }; + token = this.tn.peek(); + if (token === "[") + this._parseFieldOptions({ "options": {} }); + this.tn.skip(";"); + enm["values"].push(val); + } + } + this.tn.omit(";"); + msg["enums"].push(enm); + }; + + /** + * Parses extension / reserved ranges. + * @returns {!Array.>} + * @private + */ + ParserPrototype._parseExtensionRanges = function() { + var ranges = []; + var token, + range, + value; + do { + range = []; + while (true) { + token = this.tn.next(); + switch (token) { + case "min": + value = ProtoBuf.ID_MIN; + break; + case "max": + value = ProtoBuf.ID_MAX; + break; + default: + value = mkNumber(token); + break; + } + range.push(value); + if (range.length === 2) + break; + if (this.tn.peek() !== "to") { + range.push(value); + break; + } + this.tn.next(); + } + ranges.push(range); + } while (this.tn.omit(",")); + this.tn.skip(";"); + return ranges; + }; + + /** + * Parses an extend block. + * @param {!Object} parent Parent object + * @private + */ + ParserPrototype._parseExtend = function(parent) { + var token = this.tn.next(); + if (!Lang.TYPEREF.test(token)) + throw Error("illegal extend reference: "+token); + var ext = { + "ref": token, + "fields": [] + }; + this.tn.skip("{"); + while ((token = this.tn.next()) !== '}') { + if (Lang.RULE.test(token)) + this._parseMessageField(ext, token); + else if (Lang.TYPEREF.test(token)) { + if (!this.proto3) + throw Error("illegal field rule: "+token); + this._parseMessageField(ext, "optional", token); + } else + throw Error("illegal extend token: "+token); + } + this.tn.omit(";"); + parent["messages"].push(ext); + return ext; + }; + + // ----- General ----- + + /** + * Returns a string representation of this parser. + * @returns {string} + */ + ParserPrototype.toString = function() { + return "Parser at line "+this.tn.line; + }; + + /** + * @alias ProtoBuf.DotProto.Parser + * @expose + */ + DotProto.Parser = Parser; + + return DotProto; + + })(ProtoBuf, ProtoBuf.Lang); + + /** + * @alias ProtoBuf.Reflect + * @expose + */ + ProtoBuf.Reflect = (function(ProtoBuf) { + "use strict"; + + /** + * Reflection types. + * @exports ProtoBuf.Reflect + * @namespace + */ + var Reflect = {}; + + /** + * Constructs a Reflect base class. + * @exports ProtoBuf.Reflect.T + * @constructor + * @abstract + * @param {!ProtoBuf.Builder} builder Builder reference + * @param {?ProtoBuf.Reflect.T} parent Parent object + * @param {string} name Object name + */ + var T = function(builder, parent, name) { + + /** + * Builder reference. + * @type {!ProtoBuf.Builder} + * @expose + */ + this.builder = builder; + + /** + * Parent object. + * @type {?ProtoBuf.Reflect.T} + * @expose + */ + this.parent = parent; + + /** + * Object name in namespace. + * @type {string} + * @expose + */ + this.name = name; + + /** + * Fully qualified class name + * @type {string} + * @expose + */ + this.className; + }; + + /** + * @alias ProtoBuf.Reflect.T.prototype + * @inner + */ + var TPrototype = T.prototype; + + /** + * Returns the fully qualified name of this object. + * @returns {string} Fully qualified name as of ".PATH.TO.THIS" + * @expose + */ + TPrototype.fqn = function() { + var name = this.name, + ptr = this; + do { + ptr = ptr.parent; + if (ptr == null) + break; + name = ptr.name+"."+name; + } while (true); + return name; + }; + + /** + * Returns a string representation of this Reflect object (its fully qualified name). + * @param {boolean=} includeClass Set to true to include the class name. Defaults to false. + * @return String representation + * @expose + */ + TPrototype.toString = function(includeClass) { + return (includeClass ? this.className + " " : "") + this.fqn(); + }; + + /** + * Builds this type. + * @throws {Error} If this type cannot be built directly + * @expose + */ + TPrototype.build = function() { + throw Error(this.toString(true)+" cannot be built directly"); + }; + + /** + * @alias ProtoBuf.Reflect.T + * @expose + */ + Reflect.T = T; + + /** + * Constructs a new Namespace. + * @exports ProtoBuf.Reflect.Namespace + * @param {!ProtoBuf.Builder} builder Builder reference + * @param {?ProtoBuf.Reflect.Namespace} parent Namespace parent + * @param {string} name Namespace name + * @param {Object.=} options Namespace options + * @param {string?} syntax The syntax level of this definition (e.g., proto3) + * @constructor + * @extends ProtoBuf.Reflect.T + */ + var Namespace = function(builder, parent, name, options, syntax) { + T.call(this, builder, parent, name); + + /** + * @override + */ + this.className = "Namespace"; + + /** + * Children inside the namespace. + * @type {!Array.} + */ + this.children = []; + + /** + * Options. + * @type {!Object.} + */ + this.options = options || {}; + + /** + * Syntax level (e.g., proto2 or proto3). + * @type {!string} + */ + this.syntax = syntax || "proto2"; + }; + + /** + * @alias ProtoBuf.Reflect.Namespace.prototype + * @inner + */ + var NamespacePrototype = Namespace.prototype = Object.create(T.prototype); + + /** + * Returns an array of the namespace's children. + * @param {ProtoBuf.Reflect.T=} type Filter type (returns instances of this type only). Defaults to null (all children). + * @return {Array.} + * @expose + */ + NamespacePrototype.getChildren = function(type) { + type = type || null; + if (type == null) + return this.children.slice(); + var children = []; + for (var i=0, k=this.children.length; i} qn Qualified name to resolve + * @param {boolean=} excludeNonNamespace Excludes non-namespace types, defaults to `false` + * @return {?ProtoBuf.Reflect.Namespace} The resolved type or null if not found + * @expose + */ + NamespacePrototype.resolve = function(qn, excludeNonNamespace) { + var part = typeof qn === 'string' ? qn.split(".") : qn, + ptr = this, + i = 0; + if (part[i] === "") { // Fully qualified name, e.g. ".My.Message' + while (ptr.parent !== null) + ptr = ptr.parent; + i++; + } + var child; + do { + do { + if (!(ptr instanceof Reflect.Namespace)) { + ptr = null; + break; + } + child = ptr.getChild(part[i]); + if (!child || !(child instanceof Reflect.T) || (excludeNonNamespace && !(child instanceof Reflect.Namespace))) { + ptr = null; + break; + } + ptr = child; i++; + } while (i < part.length); + if (ptr != null) + break; // Found + // Else search the parent + if (this.parent !== null) + return this.parent.resolve(qn, excludeNonNamespace); + } while (ptr != null); + return ptr; + }; + + /** + * Determines the shortest qualified name of the specified type, if any, relative to this namespace. + * @param {!ProtoBuf.Reflect.T} t Reflection type + * @returns {string} The shortest qualified name or, if there is none, the fqn + * @expose + */ + NamespacePrototype.qn = function(t) { + var part = [], ptr = t; + do { + part.unshift(ptr.name); + ptr = ptr.parent; + } while (ptr !== null); + for (var len=1; len <= part.length; len++) { + var qn = part.slice(part.length-len); + if (t === this.resolve(qn, t instanceof Reflect.Namespace)) + return qn.join("."); + } + return t.fqn(); + }; + + /** + * Builds the namespace and returns the runtime counterpart. + * @return {Object.} Runtime namespace + * @expose + */ + NamespacePrototype.build = function() { + /** @dict */ + var ns = {}; + var children = this.children; + for (var i=0, k=children.length, child; i} + */ + NamespacePrototype.buildOpt = function() { + var opt = {}, + keys = Object.keys(this.options); + for (var i=0, k=keys.length; i}null} Option value or NULL if there is no such option + */ + NamespacePrototype.getOption = function(name) { + if (typeof name === 'undefined') + return this.options; + return typeof this.options[name] !== 'undefined' ? this.options[name] : null; + }; + + /** + * @alias ProtoBuf.Reflect.Namespace + * @expose + */ + Reflect.Namespace = Namespace; + + /** + * Constructs a new Element implementation that checks and converts values for a + * particular field type, as appropriate. + * + * An Element represents a single value: either the value of a singular field, + * or a value contained in one entry of a repeated field or map field. This + * class does not implement these higher-level concepts; it only encapsulates + * the low-level typechecking and conversion. + * + * @exports ProtoBuf.Reflect.Element + * @param {{name: string, wireType: number}} type Resolved data type + * @param {ProtoBuf.Reflect.T|null} resolvedType Resolved type, if relevant + * (e.g. submessage field). + * @param {boolean} isMapKey Is this element a Map key? The value will be + * converted to string form if so. + * @param {string} syntax Syntax level of defining message type, e.g., + * proto2 or proto3. + * @constructor + */ + var Element = function(type, resolvedType, isMapKey, syntax) { + + /** + * Element type, as a string (e.g., int32). + * @type {{name: string, wireType: number}} + */ + this.type = type; + + /** + * Element type reference to submessage or enum definition, if needed. + * @type {ProtoBuf.Reflect.T|null} + */ + this.resolvedType = resolvedType; + + /** + * Element is a map key. + * @type {boolean} + */ + this.isMapKey = isMapKey; + + /** + * Syntax level of defining message type, e.g., proto2 or proto3. + * @type {string} + */ + this.syntax = syntax; + + if (isMapKey && ProtoBuf.MAP_KEY_TYPES.indexOf(type) < 0) + throw Error("Invalid map key type: " + type.name); + }; + + var ElementPrototype = Element.prototype; + + /** + * Obtains a (new) default value for the specified type. + * @param type {string|{name: string, wireType: number}} Field type + * @returns {*} Default value + * @inner + */ + function mkDefault(type) { + if (typeof type === 'string') + type = ProtoBuf.TYPES[type]; + if (typeof type.defaultValue === 'undefined') + throw Error("default value for type "+type.name+" is not supported"); + if (type == ProtoBuf.TYPES["bytes"]) + return new ByteBuffer(0); + return type.defaultValue; + } + + /** + * Returns the default value for this field in proto3. + * @function + * @param type {string|{name: string, wireType: number}} the field type + * @returns {*} Default value + */ + Element.defaultFieldValue = mkDefault; + + /** + * Makes a Long from a value. + * @param {{low: number, high: number, unsigned: boolean}|string|number} value Value + * @param {boolean=} unsigned Whether unsigned or not, defaults to reuse it from Long-like objects or to signed for + * strings and numbers + * @returns {!Long} + * @throws {Error} If the value cannot be converted to a Long + * @inner + */ + function mkLong(value, unsigned) { + if (value && typeof value.low === 'number' && typeof value.high === 'number' && typeof value.unsigned === 'boolean' + && value.low === value.low && value.high === value.high) + return new ProtoBuf.Long(value.low, value.high, typeof unsigned === 'undefined' ? value.unsigned : unsigned); + if (typeof value === 'string') + return ProtoBuf.Long.fromString(value, unsigned || false, 10); + if (typeof value === 'number') + return ProtoBuf.Long.fromNumber(value, unsigned || false); + throw Error("not convertible to Long"); + } + + /** + * Checks if the given value can be set for an element of this type (singular + * field or one element of a repeated field or map). + * @param {*} value Value to check + * @return {*} Verified, maybe adjusted, value + * @throws {Error} If the value cannot be verified for this element slot + * @expose + */ + ElementPrototype.verifyValue = function(value) { + var self = this; + function fail(val, msg) { + throw Error("Illegal value for "+self.toString(true)+" of type "+self.type.name+": "+val+" ("+msg+")"); + } + switch (this.type) { + // Signed 32bit + case ProtoBuf.TYPES["int32"]: + case ProtoBuf.TYPES["sint32"]: + case ProtoBuf.TYPES["sfixed32"]: + // Account for !NaN: value === value + if (typeof value !== 'number' || (value === value && value % 1 !== 0)) + fail(typeof value, "not an integer"); + return value > 4294967295 ? value | 0 : value; + + // Unsigned 32bit + case ProtoBuf.TYPES["uint32"]: + case ProtoBuf.TYPES["fixed32"]: + if (typeof value !== 'number' || (value === value && value % 1 !== 0)) + fail(typeof value, "not an integer"); + return value < 0 ? value >>> 0 : value; + + // Signed 64bit + case ProtoBuf.TYPES["int64"]: + case ProtoBuf.TYPES["sint64"]: + case ProtoBuf.TYPES["sfixed64"]: { + if (ProtoBuf.Long) + try { + return mkLong(value, false); + } catch (e) { + fail(typeof value, e.message); + } + else + fail(typeof value, "requires Long.js"); + } + + // Unsigned 64bit + case ProtoBuf.TYPES["uint64"]: + case ProtoBuf.TYPES["fixed64"]: { + if (ProtoBuf.Long) + try { + return mkLong(value, true); + } catch (e) { + fail(typeof value, e.message); + } + else + fail(typeof value, "requires Long.js"); + } + + // Bool + case ProtoBuf.TYPES["bool"]: + if (typeof value !== 'boolean') + fail(typeof value, "not a boolean"); + return value; + + // Float + case ProtoBuf.TYPES["float"]: + case ProtoBuf.TYPES["double"]: + if (typeof value !== 'number') + fail(typeof value, "not a number"); + return value; + + // Length-delimited string + case ProtoBuf.TYPES["string"]: + if (typeof value !== 'string' && !(value && value instanceof String)) + fail(typeof value, "not a string"); + return ""+value; // Convert String object to string + + // Length-delimited bytes + case ProtoBuf.TYPES["bytes"]: + if (ByteBuffer.isByteBuffer(value)) + return value; + return ByteBuffer.wrap(value, "base64"); + + // Constant enum value + case ProtoBuf.TYPES["enum"]: { + var values = this.resolvedType.getChildren(ProtoBuf.Reflect.Enum.Value); + for (i=0; i 4294967295 || value < 0) + fail(typeof value, "not in range for uint32") + return value; + } else { + // proto2 requires enum values to be valid. + fail(value, "not a valid enum value"); + } + } + // Embedded message + case ProtoBuf.TYPES["group"]: + case ProtoBuf.TYPES["message"]: { + if (!value || typeof value !== 'object') + fail(typeof value, "object expected"); + if (value instanceof this.resolvedType.clazz) + return value; + if (value instanceof ProtoBuf.Builder.Message) { + // Mismatched type: Convert to object (see: https://github.com/dcodeIO/ProtoBuf.js/issues/180) + var obj = {}; + for (var i in value) + if (value.hasOwnProperty(i)) + obj[i] = value[i]; + value = obj; + } + // Else let's try to construct one from a key-value object + return new (this.resolvedType.clazz)(value); // May throw for a hundred of reasons + } + } + + // We should never end here + throw Error("[INTERNAL] Illegal value for "+this.toString(true)+": "+value+" (undefined type "+this.type+")"); + }; + + /** + * Calculates the byte length of an element on the wire. + * @param {number} id Field number + * @param {*} value Field value + * @returns {number} Byte length + * @throws {Error} If the value cannot be calculated + * @expose + */ + ElementPrototype.calculateLength = function(id, value) { + if (value === null) return 0; // Nothing to encode + // Tag has already been written + var n; + switch (this.type) { + case ProtoBuf.TYPES["int32"]: + return value < 0 ? ByteBuffer.calculateVarint64(value) : ByteBuffer.calculateVarint32(value); + case ProtoBuf.TYPES["uint32"]: + return ByteBuffer.calculateVarint32(value); + case ProtoBuf.TYPES["sint32"]: + return ByteBuffer.calculateVarint32(ByteBuffer.zigZagEncode32(value)); + case ProtoBuf.TYPES["fixed32"]: + case ProtoBuf.TYPES["sfixed32"]: + case ProtoBuf.TYPES["float"]: + return 4; + case ProtoBuf.TYPES["int64"]: + case ProtoBuf.TYPES["uint64"]: + return ByteBuffer.calculateVarint64(value); + case ProtoBuf.TYPES["sint64"]: + return ByteBuffer.calculateVarint64(ByteBuffer.zigZagEncode64(value)); + case ProtoBuf.TYPES["fixed64"]: + case ProtoBuf.TYPES["sfixed64"]: + return 8; + case ProtoBuf.TYPES["bool"]: + return 1; + case ProtoBuf.TYPES["enum"]: + return ByteBuffer.calculateVarint32(value); + case ProtoBuf.TYPES["double"]: + return 8; + case ProtoBuf.TYPES["string"]: + n = ByteBuffer.calculateUTF8Bytes(value); + return ByteBuffer.calculateVarint32(n) + n; + case ProtoBuf.TYPES["bytes"]: + if (value.remaining() < 0) + throw Error("Illegal value for "+this.toString(true)+": "+value.remaining()+" bytes remaining"); + return ByteBuffer.calculateVarint32(value.remaining()) + value.remaining(); + case ProtoBuf.TYPES["message"]: + n = this.resolvedType.calculate(value); + return ByteBuffer.calculateVarint32(n) + n; + case ProtoBuf.TYPES["group"]: + n = this.resolvedType.calculate(value); + return n + ByteBuffer.calculateVarint32((id << 3) | ProtoBuf.WIRE_TYPES.ENDGROUP); + } + // We should never end here + throw Error("[INTERNAL] Illegal value to encode in "+this.toString(true)+": "+value+" (unknown type)"); + }; + + /** + * Encodes a value to the specified buffer. Does not encode the key. + * @param {number} id Field number + * @param {*} value Field value + * @param {ByteBuffer} buffer ByteBuffer to encode to + * @return {ByteBuffer} The ByteBuffer for chaining + * @throws {Error} If the value cannot be encoded + * @expose + */ + ElementPrototype.encodeValue = function(id, value, buffer) { + if (value === null) return buffer; // Nothing to encode + // Tag has already been written + + switch (this.type) { + // 32bit signed varint + case ProtoBuf.TYPES["int32"]: + // "If you use int32 or int64 as the type for a negative number, the resulting varint is always ten bytes + // long – it is, effectively, treated like a very large unsigned integer." (see #122) + if (value < 0) + buffer.writeVarint64(value); + else + buffer.writeVarint32(value); + break; + + // 32bit unsigned varint + case ProtoBuf.TYPES["uint32"]: + buffer.writeVarint32(value); + break; + + // 32bit varint zig-zag + case ProtoBuf.TYPES["sint32"]: + buffer.writeVarint32ZigZag(value); + break; + + // Fixed unsigned 32bit + case ProtoBuf.TYPES["fixed32"]: + buffer.writeUint32(value); + break; + + // Fixed signed 32bit + case ProtoBuf.TYPES["sfixed32"]: + buffer.writeInt32(value); + break; + + // 64bit varint as-is + case ProtoBuf.TYPES["int64"]: + case ProtoBuf.TYPES["uint64"]: + buffer.writeVarint64(value); // throws + break; + + // 64bit varint zig-zag + case ProtoBuf.TYPES["sint64"]: + buffer.writeVarint64ZigZag(value); // throws + break; + + // Fixed unsigned 64bit + case ProtoBuf.TYPES["fixed64"]: + buffer.writeUint64(value); // throws + break; + + // Fixed signed 64bit + case ProtoBuf.TYPES["sfixed64"]: + buffer.writeInt64(value); // throws + break; + + // Bool + case ProtoBuf.TYPES["bool"]: + if (typeof value === 'string') + buffer.writeVarint32(value.toLowerCase() === 'false' ? 0 : !!value); + else + buffer.writeVarint32(value ? 1 : 0); + break; + + // Constant enum value + case ProtoBuf.TYPES["enum"]: + buffer.writeVarint32(value); + break; + + // 32bit float + case ProtoBuf.TYPES["float"]: + buffer.writeFloat32(value); + break; + + // 64bit float + case ProtoBuf.TYPES["double"]: + buffer.writeFloat64(value); + break; + + // Length-delimited string + case ProtoBuf.TYPES["string"]: + buffer.writeVString(value); + break; + + // Length-delimited bytes + case ProtoBuf.TYPES["bytes"]: + if (value.remaining() < 0) + throw Error("Illegal value for "+this.toString(true)+": "+value.remaining()+" bytes remaining"); + var prevOffset = value.offset; + buffer.writeVarint32(value.remaining()); + buffer.append(value); + value.offset = prevOffset; + break; + + // Embedded message + case ProtoBuf.TYPES["message"]: + var bb = new ByteBuffer().LE(); + this.resolvedType.encode(value, bb); + buffer.writeVarint32(bb.offset); + buffer.append(bb.flip()); + break; + + // Legacy group + case ProtoBuf.TYPES["group"]: + this.resolvedType.encode(value, buffer); + buffer.writeVarint32((id << 3) | ProtoBuf.WIRE_TYPES.ENDGROUP); + break; + + default: + // We should never end here + throw Error("[INTERNAL] Illegal value to encode in "+this.toString(true)+": "+value+" (unknown type)"); + } + return buffer; + }; + + /** + * Decode one element value from the specified buffer. + * @param {ByteBuffer} buffer ByteBuffer to decode from + * @param {number} wireType The field wire type + * @param {number} id The field number + * @return {*} Decoded value + * @throws {Error} If the field cannot be decoded + * @expose + */ + ElementPrototype.decode = function(buffer, wireType, id) { + if (wireType != this.type.wireType) + throw Error("Unexpected wire type for element"); + + var value, nBytes; + switch (this.type) { + // 32bit signed varint + case ProtoBuf.TYPES["int32"]: + return buffer.readVarint32() | 0; + + // 32bit unsigned varint + case ProtoBuf.TYPES["uint32"]: + return buffer.readVarint32() >>> 0; + + // 32bit signed varint zig-zag + case ProtoBuf.TYPES["sint32"]: + return buffer.readVarint32ZigZag() | 0; + + // Fixed 32bit unsigned + case ProtoBuf.TYPES["fixed32"]: + return buffer.readUint32() >>> 0; + + case ProtoBuf.TYPES["sfixed32"]: + return buffer.readInt32() | 0; + + // 64bit signed varint + case ProtoBuf.TYPES["int64"]: + return buffer.readVarint64(); + + // 64bit unsigned varint + case ProtoBuf.TYPES["uint64"]: + return buffer.readVarint64().toUnsigned(); + + // 64bit signed varint zig-zag + case ProtoBuf.TYPES["sint64"]: + return buffer.readVarint64ZigZag(); + + // Fixed 64bit unsigned + case ProtoBuf.TYPES["fixed64"]: + return buffer.readUint64(); + + // Fixed 64bit signed + case ProtoBuf.TYPES["sfixed64"]: + return buffer.readInt64(); + + // Bool varint + case ProtoBuf.TYPES["bool"]: + return !!buffer.readVarint32(); + + // Constant enum value (varint) + case ProtoBuf.TYPES["enum"]: + // The following Builder.Message#set will already throw + return buffer.readVarint32(); + + // 32bit float + case ProtoBuf.TYPES["float"]: + return buffer.readFloat(); + + // 64bit float + case ProtoBuf.TYPES["double"]: + return buffer.readDouble(); + + // Length-delimited string + case ProtoBuf.TYPES["string"]: + return buffer.readVString(); + + // Length-delimited bytes + case ProtoBuf.TYPES["bytes"]: { + nBytes = buffer.readVarint32(); + if (buffer.remaining() < nBytes) + throw Error("Illegal number of bytes for "+this.toString(true)+": "+nBytes+" required but got only "+buffer.remaining()); + value = buffer.clone(); // Offset already set + value.limit = value.offset+nBytes; + buffer.offset += nBytes; + return value; + } + + // Length-delimited embedded message + case ProtoBuf.TYPES["message"]: { + nBytes = buffer.readVarint32(); + return this.resolvedType.decode(buffer, nBytes); + } + + // Legacy group + case ProtoBuf.TYPES["group"]: + return this.resolvedType.decode(buffer, -1, id); + } + + // We should never end here + throw Error("[INTERNAL] Illegal decode type"); + }; + + /** + * Converts a value from a string to the canonical element type. + * + * Legal only when isMapKey is true. + * + * @param {string} str The string value + * @returns {*} The value + */ + ElementPrototype.valueFromString = function(str) { + if (!this.isMapKey) { + throw Error("valueFromString() called on non-map-key element"); + } + + switch (this.type) { + case ProtoBuf.TYPES["int32"]: + case ProtoBuf.TYPES["sint32"]: + case ProtoBuf.TYPES["sfixed32"]: + case ProtoBuf.TYPES["uint32"]: + case ProtoBuf.TYPES["fixed32"]: + return this.verifyValue(parseInt(str)); + + case ProtoBuf.TYPES["int64"]: + case ProtoBuf.TYPES["sint64"]: + case ProtoBuf.TYPES["sfixed64"]: + case ProtoBuf.TYPES["uint64"]: + case ProtoBuf.TYPES["fixed64"]: + // Long-based fields support conversions from string already. + return this.verifyValue(str); + + case ProtoBuf.TYPES["bool"]: + return str === "true"; + + case ProtoBuf.TYPES["string"]: + return this.verifyValue(str); + + case ProtoBuf.TYPES["bytes"]: + return ByteBuffer.fromBinary(str); + } + }; + + /** + * Converts a value from the canonical element type to a string. + * + * It should be the case that `valueFromString(valueToString(val))` returns + * a value equivalent to `verifyValue(val)` for every legal value of `val` + * according to this element type. + * + * This may be used when the element must be stored or used as a string, + * e.g., as a map key on an Object. + * + * Legal only when isMapKey is true. + * + * @param {*} val The value + * @returns {string} The string form of the value. + */ + ElementPrototype.valueToString = function(value) { + if (!this.isMapKey) { + throw Error("valueToString() called on non-map-key element"); + } + + if (this.type === ProtoBuf.TYPES["bytes"]) { + return value.toString("binary"); + } else { + return value.toString(); + } + }; + + /** + * @alias ProtoBuf.Reflect.Element + * @expose + */ + Reflect.Element = Element; + + /** + * Constructs a new Message. + * @exports ProtoBuf.Reflect.Message + * @param {!ProtoBuf.Builder} builder Builder reference + * @param {!ProtoBuf.Reflect.Namespace} parent Parent message or namespace + * @param {string} name Message name + * @param {Object.=} options Message options + * @param {boolean=} isGroup `true` if this is a legacy group + * @param {string?} syntax The syntax level of this definition (e.g., proto3) + * @constructor + * @extends ProtoBuf.Reflect.Namespace + */ + var Message = function(builder, parent, name, options, isGroup, syntax) { + Namespace.call(this, builder, parent, name, options, syntax); + + /** + * @override + */ + this.className = "Message"; + + /** + * Extensions range. + * @type {!Array.|undefined} + * @expose + */ + this.extensions = undefined; + + /** + * Runtime message class. + * @type {?function(new:ProtoBuf.Builder.Message)} + * @expose + */ + this.clazz = null; + + /** + * Whether this is a legacy group or not. + * @type {boolean} + * @expose + */ + this.isGroup = !!isGroup; + + // The following cached collections are used to efficiently iterate over or look up fields when decoding. + + /** + * Cached fields. + * @type {?Array.} + * @private + */ + this._fields = null; + + /** + * Cached fields by id. + * @type {?Object.} + * @private + */ + this._fieldsById = null; + + /** + * Cached fields by name. + * @type {?Object.} + * @private + */ + this._fieldsByName = null; + }; + + /** + * @alias ProtoBuf.Reflect.Message.prototype + * @inner + */ + var MessagePrototype = Message.prototype = Object.create(Namespace.prototype); + + /** + * Builds the message and returns the runtime counterpart, which is a fully functional class. + * @see ProtoBuf.Builder.Message + * @param {boolean=} rebuild Whether to rebuild or not, defaults to false + * @return {ProtoBuf.Reflect.Message} Message class + * @throws {Error} If the message cannot be built + * @expose + */ + MessagePrototype.build = function(rebuild) { + if (this.clazz && !rebuild) + return this.clazz; + + // Create the runtime Message class in its own scope + var clazz = (function(ProtoBuf, T) { + + var fields = T.getChildren(ProtoBuf.Reflect.Message.Field), + oneofs = T.getChildren(ProtoBuf.Reflect.Message.OneOf); + + /** + * Constructs a new runtime Message. + * @name ProtoBuf.Builder.Message + * @class Barebone of all runtime messages. + * @param {!Object.|string} values Preset values + * @param {...string} var_args + * @constructor + * @throws {Error} If the message cannot be created + */ + var Message = function(values, var_args) { + ProtoBuf.Builder.Message.call(this); + + // Create virtual oneof properties + for (var i=0, k=oneofs.length; i 0) { + var value; + // Set field values from a values object + if (arguments.length === 1 && values !== null && typeof values === 'object' && + /* not _another_ Message */ (typeof values.encode !== 'function' || values instanceof Message) && + /* not a repeated field */ !Array.isArray(values) && + /* not a Map */ !(values instanceof ProtoBuf.Map) && + /* not a ByteBuffer */ !ByteBuffer.isByteBuffer(values) && + /* not an ArrayBuffer */ !(values instanceof ArrayBuffer) && + /* not a Long */ !(ProtoBuf.Long && values instanceof ProtoBuf.Long)) { + this.$set(values); + } else // Set field values from arguments, in declaration order + for (i=0, k=arguments.length; i} keyOrObj String key or plain object holding multiple values + * @param {(*|boolean)=} value Value to set if key is a string, otherwise omitted + * @param {boolean=} noAssert Whether to not assert for an actual field / proper value type, defaults to `false` + * @returns {!ProtoBuf.Builder.Message} this + * @throws {Error} If the value cannot be set + * @expose + */ + MessagePrototype.set = function(keyOrObj, value, noAssert) { + if (keyOrObj && typeof keyOrObj === 'object') { + noAssert = value; + for (var ikey in keyOrObj) + if (keyOrObj.hasOwnProperty(ikey) && typeof (value = keyOrObj[ikey]) !== 'undefined') + this.$set(ikey, value, noAssert); + return this; + } + var field = T._fieldsByName[keyOrObj]; + if (!noAssert) { + if (!field) + throw Error(this+"#"+keyOrObj+" is not a field: undefined"); + if (!(field instanceof ProtoBuf.Reflect.Message.Field)) + throw Error(this+"#"+keyOrObj+" is not a field: "+field.toString(true)); + this[field.name] = (value = field.verifyValue(value)); // May throw + } else + this[keyOrObj] = value; + if (field && field.oneof) { // Field is part of an OneOf (not a virtual OneOf field) + var currentField = this[field.oneof.name]; // Virtual field references currently set field + if (value !== null) { + if (currentField !== null && currentField !== field.name) + this[currentField] = null; // Clear currently set field + this[field.oneof.name] = field.name; // Point virtual field at this field + } else if (/* value === null && */currentField === keyOrObj) + this[field.oneof.name] = null; // Clear virtual field (current field explicitly cleared) + } + return this; + }; + + /** + * Sets a field's value. This is an alias for [@link ProtoBuf.Builder.Message#set}. + * @name ProtoBuf.Builder.Message#$set + * @function + * @param {string|!Object.} keyOrObj String key or plain object holding multiple values + * @param {(*|boolean)=} value Value to set if key is a string, otherwise omitted + * @param {boolean=} noAssert Whether to not assert the value, defaults to `false` + * @throws {Error} If the value cannot be set + * @expose + */ + MessagePrototype.$set = MessagePrototype.set; + + /** + * Gets a field's value. + * @name ProtoBuf.Builder.Message#get + * @function + * @param {string} key Key + * @param {boolean=} noAssert Whether to not assert for an actual field, defaults to `false` + * @return {*} Value + * @throws {Error} If there is no such field + * @expose + */ + MessagePrototype.get = function(key, noAssert) { + if (noAssert) + return this[key]; + var field = T._fieldsByName[key]; + if (!field || !(field instanceof ProtoBuf.Reflect.Message.Field)) + throw Error(this+"#"+key+" is not a field: undefined"); + if (!(field instanceof ProtoBuf.Reflect.Message.Field)) + throw Error(this+"#"+key+" is not a field: "+field.toString(true)); + return this[field.name]; + }; + + /** + * Gets a field's value. This is an alias for {@link ProtoBuf.Builder.Message#$get}. + * @name ProtoBuf.Builder.Message#$get + * @function + * @param {string} key Key + * @return {*} Value + * @throws {Error} If there is no such field + * @expose + */ + MessagePrototype.$get = MessagePrototype.get; + + // Getters and setters + + for (var i=0; i} data Data payload + * @param {(!ByteBuffer|boolean)=} buffer ByteBuffer to encode to. Will create a new one and flip it if omitted. + * @param {boolean=} noVerify Whether to not verify field values, defaults to `false` + * @return {!ByteBuffer} Encoded message as a ByteBuffer + * @expose + */ + Message.encode = function(data, buffer, noVerify) { + return new Message(data).encode(buffer, noVerify); + }; + + /** + * Calculates the byte length of the message. + * @name ProtoBuf.Builder.Message#calculate + * @function + * @returns {number} Byte length + * @throws {Error} If the message cannot be calculated or if required fields are missing. + * @expose + */ + MessagePrototype.calculate = function() { + return T.calculate(this); + }; + + /** + * Encodes the varint32 length-delimited message. + * @name ProtoBuf.Builder.Message#encodeDelimited + * @function + * @param {(!ByteBuffer|boolean)=} buffer ByteBuffer to encode to. Will create a new one and flip it if omitted. + * @param {boolean=} noVerify Whether to not verify field values, defaults to `false` + * @return {!ByteBuffer} Encoded message as a ByteBuffer + * @throws {Error} If the message cannot be encoded or if required fields are missing. The later still + * returns the encoded ByteBuffer in the `encoded` property on the error. + * @expose + */ + MessagePrototype.encodeDelimited = function(buffer, noVerify) { + var isNew = false; + if (!buffer) + buffer = new ByteBuffer(), + isNew = true; + var enc = new ByteBuffer().LE(); + T.encode(this, enc, noVerify).flip(); + buffer.writeVarint32(enc.remaining()); + buffer.append(enc); + return isNew ? buffer.flip() : buffer; + }; + + /** + * Directly encodes the message to an ArrayBuffer. + * @name ProtoBuf.Builder.Message#encodeAB + * @function + * @return {ArrayBuffer} Encoded message as ArrayBuffer + * @throws {Error} If the message cannot be encoded or if required fields are missing. The later still + * returns the encoded ArrayBuffer in the `encoded` property on the error. + * @expose + */ + MessagePrototype.encodeAB = function() { + try { + return this.encode().toArrayBuffer(); + } catch (e) { + if (e["encoded"]) e["encoded"] = e["encoded"].toArrayBuffer(); + throw(e); + } + }; + + /** + * Returns the message as an ArrayBuffer. This is an alias for {@link ProtoBuf.Builder.Message#encodeAB}. + * @name ProtoBuf.Builder.Message#toArrayBuffer + * @function + * @return {ArrayBuffer} Encoded message as ArrayBuffer + * @throws {Error} If the message cannot be encoded or if required fields are missing. The later still + * returns the encoded ArrayBuffer in the `encoded` property on the error. + * @expose + */ + MessagePrototype.toArrayBuffer = MessagePrototype.encodeAB; + + /** + * Directly encodes the message to a node Buffer. + * @name ProtoBuf.Builder.Message#encodeNB + * @function + * @return {!Buffer} + * @throws {Error} If the message cannot be encoded, not running under node.js or if required fields are + * missing. The later still returns the encoded node Buffer in the `encoded` property on the error. + * @expose + */ + MessagePrototype.encodeNB = function() { + try { + return this.encode().toBuffer(); + } catch (e) { + if (e["encoded"]) e["encoded"] = e["encoded"].toBuffer(); + throw(e); + } + }; + + /** + * Returns the message as a node Buffer. This is an alias for {@link ProtoBuf.Builder.Message#encodeNB}. + * @name ProtoBuf.Builder.Message#toBuffer + * @function + * @return {!Buffer} + * @throws {Error} If the message cannot be encoded or if required fields are missing. The later still + * returns the encoded node Buffer in the `encoded` property on the error. + * @expose + */ + MessagePrototype.toBuffer = MessagePrototype.encodeNB; + + /** + * Directly encodes the message to a base64 encoded string. + * @name ProtoBuf.Builder.Message#encode64 + * @function + * @return {string} Base64 encoded string + * @throws {Error} If the underlying buffer cannot be encoded or if required fields are missing. The later + * still returns the encoded base64 string in the `encoded` property on the error. + * @expose + */ + MessagePrototype.encode64 = function() { + try { + return this.encode().toBase64(); + } catch (e) { + if (e["encoded"]) e["encoded"] = e["encoded"].toBase64(); + throw(e); + } + }; + + /** + * Returns the message as a base64 encoded string. This is an alias for {@link ProtoBuf.Builder.Message#encode64}. + * @name ProtoBuf.Builder.Message#toBase64 + * @function + * @return {string} Base64 encoded string + * @throws {Error} If the message cannot be encoded or if required fields are missing. The later still + * returns the encoded base64 string in the `encoded` property on the error. + * @expose + */ + MessagePrototype.toBase64 = MessagePrototype.encode64; + + /** + * Directly encodes the message to a hex encoded string. + * @name ProtoBuf.Builder.Message#encodeHex + * @function + * @return {string} Hex encoded string + * @throws {Error} If the underlying buffer cannot be encoded or if required fields are missing. The later + * still returns the encoded hex string in the `encoded` property on the error. + * @expose + */ + MessagePrototype.encodeHex = function() { + try { + return this.encode().toHex(); + } catch (e) { + if (e["encoded"]) e["encoded"] = e["encoded"].toHex(); + throw(e); + } + }; + + /** + * Returns the message as a hex encoded string. This is an alias for {@link ProtoBuf.Builder.Message#encodeHex}. + * @name ProtoBuf.Builder.Message#toHex + * @function + * @return {string} Hex encoded string + * @throws {Error} If the message cannot be encoded or if required fields are missing. The later still + * returns the encoded hex string in the `encoded` property on the error. + * @expose + */ + MessagePrototype.toHex = MessagePrototype.encodeHex; + + /** + * Clones a message object or field value to a raw object. + * @param {*} obj Object to clone + * @param {boolean} binaryAsBase64 Whether to include binary data as base64 strings or as a buffer otherwise + * @param {boolean} longsAsStrings Whether to encode longs as strings + * @param {!ProtoBuf.Reflect.T=} resolvedType The resolved field type if a field + * @returns {*} Cloned object + * @inner + */ + function cloneRaw(obj, binaryAsBase64, longsAsStrings, resolvedType) { + if (obj === null || typeof obj !== 'object') { + // Convert enum values to their respective names + if (resolvedType && resolvedType instanceof ProtoBuf.Reflect.Enum) { + var name = ProtoBuf.Reflect.Enum.getName(resolvedType.object, obj); + if (name !== null) + return name; + } + // Pass-through string, number, boolean, null... + return obj; + } + // Convert ByteBuffers to raw buffer or strings + if (ByteBuffer.isByteBuffer(obj)) + return binaryAsBase64 ? obj.toBase64() : obj.toBuffer(); + // Convert Longs to proper objects or strings + if (ProtoBuf.Long.isLong(obj)) + return longsAsStrings ? obj.toString() : ProtoBuf.Long.fromValue(obj); + var clone; + // Clone arrays + if (Array.isArray(obj)) { + clone = []; + obj.forEach(function(v, k) { + clone[k] = cloneRaw(v, binaryAsBase64, longsAsStrings, resolvedType); + }); + return clone; + } + clone = {}; + // Convert maps to objects + if (obj instanceof ProtoBuf.Map) { + var it = obj.entries(); + for (var e = it.next(); !e.done; e = it.next()) + clone[obj.keyElem.valueToString(e.value[0])] = cloneRaw(e.value[1], binaryAsBase64, longsAsStrings, obj.valueElem.resolvedType); + return clone; + } + // Everything else is a non-null object + var type = obj.$type, + field = undefined; + for (var i in obj) + if (obj.hasOwnProperty(i)) { + if (type && (field = type.getChild(i))) + clone[i] = cloneRaw(obj[i], binaryAsBase64, longsAsStrings, field.resolvedType); + else + clone[i] = cloneRaw(obj[i], binaryAsBase64, longsAsStrings); + } + return clone; + } + + /** + * Returns the message's raw payload. + * @param {boolean=} binaryAsBase64 Whether to include binary data as base64 strings instead of Buffers, defaults to `false` + * @param {boolean} longsAsStrings Whether to encode longs as strings + * @returns {Object.} Raw payload + * @expose + */ + MessagePrototype.toRaw = function(binaryAsBase64, longsAsStrings) { + return cloneRaw(this, !!binaryAsBase64, !!longsAsStrings, this.$type); + }; + + /** + * Encodes a message to JSON. + * @returns {string} JSON string + * @expose + */ + MessagePrototype.encodeJSON = function() { + return JSON.stringify( + cloneRaw(this, + /* binary-as-base64 */ true, + /* longs-as-strings */ true, + this.$type + ) + ); + }; + + /** + * Decodes a message from the specified buffer or string. + * @name ProtoBuf.Builder.Message.decode + * @function + * @param {!ByteBuffer|!ArrayBuffer|!Buffer|string} buffer Buffer to decode from + * @param {(number|string)=} length Message length. Defaults to decode all the remainig data. + * @param {string=} enc Encoding if buffer is a string: hex, utf8 (not recommended), defaults to base64 + * @return {!ProtoBuf.Builder.Message} Decoded message + * @throws {Error} If the message cannot be decoded or if required fields are missing. The later still + * returns the decoded message with missing fields in the `decoded` property on the error. + * @expose + * @see ProtoBuf.Builder.Message.decode64 + * @see ProtoBuf.Builder.Message.decodeHex + */ + Message.decode = function(buffer, length, enc) { + if (typeof length === 'string') + enc = length, + length = -1; + if (typeof buffer === 'string') + buffer = ByteBuffer.wrap(buffer, enc ? enc : "base64"); + buffer = ByteBuffer.isByteBuffer(buffer) ? buffer : ByteBuffer.wrap(buffer); // May throw + var le = buffer.littleEndian; + try { + var msg = T.decode(buffer.LE()); + buffer.LE(le); + return msg; + } catch (e) { + buffer.LE(le); + throw(e); + } + }; + + /** + * Decodes a varint32 length-delimited message from the specified buffer or string. + * @name ProtoBuf.Builder.Message.decodeDelimited + * @function + * @param {!ByteBuffer|!ArrayBuffer|!Buffer|string} buffer Buffer to decode from + * @param {string=} enc Encoding if buffer is a string: hex, utf8 (not recommended), defaults to base64 + * @return {ProtoBuf.Builder.Message} Decoded message or `null` if not enough bytes are available yet + * @throws {Error} If the message cannot be decoded or if required fields are missing. The later still + * returns the decoded message with missing fields in the `decoded` property on the error. + * @expose + */ + Message.decodeDelimited = function(buffer, enc) { + if (typeof buffer === 'string') + buffer = ByteBuffer.wrap(buffer, enc ? enc : "base64"); + buffer = ByteBuffer.isByteBuffer(buffer) ? buffer : ByteBuffer.wrap(buffer); // May throw + if (buffer.remaining() < 1) + return null; + var off = buffer.offset, + len = buffer.readVarint32(); + if (buffer.remaining() < len) { + buffer.offset = off; + return null; + } + try { + var msg = T.decode(buffer.slice(buffer.offset, buffer.offset + len).LE()); + buffer.offset += len; + return msg; + } catch (err) { + buffer.offset += len; + throw err; + } + }; + + /** + * Decodes the message from the specified base64 encoded string. + * @name ProtoBuf.Builder.Message.decode64 + * @function + * @param {string} str String to decode from + * @return {!ProtoBuf.Builder.Message} Decoded message + * @throws {Error} If the message cannot be decoded or if required fields are missing. The later still + * returns the decoded message with missing fields in the `decoded` property on the error. + * @expose + */ + Message.decode64 = function(str) { + return Message.decode(str, "base64"); + }; + + /** + * Decodes the message from the specified hex encoded string. + * @name ProtoBuf.Builder.Message.decodeHex + * @function + * @param {string} str String to decode from + * @return {!ProtoBuf.Builder.Message} Decoded message + * @throws {Error} If the message cannot be decoded or if required fields are missing. The later still + * returns the decoded message with missing fields in the `decoded` property on the error. + * @expose + */ + Message.decodeHex = function(str) { + return Message.decode(str, "hex"); + }; + + /** + * Decodes the message from a JSON string. + * @name ProtoBuf.Builder.Message.decodeJSON + * @function + * @param {string} str String to decode from + * @return {!ProtoBuf.Builder.Message} Decoded message + * @throws {Error} If the message cannot be decoded or if required fields are + * missing. + * @expose + */ + Message.decodeJSON = function(str) { + return new Message(JSON.parse(str)); + }; + + // Utility + + /** + * Returns a string representation of this Message. + * @name ProtoBuf.Builder.Message#toString + * @function + * @return {string} String representation as of ".Fully.Qualified.MessageName" + * @expose + */ + MessagePrototype.toString = function() { + return T.toString(); + }; + + // Properties + + /** + * Message options. + * @name ProtoBuf.Builder.Message.$options + * @type {Object.} + * @expose + */ + var $optionsS; // cc needs this + + /** + * Message options. + * @name ProtoBuf.Builder.Message#$options + * @type {Object.} + * @expose + */ + var $options; + + /** + * Reflection type. + * @name ProtoBuf.Builder.Message.$type + * @type {!ProtoBuf.Reflect.Message} + * @expose + */ + var $typeS; + + /** + * Reflection type. + * @name ProtoBuf.Builder.Message#$type + * @type {!ProtoBuf.Reflect.Message} + * @expose + */ + var $type; + + if (Object.defineProperty) + Object.defineProperty(Message, '$options', { "value": T.buildOpt() }), + Object.defineProperty(MessagePrototype, "$options", { "value": Message["$options"] }), + Object.defineProperty(Message, "$type", { "value": T }), + Object.defineProperty(MessagePrototype, "$type", { "value": T }); + + return Message; + + })(ProtoBuf, this); + + // Static enums and prototyped sub-messages / cached collections + this._fields = []; + this._fieldsById = {}; + this._fieldsByName = {}; + for (var i=0, k=this.children.length, child; i>> 3; + switch (wireType) { + case ProtoBuf.WIRE_TYPES.VARINT: + do tag = buf.readUint8(); + while ((tag & 0x80) === 0x80); + break; + case ProtoBuf.WIRE_TYPES.BITS64: + buf.offset += 8; + break; + case ProtoBuf.WIRE_TYPES.LDELIM: + tag = buf.readVarint32(); // reads the varint + buf.offset += tag; // skips n bytes + break; + case ProtoBuf.WIRE_TYPES.STARTGROUP: + skipTillGroupEnd(id, buf); + break; + case ProtoBuf.WIRE_TYPES.ENDGROUP: + if (id === expectedId) + return false; + else + throw Error("Illegal GROUPEND after unknown group: "+id+" ("+expectedId+" expected)"); + case ProtoBuf.WIRE_TYPES.BITS32: + buf.offset += 4; + break; + default: + throw Error("Illegal wire type in unknown group "+expectedId+": "+wireType); + } + return true; + } + + /** + * Decodes an encoded message and returns the decoded message. + * @param {ByteBuffer} buffer ByteBuffer to decode from + * @param {number=} length Message length. Defaults to decode all remaining data. + * @param {number=} expectedGroupEndId Expected GROUPEND id if this is a legacy group + * @return {ProtoBuf.Builder.Message} Decoded message + * @throws {Error} If the message cannot be decoded + * @expose + */ + MessagePrototype.decode = function(buffer, length, expectedGroupEndId) { + length = typeof length === 'number' ? length : -1; + var start = buffer.offset, + msg = new (this.clazz)(), + tag, wireType, id, field; + while (buffer.offset < start+length || (length === -1 && buffer.remaining() > 0)) { + tag = buffer.readVarint32(); + wireType = tag & 0x07; + id = tag >>> 3; + if (wireType === ProtoBuf.WIRE_TYPES.ENDGROUP) { + if (id !== expectedGroupEndId) + throw Error("Illegal group end indicator for "+this.toString(true)+": "+id+" ("+(expectedGroupEndId ? expectedGroupEndId+" expected" : "not a group")+")"); + break; + } + if (!(field = this._fieldsById[id])) { + // "messages created by your new code can be parsed by your old code: old binaries simply ignore the new field when parsing." + switch (wireType) { + case ProtoBuf.WIRE_TYPES.VARINT: + buffer.readVarint32(); + break; + case ProtoBuf.WIRE_TYPES.BITS32: + buffer.offset += 4; + break; + case ProtoBuf.WIRE_TYPES.BITS64: + buffer.offset += 8; + break; + case ProtoBuf.WIRE_TYPES.LDELIM: + var len = buffer.readVarint32(); + buffer.offset += len; + break; + case ProtoBuf.WIRE_TYPES.STARTGROUP: + while (skipTillGroupEnd(id, buffer)) {} + break; + default: + throw Error("Illegal wire type for unknown field "+id+" in "+this.toString(true)+"#decode: "+wireType); + } + continue; + } + if (field.repeated && !field.options["packed"]) { + msg[field.name].push(field.decode(wireType, buffer)); + } else if (field.map) { + var keyval = field.decode(wireType, buffer); + msg[field.name].set(keyval[0], keyval[1]); + } else { + msg[field.name] = field.decode(wireType, buffer); + if (field.oneof) { // Field is part of an OneOf (not a virtual OneOf field) + var currentField = msg[field.oneof.name]; // Virtual field references currently set field + if (currentField !== null && currentField !== field.name) + msg[currentField] = null; // Clear currently set field + msg[field.oneof.name] = field.name; // Point virtual field at this field + } + } + } + + // Check if all required fields are present and set default values for optional fields that are not + for (var i=0, k=this._fields.length; i=} options Options + * @param {!ProtoBuf.Reflect.Message.OneOf=} oneof Enclosing OneOf + * @param {string?} syntax The syntax level of this definition (e.g., proto3) + * @constructor + * @extends ProtoBuf.Reflect.T + */ + var Field = function(builder, message, rule, keytype, type, name, id, options, oneof, syntax) { + T.call(this, builder, message, name); + + /** + * @override + */ + this.className = "Message.Field"; + + /** + * Message field required flag. + * @type {boolean} + * @expose + */ + this.required = rule === "required"; + + /** + * Message field repeated flag. + * @type {boolean} + * @expose + */ + this.repeated = rule === "repeated"; + + /** + * Message field map flag. + * @type {boolean} + * @expose + */ + this.map = rule === "map"; + + /** + * Message field key type. Type reference string if unresolved, protobuf + * type if resolved. Valid only if this.map === true, null otherwise. + * @type {string|{name: string, wireType: number}|null} + * @expose + */ + this.keyType = keytype || null; + + /** + * Message field type. Type reference string if unresolved, protobuf type if + * resolved. In a map field, this is the value type. + * @type {string|{name: string, wireType: number}} + * @expose + */ + this.type = type; + + /** + * Resolved type reference inside the global namespace. + * @type {ProtoBuf.Reflect.T|null} + * @expose + */ + this.resolvedType = null; + + /** + * Unique message field id. + * @type {number} + * @expose + */ + this.id = id; + + /** + * Message field options. + * @type {!Object.} + * @dict + * @expose + */ + this.options = options || {}; + + /** + * Default value. + * @type {*} + * @expose + */ + this.defaultValue = null; + + /** + * Enclosing OneOf. + * @type {?ProtoBuf.Reflect.Message.OneOf} + * @expose + */ + this.oneof = oneof || null; + + /** + * Syntax level of this definition (e.g., proto3). + * @type {string} + * @expose + */ + this.syntax = syntax || 'proto2'; + + /** + * Original field name. + * @type {string} + * @expose + */ + this.originalName = this.name; // Used to revert camelcase transformation on naming collisions + + /** + * Element implementation. Created in build() after types are resolved. + * @type {ProtoBuf.Element} + * @expose + */ + this.element = null; + + /** + * Key element implementation, for map fields. Created in build() after + * types are resolved. + * @type {ProtoBuf.Element} + * @expose + */ + this.keyElement = null; + + // Convert field names to camel case notation if the override is set + if (this.builder.options['convertFieldsToCamelCase'] && !(this instanceof Message.ExtensionField)) + this.name = ProtoBuf.Util.toCamelCase(this.name); + }; + + /** + * @alias ProtoBuf.Reflect.Message.Field.prototype + * @inner + */ + var FieldPrototype = Field.prototype = Object.create(T.prototype); + + /** + * Builds the field. + * @override + * @expose + */ + FieldPrototype.build = function() { + this.element = new Element(this.type, this.resolvedType, false, this.syntax); + if (this.map) + this.keyElement = new Element(this.keyType, undefined, true, this.syntax); + + // In proto3, fields do not have field presence, and every field is set to + // its type's default value ("", 0, 0.0, or false). + if (this.syntax === 'proto3' && !this.repeated && !this.map) + this.defaultValue = Element.defaultFieldValue(this.type); + + // Otherwise, default values are present when explicitly specified + else if (typeof this.options['default'] !== 'undefined') + this.defaultValue = this.verifyValue(this.options['default']); + }; + + /** + * Checks if the given value can be set for this field. + * @param {*} value Value to check + * @param {boolean=} skipRepeated Whether to skip the repeated value check or not. Defaults to false. + * @return {*} Verified, maybe adjusted, value + * @throws {Error} If the value cannot be set for this field + * @expose + */ + FieldPrototype.verifyValue = function(value, skipRepeated) { + skipRepeated = skipRepeated || false; + var self = this; + function fail(val, msg) { + throw Error("Illegal value for "+self.toString(true)+" of type "+self.type.name+": "+val+" ("+msg+")"); + } + if (value === null) { // NULL values for optional fields + if (this.required) + fail(typeof value, "required"); + if (this.syntax === 'proto3' && this.type !== ProtoBuf.TYPES["message"]) + fail(typeof value, "proto3 field without field presence cannot be null"); + return null; + } + var i; + if (this.repeated && !skipRepeated) { // Repeated values as arrays + if (!Array.isArray(value)) + value = [value]; + var res = []; + for (i=0; i 0; + + case ProtoBuf.TYPES["bytes"]: + return value.remaining() > 0; + + case ProtoBuf.TYPES["enum"]: + return value !== 0; + + case ProtoBuf.TYPES["message"]: + return value !== null; + default: + return true; + } + }; + + /** + * Encodes the specified field value to the specified buffer. + * @param {*} value Verified field value + * @param {ByteBuffer} buffer ByteBuffer to encode to + * @param {!ProtoBuf.Builder.Message} message Runtime message + * @return {ByteBuffer} The ByteBuffer for chaining + * @throws {Error} If the field cannot be encoded + * @expose + */ + FieldPrototype.encode = function(value, buffer, message) { + if (this.type === null || typeof this.type !== 'object') + throw Error("[INTERNAL] Unresolved type in "+this.toString(true)+": "+this.type); + if (value === null || (this.repeated && value.length == 0)) + return buffer; // Optional omitted + try { + if (this.repeated) { + var i; + // "Only repeated fields of primitive numeric types (types which use the varint, 32-bit, or 64-bit wire + // types) can be declared 'packed'." + if (this.options["packed"] && ProtoBuf.PACKABLE_WIRE_TYPES.indexOf(this.type.wireType) >= 0) { + // "All of the elements of the field are packed into a single key-value pair with wire type 2 + // (length-delimited). Each element is encoded the same way it would be normally, except without a + // tag preceding it." + buffer.writeVarint32((this.id << 3) | ProtoBuf.WIRE_TYPES.LDELIM); + buffer.ensureCapacity(buffer.offset += 1); // We do not know the length yet, so let's assume a varint of length 1 + var start = buffer.offset; // Remember where the contents begin + for (i=0; i 1) { // We need to move the contents + var contents = buffer.slice(start, buffer.offset); + start += varintLen-1; + buffer.offset = start; + buffer.append(contents); + } + buffer.writeVarint32(len, start-varintLen); + } else { + // "If your message definition has repeated elements (without the [packed=true] option), the encoded + // message has zero or more key-value pairs with the same tag number" + for (i=0; i= 0) { + n += ByteBuffer.calculateVarint32((this.id << 3) | ProtoBuf.WIRE_TYPES.LDELIM); + ni = 0; + for (i=0; i= 0) { + if (!skipRepeated) { + nBytes = buffer.readVarint32(); + nBytes = buffer.offset + nBytes; // Limit + var values = []; + while (buffer.offset < nBytes) + values.push(this.decode(this.type.wireType, buffer, true)); + return values; + } + // Read the next value otherwise... + } + + // Handle maps. + if (this.map) { + // Read one (key, value) submessage, and return [key, value] + var key = Element.defaultFieldValue(this.keyType); + value = Element.defaultFieldValue(this.type); + + // Read the length + nBytes = buffer.readVarint32(); + if (buffer.remaining() < nBytes) + throw Error("Illegal number of bytes for "+this.toString(true)+": "+nBytes+" required but got only "+buffer.remaining()); + + // Get a sub-buffer of this key/value submessage + var msgbuf = buffer.clone(); + msgbuf.limit = msgbuf.offset + nBytes; + buffer.offset += nBytes; + + while (msgbuf.remaining() > 0) { + var tag = msgbuf.readVarint32(); + wireType = tag & 0x07; + var id = tag >>> 3; + if (id === 1) { + key = this.keyElement.decode(msgbuf, wireType, id); + } else if (id === 2) { + value = this.element.decode(msgbuf, wireType, id); + } else { + throw Error("Unexpected tag in map field key/value submessage"); + } + } + + return [key, value]; + } + + // Handle singular and non-packed repeated field values. + return this.element.decode(buffer, wireType, this.id); + }; + + /** + * @alias ProtoBuf.Reflect.Message.Field + * @expose + */ + Reflect.Message.Field = Field; + + /** + * Constructs a new Message ExtensionField. + * @exports ProtoBuf.Reflect.Message.ExtensionField + * @param {!ProtoBuf.Builder} builder Builder reference + * @param {!ProtoBuf.Reflect.Message} message Message reference + * @param {string} rule Rule, one of requried, optional, repeated + * @param {string} type Data type, e.g. int32 + * @param {string} name Field name + * @param {number} id Unique field id + * @param {!Object.=} options Options + * @constructor + * @extends ProtoBuf.Reflect.Message.Field + */ + var ExtensionField = function(builder, message, rule, type, name, id, options) { + Field.call(this, builder, message, rule, /* keytype = */ null, type, name, id, options); + + /** + * Extension reference. + * @type {!ProtoBuf.Reflect.Extension} + * @expose + */ + this.extension; + }; + + // Extends Field + ExtensionField.prototype = Object.create(Field.prototype); + + /** + * @alias ProtoBuf.Reflect.Message.ExtensionField + * @expose + */ + Reflect.Message.ExtensionField = ExtensionField; + + /** + * Constructs a new Message OneOf. + * @exports ProtoBuf.Reflect.Message.OneOf + * @param {!ProtoBuf.Builder} builder Builder reference + * @param {!ProtoBuf.Reflect.Message} message Message reference + * @param {string} name OneOf name + * @constructor + * @extends ProtoBuf.Reflect.T + */ + var OneOf = function(builder, message, name) { + T.call(this, builder, message, name); + + /** + * Enclosed fields. + * @type {!Array.} + * @expose + */ + this.fields = []; + }; + + /** + * @alias ProtoBuf.Reflect.Message.OneOf + * @expose + */ + Reflect.Message.OneOf = OneOf; + + /** + * Constructs a new Enum. + * @exports ProtoBuf.Reflect.Enum + * @param {!ProtoBuf.Builder} builder Builder reference + * @param {!ProtoBuf.Reflect.T} parent Parent Reflect object + * @param {string} name Enum name + * @param {Object.=} options Enum options + * @param {string?} syntax The syntax level (e.g., proto3) + * @constructor + * @extends ProtoBuf.Reflect.Namespace + */ + var Enum = function(builder, parent, name, options, syntax) { + Namespace.call(this, builder, parent, name, options, syntax); + + /** + * @override + */ + this.className = "Enum"; + + /** + * Runtime enum object. + * @type {Object.|null} + * @expose + */ + this.object = null; + }; + + /** + * Gets the string name of an enum value. + * @param {!ProtoBuf.Builder.Enum} enm Runtime enum + * @param {number} value Enum value + * @returns {?string} Name or `null` if not present + * @expose + */ + Enum.getName = function(enm, value) { + var keys = Object.keys(enm); + for (var i=0, key; i} + * @expose + */ + EnumPrototype.build = function(rebuild) { + if (this.object && !rebuild) + return this.object; + var enm = new ProtoBuf.Builder.Enum(), + values = this.getChildren(Enum.Value); + for (var i=0, k=values.length; i=} options Options + * @constructor + * @extends ProtoBuf.Reflect.Namespace + */ + var Service = function(builder, root, name, options) { + Namespace.call(this, builder, root, name, options); + + /** + * @override + */ + this.className = "Service"; + + /** + * Built runtime service class. + * @type {?function(new:ProtoBuf.Builder.Service)} + */ + this.clazz = null; + }; + + /** + * @alias ProtoBuf.Reflect.Service.prototype + * @inner + */ + var ServicePrototype = Service.prototype = Object.create(Namespace.prototype); + + /** + * Builds the service and returns the runtime counterpart, which is a fully functional class. + * @see ProtoBuf.Builder.Service + * @param {boolean=} rebuild Whether to rebuild or not + * @return {Function} Service class + * @throws {Error} If the message cannot be built + * @expose + */ + ServicePrototype.build = function(rebuild) { + if (this.clazz && !rebuild) + return this.clazz; + + // Create the runtime Service class in its own scope + return this.clazz = (function(ProtoBuf, T) { + + /** + * Constructs a new runtime Service. + * @name ProtoBuf.Builder.Service + * @param {function(string, ProtoBuf.Builder.Message, function(Error, ProtoBuf.Builder.Message=))=} rpcImpl RPC implementation receiving the method name and the message + * @class Barebone of all runtime services. + * @constructor + * @throws {Error} If the service cannot be created + */ + var Service = function(rpcImpl) { + ProtoBuf.Builder.Service.call(this); + + /** + * Service implementation. + * @name ProtoBuf.Builder.Service#rpcImpl + * @type {!function(string, ProtoBuf.Builder.Message, function(Error, ProtoBuf.Builder.Message=))} + * @expose + */ + this.rpcImpl = rpcImpl || function(name, msg, callback) { + // This is what a user has to implement: A function receiving the method name, the actual message to + // send (type checked) and the callback that's either provided with the error as its first + // argument or null and the actual response message. + setTimeout(callback.bind(this, Error("Not implemented, see: https://github.com/dcodeIO/ProtoBuf.js/wiki/Services")), 0); // Must be async! + }; + }; + + /** + * @alias ProtoBuf.Builder.Service.prototype + * @inner + */ + var ServicePrototype = Service.prototype = Object.create(ProtoBuf.Builder.Service.prototype); + + /** + * Asynchronously performs an RPC call using the given RPC implementation. + * @name ProtoBuf.Builder.Service.[Method] + * @function + * @param {!function(string, ProtoBuf.Builder.Message, function(Error, ProtoBuf.Builder.Message=))} rpcImpl RPC implementation + * @param {ProtoBuf.Builder.Message} req Request + * @param {function(Error, (ProtoBuf.Builder.Message|ByteBuffer|Buffer|string)=)} callback Callback receiving + * the error if any and the response either as a pre-parsed message or as its raw bytes + * @abstract + */ + + /** + * Asynchronously performs an RPC call using the instance's RPC implementation. + * @name ProtoBuf.Builder.Service#[Method] + * @function + * @param {ProtoBuf.Builder.Message} req Request + * @param {function(Error, (ProtoBuf.Builder.Message|ByteBuffer|Buffer|string)=)} callback Callback receiving + * the error if any and the response either as a pre-parsed message or as its raw bytes + * @abstract + */ + + var rpc = T.getChildren(ProtoBuf.Reflect.Service.RPCMethod); + for (var i=0; i} + * @expose + */ + var $optionsS; // cc needs this + + /** + * Service options. + * @name ProtoBuf.Builder.Service#$options + * @type {Object.} + * @expose + */ + var $options; + + /** + * Reflection type. + * @name ProtoBuf.Builder.Service.$type + * @type {!ProtoBuf.Reflect.Service} + * @expose + */ + var $typeS; + + /** + * Reflection type. + * @name ProtoBuf.Builder.Service#$type + * @type {!ProtoBuf.Reflect.Service} + * @expose + */ + var $type; + + if (Object.defineProperty) + Object.defineProperty(Service, "$options", { "value": T.buildOpt() }), + Object.defineProperty(ServicePrototype, "$options", { "value": Service["$options"] }), + Object.defineProperty(Service, "$type", { "value": T }), + Object.defineProperty(ServicePrototype, "$type", { "value": T }); + + return Service; + + })(ProtoBuf, this); + }; + + /** + * @alias ProtoBuf.Reflect.Service + * @expose + */ + Reflect.Service = Service; + + /** + * Abstract service method. + * @exports ProtoBuf.Reflect.Service.Method + * @param {!ProtoBuf.Builder} builder Builder reference + * @param {!ProtoBuf.Reflect.Service} svc Service + * @param {string} name Method name + * @param {Object.=} options Options + * @constructor + * @extends ProtoBuf.Reflect.T + */ + var Method = function(builder, svc, name, options) { + T.call(this, builder, svc, name); + + /** + * @override + */ + this.className = "Service.Method"; + + /** + * Options. + * @type {Object.} + * @expose + */ + this.options = options || {}; + }; + + /** + * @alias ProtoBuf.Reflect.Service.Method.prototype + * @inner + */ + var MethodPrototype = Method.prototype = Object.create(T.prototype); + + /** + * Builds the method's '$options' property. + * @name ProtoBuf.Reflect.Service.Method#buildOpt + * @function + * @return {Object.} + */ + MethodPrototype.buildOpt = NamespacePrototype.buildOpt; + + /** + * @alias ProtoBuf.Reflect.Service.Method + * @expose + */ + Reflect.Service.Method = Method; + + /** + * RPC service method. + * @exports ProtoBuf.Reflect.Service.RPCMethod + * @param {!ProtoBuf.Builder} builder Builder reference + * @param {!ProtoBuf.Reflect.Service} svc Service + * @param {string} name Method name + * @param {string} request Request message name + * @param {string} response Response message name + * @param {boolean} request_stream Whether requests are streamed + * @param {boolean} response_stream Whether responses are streamed + * @param {Object.=} options Options + * @constructor + * @extends ProtoBuf.Reflect.Service.Method + */ + var RPCMethod = function(builder, svc, name, request, response, request_stream, response_stream, options) { + Method.call(this, builder, svc, name, options); + + /** + * @override + */ + this.className = "Service.RPCMethod"; + + /** + * Request message name. + * @type {string} + * @expose + */ + this.requestName = request; + + /** + * Response message name. + * @type {string} + * @expose + */ + this.responseName = response; + + /** + * Whether requests are streamed + * @type {bool} + * @expose + */ + this.requestStream = request_stream; + + /** + * Whether responses are streamed + * @type {bool} + * @expose + */ + this.responseStream = response_stream; + + /** + * Resolved request message type. + * @type {ProtoBuf.Reflect.Message} + * @expose + */ + this.resolvedRequestType = null; + + /** + * Resolved response message type. + * @type {ProtoBuf.Reflect.Message} + * @expose + */ + this.resolvedResponseType = null; + }; + + // Extends Method + RPCMethod.prototype = Object.create(Method.prototype); + + /** + * @alias ProtoBuf.Reflect.Service.RPCMethod + * @expose + */ + Reflect.Service.RPCMethod = RPCMethod; + + return Reflect; + + })(ProtoBuf); + + /** + * @alias ProtoBuf.Builder + * @expose + */ + ProtoBuf.Builder = (function(ProtoBuf, Lang, Reflect) { + "use strict"; + + /** + * Constructs a new Builder. + * @exports ProtoBuf.Builder + * @class Provides the functionality to build protocol messages. + * @param {Object.=} options Options + * @constructor + */ + var Builder = function(options) { + + /** + * Namespace. + * @type {ProtoBuf.Reflect.Namespace} + * @expose + */ + this.ns = new Reflect.Namespace(this, null, ""); // Global namespace + + /** + * Namespace pointer. + * @type {ProtoBuf.Reflect.T} + * @expose + */ + this.ptr = this.ns; + + /** + * Resolved flag. + * @type {boolean} + * @expose + */ + this.resolved = false; + + /** + * The current building result. + * @type {Object.|null} + * @expose + */ + this.result = null; + + /** + * Imported files. + * @type {Array.} + * @expose + */ + this.files = {}; + + /** + * Import root override. + * @type {?string} + * @expose + */ + this.importRoot = null; + + /** + * Options. + * @type {!Object.} + * @expose + */ + this.options = options || {}; + }; + + /** + * @alias ProtoBuf.Builder.prototype + * @inner + */ + var BuilderPrototype = Builder.prototype; + + // ----- Definition tests ----- + + /** + * Tests if a definition most likely describes a message. + * @param {!Object} def + * @returns {boolean} + * @expose + */ + Builder.isMessage = function(def) { + // Messages require a string name + if (typeof def["name"] !== 'string') + return false; + // Messages do not contain values (enum) or rpc methods (service) + if (typeof def["values"] !== 'undefined' || typeof def["rpc"] !== 'undefined') + return false; + return true; + }; + + /** + * Tests if a definition most likely describes a message field. + * @param {!Object} def + * @returns {boolean} + * @expose + */ + Builder.isMessageField = function(def) { + // Message fields require a string rule, name and type and an id + if (typeof def["rule"] !== 'string' || typeof def["name"] !== 'string' || typeof def["type"] !== 'string' || typeof def["id"] === 'undefined') + return false; + return true; + }; + + /** + * Tests if a definition most likely describes an enum. + * @param {!Object} def + * @returns {boolean} + * @expose + */ + Builder.isEnum = function(def) { + // Enums require a string name + if (typeof def["name"] !== 'string') + return false; + // Enums require at least one value + if (typeof def["values"] === 'undefined' || !Array.isArray(def["values"]) || def["values"].length === 0) + return false; + return true; + }; + + /** + * Tests if a definition most likely describes a service. + * @param {!Object} def + * @returns {boolean} + * @expose + */ + Builder.isService = function(def) { + // Services require a string name and an rpc object + if (typeof def["name"] !== 'string' || typeof def["rpc"] !== 'object' || !def["rpc"]) + return false; + return true; + }; + + /** + * Tests if a definition most likely describes an extended message + * @param {!Object} def + * @returns {boolean} + * @expose + */ + Builder.isExtend = function(def) { + // Extends rquire a string ref + if (typeof def["ref"] !== 'string') + return false; + return true; + }; + + // ----- Building ----- + + /** + * Resets the pointer to the root namespace. + * @returns {!ProtoBuf.Builder} this + * @expose + */ + BuilderPrototype.reset = function() { + this.ptr = this.ns; + return this; + }; + + /** + * Defines a namespace on top of the current pointer position and places the pointer on it. + * @param {string} namespace + * @return {!ProtoBuf.Builder} this + * @expose + */ + BuilderPrototype.define = function(namespace) { + if (typeof namespace !== 'string' || !Lang.TYPEREF.test(namespace)) + throw Error("illegal namespace: "+namespace); + namespace.split(".").forEach(function(part) { + var ns = this.ptr.getChild(part); + if (ns === null) // Keep existing + this.ptr.addChild(ns = new Reflect.Namespace(this, this.ptr, part)); + this.ptr = ns; + }, this); + return this; + }; + + /** + * Creates the specified definitions at the current pointer position. + * @param {!Array.} defs Messages, enums or services to create + * @returns {!ProtoBuf.Builder} this + * @throws {Error} If a message definition is invalid + * @expose + */ + BuilderPrototype.create = function(defs) { + if (!defs) + return this; // Nothing to create + if (!Array.isArray(defs)) + defs = [defs]; + else { + if (defs.length === 0) + return this; + defs = defs.slice(); + } + + // It's quite hard to keep track of scopes and memory here, so let's do this iteratively. + var stack = [defs]; + while (stack.length > 0) { + defs = stack.pop(); + + if (!Array.isArray(defs)) // Stack always contains entire namespaces + throw Error("not a valid namespace: "+JSON.stringify(defs)); + + while (defs.length > 0) { + var def = defs.shift(); // Namespaces always contain an array of messages, enums and services + + if (Builder.isMessage(def)) { + var obj = new Reflect.Message(this, this.ptr, def["name"], def["options"], def["isGroup"], def["syntax"]); + + // Create OneOfs + var oneofs = {}; + if (def["oneofs"]) + Object.keys(def["oneofs"]).forEach(function(name) { + obj.addChild(oneofs[name] = new Reflect.Message.OneOf(this, obj, name)); + }, this); + + // Create fields + if (def["fields"]) + def["fields"].forEach(function(fld) { + if (obj.getChild(fld["id"]|0) !== null) + throw Error("duplicate or invalid field id in "+obj.name+": "+fld['id']); + if (fld["options"] && typeof fld["options"] !== 'object') + throw Error("illegal field options in "+obj.name+"#"+fld["name"]); + var oneof = null; + if (typeof fld["oneof"] === 'string' && !(oneof = oneofs[fld["oneof"]])) + throw Error("illegal oneof in "+obj.name+"#"+fld["name"]+": "+fld["oneof"]); + fld = new Reflect.Message.Field(this, obj, fld["rule"], fld["keytype"], fld["type"], fld["name"], fld["id"], fld["options"], oneof, def["syntax"]); + if (oneof) + oneof.fields.push(fld); + obj.addChild(fld); + }, this); + + // Push children to stack + var subObj = []; + if (def["enums"]) + def["enums"].forEach(function(enm) { + subObj.push(enm); + }); + if (def["messages"]) + def["messages"].forEach(function(msg) { + subObj.push(msg); + }); + if (def["services"]) + def["services"].forEach(function(svc) { + subObj.push(svc); + }); + + // Set extension ranges + if (def["extensions"]) { + if (typeof def["extensions"][0] === 'number') // pre 5.0.1 + obj.extensions = [ def["extensions"] ]; + else + obj.extensions = def["extensions"]; + } + + // Create on top of current namespace + this.ptr.addChild(obj); + if (subObj.length > 0) { + stack.push(defs); // Push the current level back + defs = subObj; // Continue processing sub level + subObj = null; + this.ptr = obj; // And move the pointer to this namespace + obj = null; + continue; + } + subObj = null; + + } else if (Builder.isEnum(def)) { + + obj = new Reflect.Enum(this, this.ptr, def["name"], def["options"], def["syntax"]); + def["values"].forEach(function(val) { + obj.addChild(new Reflect.Enum.Value(this, obj, val["name"], val["id"])); + }, this); + this.ptr.addChild(obj); + + } else if (Builder.isService(def)) { + + obj = new Reflect.Service(this, this.ptr, def["name"], def["options"]); + Object.keys(def["rpc"]).forEach(function(name) { + var mtd = def["rpc"][name]; + obj.addChild(new Reflect.Service.RPCMethod(this, obj, name, mtd["request"], mtd["response"], !!mtd["request_stream"], !!mtd["response_stream"], mtd["options"])); + }, this); + this.ptr.addChild(obj); + + } else if (Builder.isExtend(def)) { + + obj = this.ptr.resolve(def["ref"], true); + if (obj) { + def["fields"].forEach(function(fld) { + if (obj.getChild(fld['id']|0) !== null) + throw Error("duplicate extended field id in "+obj.name+": "+fld['id']); + // Check if field id is allowed to be extended + if (obj.extensions) { + var valid = false; + obj.extensions.forEach(function(range) { + if (fld["id"] >= range[0] && fld["id"] <= range[1]) + valid = true; + }); + if (!valid) + throw Error("illegal extended field id in "+obj.name+": "+fld['id']+" (not within valid ranges)"); + } + // Convert extension field names to camel case notation if the override is set + var name = fld["name"]; + if (this.options['convertFieldsToCamelCase']) + name = ProtoBuf.Util.toCamelCase(name); + // see #161: Extensions use their fully qualified name as their runtime key and... + var field = new Reflect.Message.ExtensionField(this, obj, fld["rule"], fld["type"], this.ptr.fqn()+'.'+name, fld["id"], fld["options"]); + // ...are added on top of the current namespace as an extension which is used for + // resolving their type later on (the extension always keeps the original name to + // prevent naming collisions) + var ext = new Reflect.Extension(this, this.ptr, fld["name"], field); + field.extension = ext; + this.ptr.addChild(ext); + obj.addChild(field); + }, this); + + } else if (!/\.?google\.protobuf\./.test(def["ref"])) // Silently skip internal extensions + throw Error("extended message "+def["ref"]+" is not defined"); + + } else + throw Error("not a valid definition: "+JSON.stringify(def)); + + def = null; + obj = null; + } + // Break goes here + defs = null; + this.ptr = this.ptr.parent; // Namespace done, continue at parent + } + this.resolved = false; // Require re-resolve + this.result = null; // Require re-build + return this; + }; + + /** + * Propagates syntax to all children. + * @param {!Object} parent + * @inner + */ + function propagateSyntax(parent) { + if (parent['messages']) { + parent['messages'].forEach(function(child) { + child["syntax"] = parent["syntax"]; + propagateSyntax(child); + }); + } + if (parent['enums']) { + parent['enums'].forEach(function(child) { + child["syntax"] = parent["syntax"]; + }); + } + } + + /** + * Imports another definition into this builder. + * @param {Object.} json Parsed import + * @param {(string|{root: string, file: string})=} filename Imported file name + * @returns {!ProtoBuf.Builder} this + * @throws {Error} If the definition or file cannot be imported + * @expose + */ + BuilderPrototype["import"] = function(json, filename) { + var delim = '/'; + + // Make sure to skip duplicate imports + + if (typeof filename === 'string') { + + if (ProtoBuf.Util.IS_NODE) + filename = require("path")['resolve'](filename); + if (this.files[filename] === true) + return this.reset(); + this.files[filename] = true; + + } else if (typeof filename === 'object') { // Object with root, file. + + var root = filename.root; + if (ProtoBuf.Util.IS_NODE) + root = require("path")['resolve'](root); + if (root.indexOf("\\") >= 0 || filename.file.indexOf("\\") >= 0) + delim = '\\'; + var fname = root + delim + filename.file; + if (this.files[fname] === true) + return this.reset(); + this.files[fname] = true; + } + + // Import imports + + if (json['imports'] && json['imports'].length > 0) { + var importRoot, + resetRoot = false; + + if (typeof filename === 'object') { // If an import root is specified, override + + this.importRoot = filename["root"]; resetRoot = true; // ... and reset afterwards + importRoot = this.importRoot; + filename = filename["file"]; + if (importRoot.indexOf("\\") >= 0 || filename.indexOf("\\") >= 0) + delim = '\\'; + + } else if (typeof filename === 'string') { + + if (this.importRoot) // If import root is overridden, use it + importRoot = this.importRoot; + else { // Otherwise compute from filename + if (filename.indexOf("/") >= 0) { // Unix + importRoot = filename.replace(/\/[^\/]*$/, ""); + if (/* /file.proto */ importRoot === "") + importRoot = "/"; + } else if (filename.indexOf("\\") >= 0) { // Windows + importRoot = filename.replace(/\\[^\\]*$/, ""); + delim = '\\'; + } else + importRoot = "."; + } + + } else + importRoot = null; + + for (var i=0; i)=} path Specifies what to return. If omitted, the entire namespace will be returned. + * @returns {!ProtoBuf.Builder.Message|!Object.} + * @throws {Error} If a type could not be resolved + * @expose + */ + BuilderPrototype.build = function(path) { + this.reset(); + if (!this.resolved) + this.resolveAll(), + this.resolved = true, + this.result = null; // Require re-build + if (this.result === null) // (Re-)Build + this.result = this.ns.build(); + if (!path) + return this.result; + var part = typeof path === 'string' ? path.split(".") : path, + ptr = this.result; // Build namespace pointer (no hasChild etc.) + for (var i=0; i=} contents Initial contents + * @constructor + */ + var Map = function(field, contents) { + if (!field.map) + throw Error("field is not a map"); + + /** + * The field corresponding to this map. + * @type {!ProtoBuf.Reflect.Field} + */ + this.field = field; + + /** + * Element instance corresponding to key type. + * @type {!ProtoBuf.Reflect.Element} + */ + this.keyElem = new Reflect.Element(field.keyType, null, true, field.syntax); + + /** + * Element instance corresponding to value type. + * @type {!ProtoBuf.Reflect.Element} + */ + this.valueElem = new Reflect.Element(field.type, field.resolvedType, false, field.syntax); + + /** + * Internal map: stores mapping of (string form of key) -> (key, value) + * pair. + * + * We provide map semantics for arbitrary key types, but we build on top + * of an Object, which has only string keys. In order to avoid the need + * to convert a string key back to its native type in many situations, + * we store the native key value alongside the value. Thus, we only need + * a one-way mapping from a key type to its string form that guarantees + * uniqueness and equality (i.e., str(K1) === str(K2) if and only if K1 + * === K2). + * + * @type {!Object} + */ + this.map = {}; + + /** + * Returns the number of elements in the map. + */ + Object.defineProperty(this, "size", { + get: function() { return Object.keys(this.map).length; } + }); + + // Fill initial contents from a raw object. + if (contents) { + var keys = Object.keys(contents); + for (var i = 0; i < keys.length; i++) { + var key = this.keyElem.valueFromString(keys[i]); + var val = this.valueElem.verifyValue(contents[keys[i]]); + this.map[this.keyElem.valueToString(key)] = + { key: key, value: val }; + } + } + }; + + var MapPrototype = Map.prototype; + + /** + * Helper: return an iterator over an array. + * @param {!Array<*>} arr the array + * @returns {!Object} an iterator + * @inner + */ + function arrayIterator(arr) { + var idx = 0; + return { + next: function() { + if (idx < arr.length) + return { done: false, value: arr[idx++] }; + return { done: true }; + } + } + } + + /** + * Clears the map. + */ + MapPrototype.clear = function() { + this.map = {}; + }; + + /** + * Deletes a particular key from the map. + * @returns {boolean} Whether any entry with this key was deleted. + */ + MapPrototype["delete"] = function(key) { + var keyValue = this.keyElem.valueToString(this.keyElem.verifyValue(key)); + var hadKey = keyValue in this.map; + delete this.map[keyValue]; + return hadKey; + }; + + /** + * Returns an iterator over [key, value] pairs in the map. + * @returns {Object} The iterator + */ + MapPrototype.entries = function() { + var entries = []; + var strKeys = Object.keys(this.map); + for (var i = 0, entry; i < strKeys.length; i++) + entries.push([(entry=this.map[strKeys[i]]).key, entry.value]); + return arrayIterator(entries); + }; + + /** + * Returns an iterator over keys in the map. + * @returns {Object} The iterator + */ + MapPrototype.keys = function() { + var keys = []; + var strKeys = Object.keys(this.map); + for (var i = 0; i < strKeys.length; i++) + keys.push(this.map[strKeys[i]].key); + return arrayIterator(keys); + }; + + /** + * Returns an iterator over values in the map. + * @returns {!Object} The iterator + */ + MapPrototype.values = function() { + var values = []; + var strKeys = Object.keys(this.map); + for (var i = 0; i < strKeys.length; i++) + values.push(this.map[strKeys[i]].value); + return arrayIterator(values); + }; + + /** + * Iterates over entries in the map, calling a function on each. + * @param {function(this:*, *, *, *)} cb The callback to invoke with value, key, and map arguments. + * @param {Object=} thisArg The `this` value for the callback + */ + MapPrototype.forEach = function(cb, thisArg) { + var strKeys = Object.keys(this.map); + for (var i = 0, entry; i < strKeys.length; i++) + cb.call(thisArg, (entry=this.map[strKeys[i]]).value, entry.key, this); + }; + + /** + * Sets a key in the map to the given value. + * @param {*} key The key + * @param {*} value The value + * @returns {!ProtoBuf.Map} The map instance + */ + MapPrototype.set = function(key, value) { + var keyValue = this.keyElem.verifyValue(key); + var valValue = this.valueElem.verifyValue(value); + this.map[this.keyElem.valueToString(keyValue)] = + { key: keyValue, value: valValue }; + return this; + }; + + /** + * Gets the value corresponding to a key in the map. + * @param {*} key The key + * @returns {*|undefined} The value, or `undefined` if key not present + */ + MapPrototype.get = function(key) { + var keyValue = this.keyElem.valueToString(this.keyElem.verifyValue(key)); + if (!(keyValue in this.map)) + return undefined; + return this.map[keyValue].value; + }; + + /** + * Determines whether the given key is present in the map. + * @param {*} key The key + * @returns {boolean} `true` if the key is present + */ + MapPrototype.has = function(key) { + var keyValue = this.keyElem.valueToString(this.keyElem.verifyValue(key)); + return (keyValue in this.map); + }; + + return Map; + })(ProtoBuf, ProtoBuf.Reflect); + + + /** + * Loads a .proto string and returns the Builder. + * @param {string} proto .proto file contents + * @param {(ProtoBuf.Builder|string|{root: string, file: string})=} builder Builder to append to. Will create a new one if omitted. + * @param {(string|{root: string, file: string})=} filename The corresponding file name if known. Must be specified for imports. + * @return {ProtoBuf.Builder} Builder to create new messages + * @throws {Error} If the definition cannot be parsed or built + * @expose + */ + ProtoBuf.loadProto = function(proto, builder, filename) { + if (typeof builder === 'string' || (builder && typeof builder["file"] === 'string' && typeof builder["root"] === 'string')) + filename = builder, + builder = undefined; + return ProtoBuf.loadJson(ProtoBuf.DotProto.Parser.parse(proto), builder, filename); + }; + + /** + * Loads a .proto string and returns the Builder. This is an alias of {@link ProtoBuf.loadProto}. + * @function + * @param {string} proto .proto file contents + * @param {(ProtoBuf.Builder|string)=} builder Builder to append to. Will create a new one if omitted. + * @param {(string|{root: string, file: string})=} filename The corresponding file name if known. Must be specified for imports. + * @return {ProtoBuf.Builder} Builder to create new messages + * @throws {Error} If the definition cannot be parsed or built + * @expose + */ + ProtoBuf.protoFromString = ProtoBuf.loadProto; // Legacy + + /** + * Loads a .proto file and returns the Builder. + * @param {string|{root: string, file: string}} filename Path to proto file or an object specifying 'file' with + * an overridden 'root' path for all imported files. + * @param {function(?Error, !ProtoBuf.Builder=)=} callback Callback that will receive `null` as the first and + * the Builder as its second argument on success, otherwise the error as its first argument. If omitted, the + * file will be read synchronously and this function will return the Builder. + * @param {ProtoBuf.Builder=} builder Builder to append to. Will create a new one if omitted. + * @return {?ProtoBuf.Builder|undefined} The Builder if synchronous (no callback specified, will be NULL if the + * request has failed), else undefined + * @expose + */ + ProtoBuf.loadProtoFile = function(filename, callback, builder) { + if (callback && typeof callback === 'object') + builder = callback, + callback = null; + else if (!callback || typeof callback !== 'function') + callback = null; + if (callback) + return ProtoBuf.Util.fetch(typeof filename === 'string' ? filename : filename["root"]+"/"+filename["file"], function(contents) { + if (contents === null) { + callback(Error("Failed to fetch file")); + return; + } + try { + callback(null, ProtoBuf.loadProto(contents, builder, filename)); + } catch (e) { + callback(e); + } + }); + var contents = ProtoBuf.Util.fetch(typeof filename === 'object' ? filename["root"]+"/"+filename["file"] : filename); + return contents === null ? null : ProtoBuf.loadProto(contents, builder, filename); + }; + + /** + * Loads a .proto file and returns the Builder. This is an alias of {@link ProtoBuf.loadProtoFile}. + * @function + * @param {string|{root: string, file: string}} filename Path to proto file or an object specifying 'file' with + * an overridden 'root' path for all imported files. + * @param {function(?Error, !ProtoBuf.Builder=)=} callback Callback that will receive `null` as the first and + * the Builder as its second argument on success, otherwise the error as its first argument. If omitted, the + * file will be read synchronously and this function will return the Builder. + * @param {ProtoBuf.Builder=} builder Builder to append to. Will create a new one if omitted. + * @return {!ProtoBuf.Builder|undefined} The Builder if synchronous (no callback specified, will be NULL if the + * request has failed), else undefined + * @expose + */ + ProtoBuf.protoFromFile = ProtoBuf.loadProtoFile; // Legacy + + + /** + * Constructs a new empty Builder. + * @param {Object.=} options Builder options, defaults to global options set on ProtoBuf + * @return {!ProtoBuf.Builder} Builder + * @expose + */ + ProtoBuf.newBuilder = function(options) { + options = options || {}; + if (typeof options['convertFieldsToCamelCase'] === 'undefined') + options['convertFieldsToCamelCase'] = ProtoBuf.convertFieldsToCamelCase; + if (typeof options['populateAccessors'] === 'undefined') + options['populateAccessors'] = ProtoBuf.populateAccessors; + return new ProtoBuf.Builder(options); + }; + + /** + * Loads a .json definition and returns the Builder. + * @param {!*|string} json JSON definition + * @param {(ProtoBuf.Builder|string|{root: string, file: string})=} builder Builder to append to. Will create a new one if omitted. + * @param {(string|{root: string, file: string})=} filename The corresponding file name if known. Must be specified for imports. + * @return {ProtoBuf.Builder} Builder to create new messages + * @throws {Error} If the definition cannot be parsed or built + * @expose + */ + ProtoBuf.loadJson = function(json, builder, filename) { + if (typeof builder === 'string' || (builder && typeof builder["file"] === 'string' && typeof builder["root"] === 'string')) + filename = builder, + builder = null; + if (!builder || typeof builder !== 'object') + builder = ProtoBuf.newBuilder(); + if (typeof json === 'string') + json = JSON.parse(json); + builder["import"](json, filename); + builder.resolveAll(); + return builder; + }; + + /** + * Loads a .json file and returns the Builder. + * @param {string|!{root: string, file: string}} filename Path to json file or an object specifying 'file' with + * an overridden 'root' path for all imported files. + * @param {function(?Error, !ProtoBuf.Builder=)=} callback Callback that will receive `null` as the first and + * the Builder as its second argument on success, otherwise the error as its first argument. If omitted, the + * file will be read synchronously and this function will return the Builder. + * @param {ProtoBuf.Builder=} builder Builder to append to. Will create a new one if omitted. + * @return {?ProtoBuf.Builder|undefined} The Builder if synchronous (no callback specified, will be NULL if the + * request has failed), else undefined + * @expose + */ + ProtoBuf.loadJsonFile = function(filename, callback, builder) { + if (callback && typeof callback === 'object') + builder = callback, + callback = null; + else if (!callback || typeof callback !== 'function') + callback = null; + if (callback) + return ProtoBuf.Util.fetch(typeof filename === 'string' ? filename : filename["root"]+"/"+filename["file"], function(contents) { + if (contents === null) { + callback(Error("Failed to fetch file")); + return; + } + try { + callback(null, ProtoBuf.loadJson(JSON.parse(contents), builder, filename)); + } catch (e) { + callback(e); + } + }); + var contents = ProtoBuf.Util.fetch(typeof filename === 'object' ? filename["root"]+"/"+filename["file"] : filename); + return contents === null ? null : ProtoBuf.loadJson(JSON.parse(contents), builder, filename); + }; + + return ProtoBuf; +}); (function() { 'use strict'; @@ -35191,7 +35177,7 @@ Curve25519Worker.prototype = { return curve25519.verify(pubKey, msg, sig); } }; - }; + } Internal.Curve = wrapCurve25519(Internal.curve25519); Internal.Curve.async = wrapCurve25519(Internal.curve25519_async); @@ -35222,21 +35208,8 @@ Curve25519Worker.prototype = { })(); -/* vim: ts=4:sw=4 - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ +/* vim: ts=4:sw=4 */ + var Internal = Internal || {}; (function() { @@ -35363,63 +35336,21 @@ var Internal = Internal || {}; })(); -/* vim: ts=4:sw=4 - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . +/* + * vim: ts=4:sw=4 */ var util = (function() { 'use strict'; - var StaticByteBufferProto = new dcodeIO.ByteBuffer().__proto__; var StaticArrayBufferProto = new ArrayBuffer().__proto__; - var StaticUint8ArrayProto = new Uint8Array().__proto__; - - function stringObject(thing) { - if (typeof thing === 'string') { - return thing; - } - if (thing === Object(thing)) { - if (thing.__proto__ == StaticUint8ArrayProto) { - return String.fromCharCode.apply(null, thing); - } - if (thing.__proto__ == StaticArrayBufferProto) { - return stringObject(new Uint8Array(thing)); - } - if (thing.__proto__ == StaticByteBufferProto) { - return thing.toString('binary'); - } - } - throw new Error('unsure how to stringify object of type ' + typeof thing); - } return { toString: function(thing) { if (typeof thing == 'string') { return thing; - } else if (util.isStringable(thing)) { - return util.stringObject(thing); - } else { - throw new Error("Unsure how to convert object to string from type " + typeof thing); } - }, - stringObject: stringObject, - isStringable: function (thing) { - return (thing === Object(thing) && - (thing.__proto__ == StaticArrayBufferProto || - thing.__proto__ == StaticUint8ArrayProto || - thing.__proto__ == StaticByteBufferProto)); + return new dcodeIO.ByteBuffer.wrap(thing).toString('binary'); }, toArrayBuffer: function(thing) { if (thing === undefined) { @@ -35429,42 +35360,23 @@ var util = (function() { if (thing.__proto__ == StaticArrayBufferProto) { return thing; } - //TODO: Several more cases here... - } - - if (thing instanceof Array) { - // Assuming Uint16Array from curve25519 - //TODO: Move to convertToArrayBuffer - var res = new ArrayBuffer(thing.length * 2); - var uint = new Uint16Array(res); - for (var i = 0; i < thing.length; i++) { - uint[i] = thing[i]; - } - return res; } var str; - if (util.isStringable(thing)) { - str = util.stringObject(thing); - } else if (typeof thing == "string") { + if (typeof thing == "string") { str = thing; } else { - throw new Error("Tried to convert a non-stringable thing of type " + typeof thing + " to an array buffer"); + throw new Error("Tried to convert a non-string of type " + typeof thing + " to an array buffer"); } - var res = new ArrayBuffer(str.length); - var uint = new Uint8Array(res); - for (var i = 0; i < str.length; i++) { - uint[i] = str.charCodeAt(i); - } - return res; + return new dcodeIO.ByteBuffer.wrap(thing, 'binary').toArrayBuffer(); }, isEqual: function(a, b) { // TODO: Special-case arraybuffers, etc if (a === undefined || b === undefined) { return false; } - a = stringObject(a); - b = stringObject(b); + a = util.toString(a); + b = util.toString(b); var maxLength = Math.max(a.length, b.length); if (maxLength < 5) { throw new Error("a/b compare too short"); @@ -35559,21 +35471,7 @@ Internal.protoText = function() { return protoText; }(); -/* vim: ts=4:sw=4 - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ +/* vim: ts=4:sw=4 */ var Internal = Internal || {}; Internal.protobuf = function() { @@ -35581,7 +35479,7 @@ Internal.protobuf = function() { function loadProtoBufs(filename) { return dcodeIO.ProtoBuf.loadProto(Internal.protoText['protos/' + filename]).build('textsecure'); - }; + } var protocolMessages = loadProtoBufs('WhisperTextProtocol.proto'); @@ -35591,44 +35489,50 @@ Internal.protobuf = function() { }; }(); -/* vim: ts=4:sw=4 - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ +/* vim: ts=4:sw=4 */ var Internal = Internal || {}; +Internal.BaseKeyType = { + OURS: 1, + THEIRS: 2 +}; +Internal.ChainType = { + SENDING: 1, + RECEIVING: 2 +}; + Internal.SessionRecord = function() { 'use strict'; var MESSAGE_LOST_THRESHOLD_MS = 1000*60*60*24*7; + + var StaticByteBufferProto = new dcodeIO.ByteBuffer().__proto__; + var StaticArrayBufferProto = new ArrayBuffer().__proto__; + var StaticUint8ArrayProto = new Uint8Array().__proto__; + + function isStringable(thing) { + return (thing === Object(thing) && + (thing.__proto__ == StaticArrayBufferProto || + thing.__proto__ == StaticUint8ArrayProto || + thing.__proto__ == StaticByteBufferProto)); + } function ensureStringed(thing) { if (typeof thing == "string" || typeof thing == "number" || typeof thing == "boolean") { return thing; - } else if (util.isStringable(thing)) { - return util.stringObject(thing); + } else if (isStringable(thing)) { + return util.toString(thing); } else if (thing instanceof Array) { - var res = []; + var array = []; for (var i = 0; i < thing.length; i++) { - res[i] = ensureStringed(thing[i]); + array[i] = ensureStringed(thing[i]); } - return res; + return array; } else if (thing === Object(thing)) { - var res = {}; + var obj = {}; for (var key in thing) { - res[key] = ensureStringed(thing[key]); + obj[key] = ensureStringed(thing[key]); } - return res; + return obj; } else if (thing === null) { return null; } else { @@ -35680,19 +35584,12 @@ Internal.SessionRecord = function() { }, getSessionByBaseKey: function(baseKey) { - return this._sessions[util.toString(baseKey)]; - }, - getSessionOrIdentityKeyByBaseKey: function(baseKey) { - var preferredSession = this.getSessionByBaseKey(baseKey); - if (preferredSession !== undefined) { - return preferredSession; + var session = this._sessions[util.toString(baseKey)]; + if (session && session.indexInfo.baseKeyType === Internal.BaseKeyType.OURS) { + console.log("Tried to lookup a session using our basekey"); + return undefined; } - - if (this.identityKey !== undefined) { - return { indexInfo: { remoteIdentityKey: this.identityKey } }; - } - - throw new Error("Datastore inconsistency: device was stored without identity key"); + return session; }, getSessionByRemoteEphemeralKey: function(remoteEphemeralKey) { this.detectDuplicateOpenSessions(); @@ -35700,7 +35597,7 @@ Internal.SessionRecord = function() { var searchKey = util.toString(remoteEphemeralKey); - var openSession = undefined; + var openSession; for (var key in sessions) { if (sessions[key].indexInfo.closed == -1) { openSession = sessions[key]; @@ -35731,7 +35628,7 @@ Internal.SessionRecord = function() { return undefined; }, detectDuplicateOpenSessions: function() { - var openSession = undefined; + var openSession; var sessions = this._sessions; for (var key in sessions) { if (sessions[key].indexInfo.closed == -1) { @@ -35801,8 +35698,8 @@ Internal.SessionRecord = function() { } } // Delete current root key and our ephemeral key pair to disallow ratchet stepping - delete session.currentRatchet['rootKey']; - delete session.currentRatchet['ephemeralKeyPair']; + delete session.currentRatchet.rootKey; + delete session.currentRatchet.ephemeralKeyPair; session.indexInfo.closed = Date.now(); this.removeOldChains(session); }, @@ -36061,6 +35958,7 @@ SessionBuilder.prototype = { // otherwise we figure it out when we first maybeStepRatchet with the remote's ephemeral key if (isInitiator) { session.indexInfo.baseKey = ourEphemeralKey.pubKey; + session.indexInfo.baseKeyType = Internal.BaseKeyType.OURS; return Internal.crypto.createKeyPair().then(function(ourSendingEphemeralKey) { session.currentRatchet.ephemeralKeyPair = ourSendingEphemeralKey; return this.calculateSendingRatchet(session, theirSignedPubKey).then(function() { @@ -36069,6 +35967,7 @@ SessionBuilder.prototype = { }.bind(this)); } else { session.indexInfo.baseKey = theirEphemeralPubKey; + session.indexInfo.baseKeyType = Internal.BaseKeyType.THEIRS; session.currentRatchet.ephemeralKeyPair = ourSignedKey; return session; } @@ -36087,7 +35986,8 @@ SessionBuilder.prototype = { }).then(function(masterKey) { session[util.toString(ratchet.ephemeralKeyPair.pubKey)] = { messageKeys : {}, - chainKey : { counter : -1, key : masterKey[1] } + chainKey : { counter : -1, key : masterKey[1] }, + chainType : Internal.ChainType.SENDING }; ratchet.rootKey = masterKey[0]; }); @@ -36152,6 +36052,9 @@ SessionCipher.prototype = { session.currentRatchet.ephemeralKeyPair.pubKey ); chain = session[util.toString(msg.ephemeralKey)]; + if (chain.chainType === Internal.ChainType.RECEIVING) { + throw new Error("Tried to encrypt on a receiving chain"); + } return this.fillMessageKeys(chain, chain.chainKey.counter + 1); }.bind(this)).then(function() { @@ -36210,7 +36113,7 @@ SessionCipher.prototype = { var messageLengthWithTerminator = messageLength + 1; var messagePartCount = Math.floor(messageLengthWithTerminator / 160); - if (messageLengthWithTerminator % 160 != 0) { + if (messageLengthWithTerminator % 160 !== 0) { messagePartCount++; } @@ -36298,6 +36201,9 @@ SessionCipher.prototype = { return this.maybeStepRatchet(session, remoteEphemeralKey, message.previousCounter).then(function() { var chain = session[util.toString(message.ephemeralKey)]; + if (chain.chainType === Internal.ChainType.SENDING) { + throw new Error("Tried to decrypt on a sending chain"); + } return this.fillMessageKeys(chain, message.counter).then(function() { var messageKey = chain.messageKeys[message.counter]; @@ -36331,12 +36237,12 @@ SessionCipher.prototype = { plaintext.set(paddedPlaintext.subarray(0, i)); plaintext = plaintext.buffer; break; - } else if (paddedPlaintext[i] != 0x00) { + } else if (paddedPlaintext[i] !== 0x00) { throw new Error('Invalid padding'); } } - delete session['pendingPreKey']; + delete session.pendingPreKey; return plaintext; }); }, @@ -36417,7 +36323,8 @@ SessionCipher.prototype = { } session[util.toString(ephemeralPublicKey)] = { messageKeys: {}, - chainKey: { counter: -1, key: masterKey[1] } + chainKey: { counter: -1, key: masterKey[1] }, + chainType: sending ? Internal.ChainType.SENDING : Internal.ChainType.RECEIVING }; ratchet.rootKey = masterKey[0]; });