--- /dev/null
+/*\r
+ Copyright 2013 Daniel Wirtz <dcode@dcode.io>\r
+\r
+ Licensed under the Apache License, Version 2.0 (the "License");\r
+ you may not use this file except in compliance with the License.\r
+ You may obtain a copy of the License at\r
+\r
+ http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+ Unless required by applicable law or agreed to in writing, software\r
+ distributed under the License is distributed on an "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ See the License for the specific language governing permissions and\r
+ limitations under the License.\r
+ */\r
+\r
+/**\r
+ * @license protobuf.js (c) 2013 Daniel Wirtz <dcode@dcode.io>\r
+ * Released under the Apache License, Version 2.0\r
+ * see: https://github.com/dcodeIO/protobuf.js for details\r
+ */\r
+(function(global, factory) {\r
+\r
+ /* AMD */ if (typeof define === 'function' && define["amd"])\r
+ define(["bytebuffer"], factory);\r
+ /* CommonJS */ else if (typeof require === "function" && typeof module === "object" && module && module["exports"])\r
+ module["exports"] = factory(require("bytebuffer"), true);\r
+ /* Global */ else\r
+ (global["dcodeIO"] = global["dcodeIO"] || {})["ProtoBuf"] = factory(global["dcodeIO"]["ByteBuffer"]);\r
+\r
+})(this, function(ByteBuffer, isCommonJS) {\r
+ "use strict";\r
+\r
+ /**\r
+ * The ProtoBuf namespace.\r
+ * @exports ProtoBuf\r
+ * @namespace\r
+ * @expose\r
+ */\r
+ var ProtoBuf = {};\r
+\r
+ /**\r
+ * @type {!function(new: ByteBuffer, ...[*])}\r
+ * @expose\r
+ */\r
+ ProtoBuf.ByteBuffer = ByteBuffer;\r
+\r
+ /**\r
+ * @type {?function(new: Long, ...[*])}\r
+ * @expose\r
+ */\r
+ ProtoBuf.Long = ByteBuffer.Long || null;\r
+\r
+ /**\r
+ * ProtoBuf.js version.\r
+ * @type {string}\r
+ * @const\r
+ * @expose\r
+ */\r
+ ProtoBuf.VERSION = "5.0.3";\r
+\r
+ /**\r
+ * Wire types.\r
+ * @type {Object.<string,number>}\r
+ * @const\r
+ * @expose\r
+ */\r
+ ProtoBuf.WIRE_TYPES = {};\r
+\r
+ /**\r
+ * Varint wire type.\r
+ * @type {number}\r
+ * @expose\r
+ */\r
+ ProtoBuf.WIRE_TYPES.VARINT = 0;\r
+\r
+ /**\r
+ * Fixed 64 bits wire type.\r
+ * @type {number}\r
+ * @const\r
+ * @expose\r
+ */\r
+ ProtoBuf.WIRE_TYPES.BITS64 = 1;\r
+\r
+ /**\r
+ * Length delimited wire type.\r
+ * @type {number}\r
+ * @const\r
+ * @expose\r
+ */\r
+ ProtoBuf.WIRE_TYPES.LDELIM = 2;\r
+\r
+ /**\r
+ * Start group wire type.\r
+ * @type {number}\r
+ * @const\r
+ * @expose\r
+ */\r
+ ProtoBuf.WIRE_TYPES.STARTGROUP = 3;\r
+\r
+ /**\r
+ * End group wire type.\r
+ * @type {number}\r
+ * @const\r
+ * @expose\r
+ */\r
+ ProtoBuf.WIRE_TYPES.ENDGROUP = 4;\r
+\r
+ /**\r
+ * Fixed 32 bits wire type.\r
+ * @type {number}\r
+ * @const\r
+ * @expose\r
+ */\r
+ ProtoBuf.WIRE_TYPES.BITS32 = 5;\r
+\r
+ /**\r
+ * Packable wire types.\r
+ * @type {!Array.<number>}\r
+ * @const\r
+ * @expose\r
+ */\r
+ ProtoBuf.PACKABLE_WIRE_TYPES = [\r
+ ProtoBuf.WIRE_TYPES.VARINT,\r
+ ProtoBuf.WIRE_TYPES.BITS64,\r
+ ProtoBuf.WIRE_TYPES.BITS32\r
+ ];\r
+\r
+ /**\r
+ * Types.\r
+ * @dict\r
+ * @type {!Object.<string,{name: string, wireType: number, defaultValue: *}>}\r
+ * @const\r
+ * @expose\r
+ */\r
+ ProtoBuf.TYPES = {\r
+ // According to the protobuf spec.\r
+ "int32": {\r
+ name: "int32",\r
+ wireType: ProtoBuf.WIRE_TYPES.VARINT,\r
+ defaultValue: 0\r
+ },\r
+ "uint32": {\r
+ name: "uint32",\r
+ wireType: ProtoBuf.WIRE_TYPES.VARINT,\r
+ defaultValue: 0\r
+ },\r
+ "sint32": {\r
+ name: "sint32",\r
+ wireType: ProtoBuf.WIRE_TYPES.VARINT,\r
+ defaultValue: 0\r
+ },\r
+ "int64": {\r
+ name: "int64",\r
+ wireType: ProtoBuf.WIRE_TYPES.VARINT,\r
+ defaultValue: ProtoBuf.Long ? ProtoBuf.Long.ZERO : undefined\r
+ },\r
+ "uint64": {\r
+ name: "uint64",\r
+ wireType: ProtoBuf.WIRE_TYPES.VARINT,\r
+ defaultValue: ProtoBuf.Long ? ProtoBuf.Long.UZERO : undefined\r
+ },\r
+ "sint64": {\r
+ name: "sint64",\r
+ wireType: ProtoBuf.WIRE_TYPES.VARINT,\r
+ defaultValue: ProtoBuf.Long ? ProtoBuf.Long.ZERO : undefined\r
+ },\r
+ "bool": {\r
+ name: "bool",\r
+ wireType: ProtoBuf.WIRE_TYPES.VARINT,\r
+ defaultValue: false\r
+ },\r
+ "double": {\r
+ name: "double",\r
+ wireType: ProtoBuf.WIRE_TYPES.BITS64,\r
+ defaultValue: 0\r
+ },\r
+ "string": {\r
+ name: "string",\r
+ wireType: ProtoBuf.WIRE_TYPES.LDELIM,\r
+ defaultValue: ""\r
+ },\r
+ "bytes": {\r
+ name: "bytes",\r
+ wireType: ProtoBuf.WIRE_TYPES.LDELIM,\r
+ defaultValue: null // overridden in the code, must be a unique instance\r
+ },\r
+ "fixed32": {\r
+ name: "fixed32",\r
+ wireType: ProtoBuf.WIRE_TYPES.BITS32,\r
+ defaultValue: 0\r
+ },\r
+ "sfixed32": {\r
+ name: "sfixed32",\r
+ wireType: ProtoBuf.WIRE_TYPES.BITS32,\r
+ defaultValue: 0\r
+ },\r
+ "fixed64": {\r
+ name: "fixed64",\r
+ wireType: ProtoBuf.WIRE_TYPES.BITS64,\r
+ defaultValue: ProtoBuf.Long ? ProtoBuf.Long.UZERO : undefined\r
+ },\r
+ "sfixed64": {\r
+ name: "sfixed64",\r
+ wireType: ProtoBuf.WIRE_TYPES.BITS64,\r
+ defaultValue: ProtoBuf.Long ? ProtoBuf.Long.ZERO : undefined\r
+ },\r
+ "float": {\r
+ name: "float",\r
+ wireType: ProtoBuf.WIRE_TYPES.BITS32,\r
+ defaultValue: 0\r
+ },\r
+ "enum": {\r
+ name: "enum",\r
+ wireType: ProtoBuf.WIRE_TYPES.VARINT,\r
+ defaultValue: 0\r
+ },\r
+ "message": {\r
+ name: "message",\r
+ wireType: ProtoBuf.WIRE_TYPES.LDELIM,\r
+ defaultValue: null\r
+ },\r
+ "group": {\r
+ name: "group",\r
+ wireType: ProtoBuf.WIRE_TYPES.STARTGROUP,\r
+ defaultValue: null\r
+ }\r
+ };\r
+\r
+ /**\r
+ * Valid map key types.\r
+ * @type {!Array.<!Object.<string,{name: string, wireType: number, defaultValue: *}>>}\r
+ * @const\r
+ * @expose\r
+ */\r
+ ProtoBuf.MAP_KEY_TYPES = [\r
+ ProtoBuf.TYPES["int32"],\r
+ ProtoBuf.TYPES["sint32"],\r
+ ProtoBuf.TYPES["sfixed32"],\r
+ ProtoBuf.TYPES["uint32"],\r
+ ProtoBuf.TYPES["fixed32"],\r
+ ProtoBuf.TYPES["int64"],\r
+ ProtoBuf.TYPES["sint64"],\r
+ ProtoBuf.TYPES["sfixed64"],\r
+ ProtoBuf.TYPES["uint64"],\r
+ ProtoBuf.TYPES["fixed64"],\r
+ ProtoBuf.TYPES["bool"],\r
+ ProtoBuf.TYPES["string"],\r
+ ProtoBuf.TYPES["bytes"]\r
+ ];\r
+\r
+ /**\r
+ * Minimum field id.\r
+ * @type {number}\r
+ * @const\r
+ * @expose\r
+ */\r
+ ProtoBuf.ID_MIN = 1;\r
+\r
+ /**\r
+ * Maximum field id.\r
+ * @type {number}\r
+ * @const\r
+ * @expose\r
+ */\r
+ ProtoBuf.ID_MAX = 0x1FFFFFFF;\r
+\r
+ /**\r
+ * If set to `true`, field names will be converted from underscore notation to camel case. Defaults to `false`.\r
+ * Must be set prior to parsing.\r
+ * @type {boolean}\r
+ * @expose\r
+ */\r
+ ProtoBuf.convertFieldsToCamelCase = false;\r
+\r
+ /**\r
+ * By default, messages are populated with (setX, set_x) accessors for each field. This can be disabled by\r
+ * setting this to `false` prior to building messages.\r
+ * @type {boolean}\r
+ * @expose\r
+ */\r
+ ProtoBuf.populateAccessors = true;\r
+\r
+ /**\r
+ * By default, messages are populated with default values if a field is not present on the wire. To disable\r
+ * this behavior, set this setting to `false`.\r
+ * @type {boolean}\r
+ * @expose\r
+ */\r
+ ProtoBuf.populateDefaults = true;\r
+\r
+ /**\r
+ * @alias ProtoBuf.Util\r
+ * @expose\r
+ */\r
+ ProtoBuf.Util = (function() {\r
+ "use strict";\r
+\r
+ /**\r
+ * ProtoBuf utilities.\r
+ * @exports ProtoBuf.Util\r
+ * @namespace\r
+ */\r
+ var Util = {};\r
+\r
+ /**\r
+ * Flag if running in node or not.\r
+ * @type {boolean}\r
+ * @const\r
+ * @expose\r
+ */\r
+ Util.IS_NODE = !!(\r
+ typeof process === 'object' && process+'' === '[object process]' && !process['browser']\r
+ );\r
+\r
+ /**\r
+ * Constructs a XMLHttpRequest object.\r
+ * @return {XMLHttpRequest}\r
+ * @throws {Error} If XMLHttpRequest is not supported\r
+ * @expose\r
+ */\r
+ Util.XHR = function() {\r
+ // No dependencies please, ref: http://www.quirksmode.org/js/xmlhttp.html\r
+ var XMLHttpFactories = [\r
+ function () {return new XMLHttpRequest()},\r
+ function () {return new ActiveXObject("Msxml2.XMLHTTP")},\r
+ function () {return new ActiveXObject("Msxml3.XMLHTTP")},\r
+ function () {return new ActiveXObject("Microsoft.XMLHTTP")}\r
+ ];\r
+ /** @type {?XMLHttpRequest} */\r
+ var xhr = null;\r
+ for (var i=0;i<XMLHttpFactories.length;i++) {\r
+ try { xhr = XMLHttpFactories[i](); }\r
+ catch (e) { continue; }\r
+ break;\r
+ }\r
+ if (!xhr)\r
+ throw Error("XMLHttpRequest is not supported");\r
+ return xhr;\r
+ };\r
+\r
+ /**\r
+ * Fetches a resource.\r
+ * @param {string} path Resource path\r
+ * @param {function(?string)=} callback Callback receiving the resource's contents. If omitted the resource will\r
+ * be fetched synchronously. If the request failed, contents will be null.\r
+ * @return {?string|undefined} Resource contents if callback is omitted (null if the request failed), else undefined.\r
+ * @expose\r
+ */\r
+ Util.fetch = function(path, callback) {\r
+ if (callback && typeof callback != 'function')\r
+ callback = null;\r
+ if (Util.IS_NODE) {\r
+ var fs = require("fs");\r
+ if (callback) {\r
+ fs.readFile(path, function(err, data) {\r
+ if (err)\r
+ callback(null);\r
+ else\r
+ callback(""+data);\r
+ });\r
+ } else\r
+ try {\r
+ return fs.readFileSync(path);\r
+ } catch (e) {\r
+ return null;\r
+ }\r
+ } else {\r
+ var xhr = Util.XHR();\r
+ xhr.open('GET', path, callback ? true : false);\r
+ // xhr.setRequestHeader('User-Agent', 'XMLHTTP/1.0');\r
+ xhr.setRequestHeader('Accept', 'text/plain');\r
+ if (typeof xhr.overrideMimeType === 'function') xhr.overrideMimeType('text/plain');\r
+ if (callback) {\r
+ xhr.onreadystatechange = function() {\r
+ if (xhr.readyState != 4) return;\r
+ if (/* remote */ xhr.status == 200 || /* local */ (xhr.status == 0 && typeof xhr.responseText === 'string'))\r
+ callback(xhr.responseText);\r
+ else\r
+ callback(null);\r
+ };\r
+ if (xhr.readyState == 4)\r
+ return;\r
+ xhr.send(null);\r
+ } else {\r
+ xhr.send(null);\r
+ if (/* remote */ xhr.status == 200 || /* local */ (xhr.status == 0 && typeof xhr.responseText === 'string'))\r
+ return xhr.responseText;\r
+ return null;\r
+ }\r
+ }\r
+ };\r
+\r
+ /**\r
+ * Converts a string to camel case.\r
+ * @param {string} str\r
+ * @returns {string}\r
+ * @expose\r
+ */\r
+ Util.toCamelCase = function(str) {\r
+ return str.replace(/_([a-zA-Z])/g, function ($0, $1) {\r
+ return $1.toUpperCase();\r
+ });\r
+ };\r
+\r
+ return Util;\r
+ })();\r
+\r
+ /**\r
+ * Language expressions.\r
+ * @type {!Object.<string,!RegExp>}\r
+ * @expose\r
+ */\r
+ ProtoBuf.Lang = {\r
+\r
+ // Characters always ending a statement\r
+ DELIM: /[\s\{\}=;:\[\],'"\(\)<>]/g,\r
+\r
+ // Field rules\r
+ RULE: /^(?:required|optional|repeated|map)$/,\r
+\r
+ // Field types\r
+ TYPE: /^(?:double|float|int32|uint32|sint32|int64|uint64|sint64|fixed32|sfixed32|fixed64|sfixed64|bool|string|bytes)$/,\r
+\r
+ // Names\r
+ NAME: /^[a-zA-Z_][a-zA-Z_0-9]*$/,\r
+\r
+ // Type definitions\r
+ TYPEDEF: /^[a-zA-Z][a-zA-Z_0-9]*$/,\r
+\r
+ // Type references\r
+ TYPEREF: /^(?:\.?[a-zA-Z_][a-zA-Z_0-9]*)(?:\.[a-zA-Z_][a-zA-Z_0-9]*)*$/,\r
+\r
+ // Fully qualified type references\r
+ FQTYPEREF: /^(?:\.[a-zA-Z_][a-zA-Z_0-9]*)+$/,\r
+\r
+ // All numbers\r
+ NUMBER: /^-?(?:[1-9][0-9]*|0|0[xX][0-9a-fA-F]+|0[0-7]+|([0-9]*(\.[0-9]*)?([Ee][+-]?[0-9]+)?)|inf|nan)$/,\r
+\r
+ // Decimal numbers\r
+ NUMBER_DEC: /^(?:[1-9][0-9]*|0)$/,\r
+\r
+ // Hexadecimal numbers\r
+ NUMBER_HEX: /^0[xX][0-9a-fA-F]+$/,\r
+\r
+ // Octal numbers\r
+ NUMBER_OCT: /^0[0-7]+$/,\r
+\r
+ // Floating point numbers\r
+ NUMBER_FLT: /^([0-9]*(\.[0-9]*)?([Ee][+-]?[0-9]+)?|inf|nan)$/,\r
+\r
+ // Booleans\r
+ BOOL: /^(?:true|false)$/i,\r
+\r
+ // Id numbers\r
+ ID: /^(?:[1-9][0-9]*|0|0[xX][0-9a-fA-F]+|0[0-7]+)$/,\r
+\r
+ // Negative id numbers (enum values)\r
+ NEGID: /^\-?(?:[1-9][0-9]*|0|0[xX][0-9a-fA-F]+|0[0-7]+)$/,\r
+\r
+ // Whitespaces\r
+ WHITESPACE: /\s/,\r
+\r
+ // All strings\r
+ STRING: /(?:"([^"\\]*(?:\\.[^"\\]*)*)")|(?:'([^'\\]*(?:\\.[^'\\]*)*)')/g,\r
+\r
+ // Double quoted strings\r
+ STRING_DQ: /(?:"([^"\\]*(?:\\.[^"\\]*)*)")/g,\r
+\r
+ // Single quoted strings\r
+ STRING_SQ: /(?:'([^'\\]*(?:\\.[^'\\]*)*)')/g\r
+ };\r
+\r
+ /**\r
+ * @alias ProtoBuf.DotProto\r
+ * @expose\r
+ */\r
+ ProtoBuf.DotProto = (function(ProtoBuf, Lang) {\r
+ "use strict";\r
+\r
+ /**\r
+ * Utilities to parse .proto files.\r
+ * @exports ProtoBuf.DotProto\r
+ * @namespace\r
+ */\r
+ var DotProto = {};\r
+\r
+ /**\r
+ * Constructs a new Tokenizer.\r
+ * @exports ProtoBuf.DotProto.Tokenizer\r
+ * @class prototype tokenizer\r
+ * @param {string} proto Proto to tokenize\r
+ * @constructor\r
+ */\r
+ var Tokenizer = function(proto) {\r
+\r
+ /**\r
+ * Source to parse.\r
+ * @type {string}\r
+ * @expose\r
+ */\r
+ this.source = proto+"";\r
+\r
+ /**\r
+ * Current index.\r
+ * @type {number}\r
+ * @expose\r
+ */\r
+ this.index = 0;\r
+\r
+ /**\r
+ * Current line.\r
+ * @type {number}\r
+ * @expose\r
+ */\r
+ this.line = 1;\r
+\r
+ /**\r
+ * Token stack.\r
+ * @type {!Array.<string>}\r
+ * @expose\r
+ */\r
+ this.stack = [];\r
+\r
+ /**\r
+ * Opening character of the current string read, if any.\r
+ * @type {?string}\r
+ * @private\r
+ */\r
+ this._stringOpen = null;\r
+ };\r
+\r
+ /**\r
+ * @alias ProtoBuf.DotProto.Tokenizer.prototype\r
+ * @inner\r
+ */\r
+ var TokenizerPrototype = Tokenizer.prototype;\r
+\r
+ /**\r
+ * Reads a string beginning at the current index.\r
+ * @return {string}\r
+ * @private\r
+ */\r
+ TokenizerPrototype._readString = function() {\r
+ var re = this._stringOpen === '"'\r
+ ? Lang.STRING_DQ\r
+ : Lang.STRING_SQ;\r
+ re.lastIndex = this.index - 1; // Include the open quote\r
+ var match = re.exec(this.source);\r
+ if (!match)\r
+ throw Error("unterminated string");\r
+ this.index = re.lastIndex;\r
+ this.stack.push(this._stringOpen);\r
+ this._stringOpen = null;\r
+ return match[1];\r
+ };\r
+\r
+ /**\r
+ * Gets the next token and advances by one.\r
+ * @return {?string} Token or `null` on EOF\r
+ * @expose\r
+ */\r
+ TokenizerPrototype.next = function() {\r
+ if (this.stack.length > 0)\r
+ return this.stack.shift();\r
+ if (this.index >= this.source.length)\r
+ return null;\r
+ if (this._stringOpen !== null)\r
+ return this._readString();\r
+\r
+ var repeat,\r
+ prev,\r
+ next;\r
+ do {\r
+ repeat = false;\r
+\r
+ // Strip white spaces\r
+ while (Lang.WHITESPACE.test(next = this.source.charAt(this.index))) {\r
+ if (next === '\n')\r
+ ++this.line;\r
+ if (++this.index === this.source.length)\r
+ return null;\r
+ }\r
+\r
+ // Strip comments\r
+ if (this.source.charAt(this.index) === '/') {\r
+ ++this.index;\r
+ if (this.source.charAt(this.index) === '/') { // Line\r
+ while (this.source.charAt(++this.index) !== '\n')\r
+ if (this.index == this.source.length)\r
+ return null;\r
+ ++this.index;\r
+ ++this.line;\r
+ repeat = true;\r
+ } else if ((next = this.source.charAt(this.index)) === '*') { /* Block */\r
+ do {\r
+ if (next === '\n')\r
+ ++this.line;\r
+ if (++this.index === this.source.length)\r
+ return null;\r
+ prev = next;\r
+ next = this.source.charAt(this.index);\r
+ } while (prev !== '*' || next !== '/');\r
+ ++this.index;\r
+ repeat = true;\r
+ } else\r
+ return '/';\r
+ }\r
+ } while (repeat);\r
+\r
+ if (this.index === this.source.length)\r
+ return null;\r
+\r
+ // Read the next token\r
+ var end = this.index;\r
+ Lang.DELIM.lastIndex = 0;\r
+ var delim = Lang.DELIM.test(this.source.charAt(end++));\r
+ if (!delim)\r
+ while(end < this.source.length && !Lang.DELIM.test(this.source.charAt(end)))\r
+ ++end;\r
+ var token = this.source.substring(this.index, this.index = end);\r
+ if (token === '"' || token === "'")\r
+ this._stringOpen = token;\r
+ return token;\r
+ };\r
+\r
+ /**\r
+ * Peeks for the next token.\r
+ * @return {?string} Token or `null` on EOF\r
+ * @expose\r
+ */\r
+ TokenizerPrototype.peek = function() {\r
+ if (this.stack.length === 0) {\r
+ var token = this.next();\r
+ if (token === null)\r
+ return null;\r
+ this.stack.push(token);\r
+ }\r
+ return this.stack[0];\r
+ };\r
+\r
+ /**\r
+ * Skips a specific token and throws if it differs.\r
+ * @param {string} expected Expected token\r
+ * @throws {Error} If the actual token differs\r
+ */\r
+ TokenizerPrototype.skip = function(expected) {\r
+ var actual = this.next();\r
+ if (actual !== expected)\r
+ throw Error("illegal '"+actual+"', '"+expected+"' expected");\r
+ };\r
+\r
+ /**\r
+ * Omits an optional token.\r
+ * @param {string} expected Expected optional token\r
+ * @returns {boolean} `true` if the token exists\r
+ */\r
+ TokenizerPrototype.omit = function(expected) {\r
+ if (this.peek() === expected) {\r
+ this.next();\r
+ return true;\r
+ }\r
+ return false;\r
+ };\r
+\r
+ /**\r
+ * Returns a string representation of this object.\r
+ * @return {string} String representation as of "Tokenizer(index/length)"\r
+ * @expose\r
+ */\r
+ TokenizerPrototype.toString = function() {\r
+ return "Tokenizer ("+this.index+"/"+this.source.length+" at line "+this.line+")";\r
+ };\r
+\r
+ /**\r
+ * @alias ProtoBuf.DotProto.Tokenizer\r
+ * @expose\r
+ */\r
+ DotProto.Tokenizer = Tokenizer;\r
+\r
+ /**\r
+ * Constructs a new Parser.\r
+ * @exports ProtoBuf.DotProto.Parser\r
+ * @class prototype parser\r
+ * @param {string} source Source\r
+ * @constructor\r
+ */\r
+ var Parser = function(source) {\r
+\r
+ /**\r
+ * Tokenizer.\r
+ * @type {!ProtoBuf.DotProto.Tokenizer}\r
+ * @expose\r
+ */\r
+ this.tn = new Tokenizer(source);\r
+\r
+ /**\r
+ * Whether parsing proto3 or not.\r
+ * @type {boolean}\r
+ */\r
+ this.proto3 = false;\r
+ };\r
+\r
+ /**\r
+ * @alias ProtoBuf.DotProto.Parser.prototype\r
+ * @inner\r
+ */\r
+ var ParserPrototype = Parser.prototype;\r
+\r
+ /**\r
+ * Parses the source.\r
+ * @returns {!Object}\r
+ * @throws {Error} If the source cannot be parsed\r
+ * @expose\r
+ */\r
+ ParserPrototype.parse = function() {\r
+ var topLevel = {\r
+ "name": "[ROOT]", // temporary\r
+ "package": null,\r
+ "messages": [],\r
+ "enums": [],\r
+ "imports": [],\r
+ "options": {},\r
+ "services": []\r
+ // "syntax": undefined\r
+ };\r
+ var token,\r
+ head = true,\r
+ weak;\r
+ try {\r
+ while (token = this.tn.next()) {\r
+ switch (token) {\r
+ case 'package':\r
+ if (!head || topLevel["package"] !== null)\r
+ throw Error("unexpected 'package'");\r
+ token = this.tn.next();\r
+ if (!Lang.TYPEREF.test(token))\r
+ throw Error("illegal package name: " + token);\r
+ this.tn.skip(";");\r
+ topLevel["package"] = token;\r
+ break;\r
+ case 'import':\r
+ if (!head)\r
+ throw Error("unexpected 'import'");\r
+ token = this.tn.peek();\r
+ if (token === "public" || (weak = token === "weak")) // token ignored\r
+ this.tn.next();\r
+ token = this._readString();\r
+ this.tn.skip(";");\r
+ if (!weak) // import ignored\r
+ topLevel["imports"].push(token);\r
+ break;\r
+ case 'syntax':\r
+ if (!head)\r
+ throw Error("unexpected 'syntax'");\r
+ this.tn.skip("=");\r
+ if ((topLevel["syntax"] = this._readString()) === "proto3")\r
+ this.proto3 = true;\r
+ this.tn.skip(";");\r
+ break;\r
+ case 'message':\r
+ this._parseMessage(topLevel, null);\r
+ head = false;\r
+ break;\r
+ case 'enum':\r
+ this._parseEnum(topLevel);\r
+ head = false;\r
+ break;\r
+ case 'option':\r
+ this._parseOption(topLevel);\r
+ break;\r
+ case 'service':\r
+ this._parseService(topLevel);\r
+ break;\r
+ case 'extend':\r
+ this._parseExtend(topLevel);\r
+ break;\r
+ default:\r
+ throw Error("unexpected '" + token + "'");\r
+ }\r
+ }\r
+ } catch (e) {\r
+ e.message = "Parse error at line "+this.tn.line+": " + e.message;\r
+ throw e;\r
+ }\r
+ delete topLevel["name"];\r
+ return topLevel;\r
+ };\r
+\r
+ /**\r
+ * Parses the specified source.\r
+ * @returns {!Object}\r
+ * @throws {Error} If the source cannot be parsed\r
+ * @expose\r
+ */\r
+ Parser.parse = function(source) {\r
+ return new Parser(source).parse();\r
+ };\r
+\r
+ // ----- Conversion ------\r
+\r
+ /**\r
+ * Converts a numerical string to an id.\r
+ * @param {string} value\r
+ * @param {boolean=} mayBeNegative\r
+ * @returns {number}\r
+ * @inner\r
+ */\r
+ function mkId(value, mayBeNegative) {\r
+ var id = -1,\r
+ sign = 1;\r
+ if (value.charAt(0) == '-') {\r
+ sign = -1;\r
+ value = value.substring(1);\r
+ }\r
+ if (Lang.NUMBER_DEC.test(value))\r
+ id = parseInt(value);\r
+ else if (Lang.NUMBER_HEX.test(value))\r
+ id = parseInt(value.substring(2), 16);\r
+ else if (Lang.NUMBER_OCT.test(value))\r
+ id = parseInt(value.substring(1), 8);\r
+ else\r
+ throw Error("illegal id value: " + (sign < 0 ? '-' : '') + value);\r
+ id = (sign*id)|0; // Force to 32bit\r
+ if (!mayBeNegative && id < 0)\r
+ throw Error("illegal id value: " + (sign < 0 ? '-' : '') + value);\r
+ return id;\r
+ }\r
+\r
+ /**\r
+ * Converts a numerical string to a number.\r
+ * @param {string} val\r
+ * @returns {number}\r
+ * @inner\r
+ */\r
+ function mkNumber(val) {\r
+ var sign = 1;\r
+ if (val.charAt(0) == '-') {\r
+ sign = -1;\r
+ val = val.substring(1);\r
+ }\r
+ if (Lang.NUMBER_DEC.test(val))\r
+ return sign * parseInt(val, 10);\r
+ else if (Lang.NUMBER_HEX.test(val))\r
+ return sign * parseInt(val.substring(2), 16);\r
+ else if (Lang.NUMBER_OCT.test(val))\r
+ return sign * parseInt(val.substring(1), 8);\r
+ else if (val === 'inf')\r
+ return sign * Infinity;\r
+ else if (val === 'nan')\r
+ return NaN;\r
+ else if (Lang.NUMBER_FLT.test(val))\r
+ return sign * parseFloat(val);\r
+ throw Error("illegal number value: " + (sign < 0 ? '-' : '') + val);\r
+ }\r
+\r
+ // ----- Reading ------\r
+\r
+ /**\r
+ * Reads a string.\r
+ * @returns {string}\r
+ * @private\r
+ */\r
+ ParserPrototype._readString = function() {\r
+ var value = "",\r
+ token,\r
+ delim;\r
+ do {\r
+ delim = this.tn.next();\r
+ if (delim !== "'" && delim !== '"')\r
+ throw Error("illegal string delimiter: "+delim);\r
+ value += this.tn.next();\r
+ this.tn.skip(delim);\r
+ token = this.tn.peek();\r
+ } while (token === '"' || token === '"'); // multi line?\r
+ return value;\r
+ };\r
+\r
+ /**\r
+ * Reads a value.\r
+ * @param {boolean=} mayBeTypeRef\r
+ * @returns {number|boolean|string}\r
+ * @private\r
+ */\r
+ ParserPrototype._readValue = function(mayBeTypeRef) {\r
+ var token = this.tn.peek(),\r
+ value;\r
+ if (token === '"' || token === "'")\r
+ return this._readString();\r
+ this.tn.next();\r
+ if (Lang.NUMBER.test(token))\r
+ return mkNumber(token);\r
+ if (Lang.BOOL.test(token))\r
+ return (token.toLowerCase() === 'true');\r
+ if (mayBeTypeRef && Lang.TYPEREF.test(token))\r
+ return token;\r
+ throw Error("illegal value: "+token);\r
+\r
+ };\r
+\r
+ // ----- Parsing constructs -----\r
+\r
+ /**\r
+ * Parses a namespace option.\r
+ * @param {!Object} parent Parent definition\r
+ * @param {boolean=} isList\r
+ * @private\r
+ */\r
+ ParserPrototype._parseOption = function(parent, isList) {\r
+ var token = this.tn.next(),\r
+ custom = false;\r
+ if (token === '(') {\r
+ custom = true;\r
+ token = this.tn.next();\r
+ }\r
+ if (!Lang.TYPEREF.test(token))\r
+ // we can allow options of the form google.protobuf.* since they will just get ignored anyways\r
+ // if (!/google\.protobuf\./.test(token)) // FIXME: Why should that not be a valid typeref?\r
+ throw Error("illegal option name: "+token);\r
+ var name = token;\r
+ if (custom) { // (my_method_option).foo, (my_method_option), some_method_option, (foo.my_option).bar\r
+ this.tn.skip(')');\r
+ name = '('+name+')';\r
+ token = this.tn.peek();\r
+ if (Lang.FQTYPEREF.test(token)) {\r
+ name += token;\r
+ this.tn.next();\r
+ }\r
+ }\r
+ this.tn.skip('=');\r
+ this._parseOptionValue(parent, name);\r
+ if (!isList)\r
+ this.tn.skip(";");\r
+ };\r
+\r
+ /**\r
+ * Sets an option on the specified options object.\r
+ * @param {!Object.<string,*>} options\r
+ * @param {string} name\r
+ * @param {string|number|boolean} value\r
+ * @inner\r
+ */\r
+ function setOption(options, name, value) {\r
+ if (typeof options[name] === 'undefined')\r
+ options[name] = value;\r
+ else {\r
+ if (!Array.isArray(options[name]))\r
+ options[name] = [ options[name] ];\r
+ options[name].push(value);\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Parses an option value.\r
+ * @param {!Object} parent\r
+ * @param {string} name\r
+ * @private\r
+ */\r
+ ParserPrototype._parseOptionValue = function(parent, name) {\r
+ var token = this.tn.peek();\r
+ if (token !== '{') { // Plain value\r
+ setOption(parent["options"], name, this._readValue(true));\r
+ } else { // Aggregate options\r
+ this.tn.skip("{");\r
+ while ((token = this.tn.next()) !== '}') {\r
+ if (!Lang.NAME.test(token))\r
+ throw Error("illegal option name: " + name + "." + token);\r
+ if (this.tn.omit(":"))\r
+ setOption(parent["options"], name + "." + token, this._readValue(true));\r
+ else\r
+ this._parseOptionValue(parent, name + "." + token);\r
+ }\r
+ }\r
+ };\r
+\r
+ /**\r
+ * Parses a service definition.\r
+ * @param {!Object} parent Parent definition\r
+ * @private\r
+ */\r
+ ParserPrototype._parseService = function(parent) {\r
+ var token = this.tn.next();\r
+ if (!Lang.NAME.test(token))\r
+ throw Error("illegal service name at line "+this.tn.line+": "+token);\r
+ var name = token;\r
+ var svc = {\r
+ "name": name,\r
+ "rpc": {},\r
+ "options": {}\r
+ };\r
+ this.tn.skip("{");\r
+ while ((token = this.tn.next()) !== '}') {\r
+ if (token === "option")\r
+ this._parseOption(svc);\r
+ else if (token === 'rpc')\r
+ this._parseServiceRPC(svc);\r
+ else\r
+ throw Error("illegal service token: "+token);\r
+ }\r
+ this.tn.omit(";");\r
+ parent["services"].push(svc);\r
+ };\r
+\r
+ /**\r
+ * Parses a RPC service definition of the form ['rpc', name, (request), 'returns', (response)].\r
+ * @param {!Object} svc Service definition\r
+ * @private\r
+ */\r
+ ParserPrototype._parseServiceRPC = function(svc) {\r
+ var type = "rpc",\r
+ token = this.tn.next();\r
+ if (!Lang.NAME.test(token))\r
+ throw Error("illegal rpc service method name: "+token);\r
+ var name = token;\r
+ var method = {\r
+ "request": null,\r
+ "response": null,\r
+ "request_stream": false,\r
+ "response_stream": false,\r
+ "options": {}\r
+ };\r
+ this.tn.skip("(");\r
+ token = this.tn.next();\r
+ if (token.toLowerCase() === "stream") {\r
+ method["request_stream"] = true;\r
+ token = this.tn.next();\r
+ }\r
+ if (!Lang.TYPEREF.test(token))\r
+ throw Error("illegal rpc service request type: "+token);\r
+ method["request"] = token;\r
+ this.tn.skip(")");\r
+ token = this.tn.next();\r
+ if (token.toLowerCase() !== "returns")\r
+ throw Error("illegal rpc service request type delimiter: "+token);\r
+ this.tn.skip("(");\r
+ token = this.tn.next();\r
+ if (token.toLowerCase() === "stream") {\r
+ method["response_stream"] = true;\r
+ token = this.tn.next();\r
+ }\r
+ method["response"] = token;\r
+ this.tn.skip(")");\r
+ token = this.tn.peek();\r
+ if (token === '{') {\r
+ this.tn.next();\r
+ while ((token = this.tn.next()) !== '}') {\r
+ if (token === 'option')\r
+ this._parseOption(method);\r
+ else\r
+ throw Error("illegal rpc service token: " + token);\r
+ }\r
+ this.tn.omit(";");\r
+ } else\r
+ this.tn.skip(";");\r
+ if (typeof svc[type] === 'undefined')\r
+ svc[type] = {};\r
+ svc[type][name] = method;\r
+ };\r
+\r
+ /**\r
+ * Parses a message definition.\r
+ * @param {!Object} parent Parent definition\r
+ * @param {!Object=} fld Field definition if this is a group\r
+ * @returns {!Object}\r
+ * @private\r
+ */\r
+ ParserPrototype._parseMessage = function(parent, fld) {\r
+ var isGroup = !!fld,\r
+ token = this.tn.next();\r
+ var msg = {\r
+ "name": "",\r
+ "fields": [],\r
+ "enums": [],\r
+ "messages": [],\r
+ "options": {},\r
+ "services": [],\r
+ "oneofs": {}\r
+ // "extensions": undefined\r
+ };\r
+ if (!Lang.NAME.test(token))\r
+ throw Error("illegal "+(isGroup ? "group" : "message")+" name: "+token);\r
+ msg["name"] = token;\r
+ if (isGroup) {\r
+ this.tn.skip("=");\r
+ fld["id"] = mkId(this.tn.next());\r
+ msg["isGroup"] = true;\r
+ }\r
+ token = this.tn.peek();\r
+ if (token === '[' && fld)\r
+ this._parseFieldOptions(fld);\r
+ this.tn.skip("{");\r
+ while ((token = this.tn.next()) !== '}') {\r
+ if (Lang.RULE.test(token))\r
+ this._parseMessageField(msg, token);\r
+ else if (token === "oneof")\r
+ this._parseMessageOneOf(msg);\r
+ else if (token === "enum")\r
+ this._parseEnum(msg);\r
+ else if (token === "message")\r
+ this._parseMessage(msg);\r
+ else if (token === "option")\r
+ this._parseOption(msg);\r
+ else if (token === "service")\r
+ this._parseService(msg);\r
+ else if (token === "extensions")\r
+ if (msg.hasOwnProperty("extensions")) {\r
+ msg["extensions"] = msg["extensions"].concat(this._parseExtensionRanges())\r
+ } else {\r
+ msg["extensions"] = this._parseExtensionRanges();\r
+ }\r
+ else if (token === "reserved")\r
+ this._parseIgnored(); // TODO\r
+ else if (token === "extend")\r
+ this._parseExtend(msg);\r
+ else if (Lang.TYPEREF.test(token)) {\r
+ if (!this.proto3)\r
+ throw Error("illegal field rule: "+token);\r
+ this._parseMessageField(msg, "optional", token);\r
+ } else\r
+ throw Error("illegal message token: "+token);\r
+ }\r
+ this.tn.omit(";");\r
+ parent["messages"].push(msg);\r
+ return msg;\r
+ };\r
+\r
+ /**\r
+ * Parses an ignored statement.\r
+ * @private\r
+ */\r
+ ParserPrototype._parseIgnored = function() {\r
+ while (this.tn.peek() !== ';')\r
+ this.tn.next();\r
+ this.tn.skip(";");\r
+ };\r
+\r
+ /**\r
+ * Parses a message field.\r
+ * @param {!Object} msg Message definition\r
+ * @param {string} rule Field rule\r
+ * @param {string=} type Field type if already known (never known for maps)\r
+ * @returns {!Object} Field descriptor\r
+ * @private\r
+ */\r
+ ParserPrototype._parseMessageField = function(msg, rule, type) {\r
+ if (!Lang.RULE.test(rule))\r
+ throw Error("illegal message field rule: "+rule);\r
+ var fld = {\r
+ "rule": rule,\r
+ "type": "",\r
+ "name": "",\r
+ "options": {},\r
+ "id": 0\r
+ };\r
+ var token;\r
+ if (rule === "map") {\r
+\r
+ if (type)\r
+ throw Error("illegal type: " + type);\r
+ this.tn.skip('<');\r
+ token = this.tn.next();\r
+ if (!Lang.TYPE.test(token) && !Lang.TYPEREF.test(token))\r
+ throw Error("illegal message field type: " + token);\r
+ fld["keytype"] = token;\r
+ this.tn.skip(',');\r
+ token = this.tn.next();\r
+ if (!Lang.TYPE.test(token) && !Lang.TYPEREF.test(token))\r
+ throw Error("illegal message field: " + token);\r
+ fld["type"] = token;\r
+ this.tn.skip('>');\r
+ token = this.tn.next();\r
+ if (!Lang.NAME.test(token))\r
+ throw Error("illegal message field name: " + token);\r
+ fld["name"] = token;\r
+ this.tn.skip("=");\r
+ fld["id"] = mkId(this.tn.next());\r
+ token = this.tn.peek();\r
+ if (token === '[')\r
+ this._parseFieldOptions(fld);\r
+ this.tn.skip(";");\r
+\r
+ } else {\r
+\r
+ type = typeof type !== 'undefined' ? type : this.tn.next();\r
+\r
+ if (type === "group") {\r
+\r
+ // "A [legacy] group simply combines a nested message type and a field into a single declaration. In your\r
+ // code, you can treat this message just as if it had a Result type field called result (the latter name is\r
+ // converted to lower-case so that it does not conflict with the former)."\r
+ var grp = this._parseMessage(msg, fld);\r
+ if (!/^[A-Z]/.test(grp["name"]))\r
+ throw Error('illegal group name: '+grp["name"]);\r
+ fld["type"] = grp["name"];\r
+ fld["name"] = grp["name"].toLowerCase();\r
+ this.tn.omit(";");\r
+\r
+ } else {\r
+\r
+ if (!Lang.TYPE.test(type) && !Lang.TYPEREF.test(type))\r
+ throw Error("illegal message field type: " + type);\r
+ fld["type"] = type;\r
+ token = this.tn.next();\r
+ if (!Lang.NAME.test(token))\r
+ throw Error("illegal message field name: " + token);\r
+ fld["name"] = token;\r
+ this.tn.skip("=");\r
+ fld["id"] = mkId(this.tn.next());\r
+ token = this.tn.peek();\r
+ if (token === "[")\r
+ this._parseFieldOptions(fld);\r
+ this.tn.skip(";");\r
+\r
+ }\r
+ }\r
+ msg["fields"].push(fld);\r
+ return fld;\r
+ };\r
+\r
+ /**\r
+ * Parses a message oneof.\r
+ * @param {!Object} msg Message definition\r
+ * @private\r
+ */\r
+ ParserPrototype._parseMessageOneOf = function(msg) {\r
+ var token = this.tn.next();\r
+ if (!Lang.NAME.test(token))\r
+ throw Error("illegal oneof name: "+token);\r
+ var name = token,\r
+ fld;\r
+ var fields = [];\r
+ this.tn.skip("{");\r
+ while ((token = this.tn.next()) !== "}") {\r
+ fld = this._parseMessageField(msg, "optional", token);\r
+ fld["oneof"] = name;\r
+ fields.push(fld["id"]);\r
+ }\r
+ this.tn.omit(";");\r
+ msg["oneofs"][name] = fields;\r
+ };\r
+\r
+ /**\r
+ * Parses a set of field option definitions.\r
+ * @param {!Object} fld Field definition\r
+ * @private\r
+ */\r
+ ParserPrototype._parseFieldOptions = function(fld) {\r
+ this.tn.skip("[");\r
+ var token,\r
+ first = true;\r
+ while ((token = this.tn.peek()) !== ']') {\r
+ if (!first)\r
+ this.tn.skip(",");\r
+ this._parseOption(fld, true);\r
+ first = false;\r
+ }\r
+ this.tn.next();\r
+ };\r
+\r
+ /**\r
+ * Parses an enum.\r
+ * @param {!Object} msg Message definition\r
+ * @private\r
+ */\r
+ ParserPrototype._parseEnum = function(msg) {\r
+ var enm = {\r
+ "name": "",\r
+ "values": [],\r
+ "options": {}\r
+ };\r
+ var token = this.tn.next();\r
+ if (!Lang.NAME.test(token))\r
+ throw Error("illegal name: "+token);\r
+ enm["name"] = token;\r
+ this.tn.skip("{");\r
+ while ((token = this.tn.next()) !== '}') {\r
+ if (token === "option")\r
+ this._parseOption(enm);\r
+ else {\r
+ if (!Lang.NAME.test(token))\r
+ throw Error("illegal name: "+token);\r
+ this.tn.skip("=");\r
+ var val = {\r
+ "name": token,\r
+ "id": mkId(this.tn.next(), true)\r
+ };\r
+ token = this.tn.peek();\r
+ if (token === "[")\r
+ this._parseFieldOptions({ "options": {} });\r
+ this.tn.skip(";");\r
+ enm["values"].push(val);\r
+ }\r
+ }\r
+ this.tn.omit(";");\r
+ msg["enums"].push(enm);\r
+ };\r
+\r
+ /**\r
+ * Parses extension / reserved ranges.\r
+ * @returns {!Array.<!Array.<number>>}\r
+ * @private\r
+ */\r
+ ParserPrototype._parseExtensionRanges = function() {\r
+ var ranges = [];\r
+ var token,\r
+ range,\r
+ value;\r
+ do {\r
+ range = [];\r
+ while (true) {\r
+ token = this.tn.next();\r
+ switch (token) {\r
+ case "min":\r
+ value = ProtoBuf.ID_MIN;\r
+ break;\r
+ case "max":\r
+ value = ProtoBuf.ID_MAX;\r
+ break;\r
+ default:\r
+ value = mkNumber(token);\r
+ break;\r
+ }\r
+ range.push(value);\r
+ if (range.length === 2)\r
+ break;\r
+ if (this.tn.peek() !== "to") {\r
+ range.push(value);\r
+ break;\r
+ }\r
+ this.tn.next();\r
+ }\r
+ ranges.push(range);\r
+ } while (this.tn.omit(","));\r
+ this.tn.skip(";");\r
+ return ranges;\r
+ };\r
+\r
+ /**\r
+ * Parses an extend block.\r
+ * @param {!Object} parent Parent object\r
+ * @private\r
+ */\r
+ ParserPrototype._parseExtend = function(parent) {\r
+ var token = this.tn.next();\r
+ if (!Lang.TYPEREF.test(token))\r
+ throw Error("illegal extend reference: "+token);\r
+ var ext = {\r
+ "ref": token,\r
+ "fields": []\r
+ };\r
+ this.tn.skip("{");\r
+ while ((token = this.tn.next()) !== '}') {\r
+ if (Lang.RULE.test(token))\r
+ this._parseMessageField(ext, token);\r
+ else if (Lang.TYPEREF.test(token)) {\r
+ if (!this.proto3)\r
+ throw Error("illegal field rule: "+token);\r
+ this._parseMessageField(ext, "optional", token);\r
+ } else\r
+ throw Error("illegal extend token: "+token);\r
+ }\r
+ this.tn.omit(";");\r
+ parent["messages"].push(ext);\r
+ return ext;\r
+ };\r
+\r
+ // ----- General -----\r
+\r
+ /**\r
+ * Returns a string representation of this parser.\r
+ * @returns {string}\r
+ */\r
+ ParserPrototype.toString = function() {\r
+ return "Parser at line "+this.tn.line;\r
+ };\r
+\r
+ /**\r
+ * @alias ProtoBuf.DotProto.Parser\r
+ * @expose\r
+ */\r
+ DotProto.Parser = Parser;\r
+\r
+ return DotProto;\r
+\r
+ })(ProtoBuf, ProtoBuf.Lang);\r
+\r
+ /**\r
+ * @alias ProtoBuf.Reflect\r
+ * @expose\r
+ */\r
+ ProtoBuf.Reflect = (function(ProtoBuf) {\r
+ "use strict";\r
+\r
+ /**\r
+ * Reflection types.\r
+ * @exports ProtoBuf.Reflect\r
+ * @namespace\r
+ */\r
+ var Reflect = {};\r
+\r
+ /**\r
+ * Constructs a Reflect base class.\r
+ * @exports ProtoBuf.Reflect.T\r
+ * @constructor\r
+ * @abstract\r
+ * @param {!ProtoBuf.Builder} builder Builder reference\r
+ * @param {?ProtoBuf.Reflect.T} parent Parent object\r
+ * @param {string} name Object name\r
+ */\r
+ var T = function(builder, parent, name) {\r
+\r
+ /**\r
+ * Builder reference.\r
+ * @type {!ProtoBuf.Builder}\r
+ * @expose\r
+ */\r
+ this.builder = builder;\r
+\r
+ /**\r
+ * Parent object.\r
+ * @type {?ProtoBuf.Reflect.T}\r
+ * @expose\r
+ */\r
+ this.parent = parent;\r
+\r
+ /**\r
+ * Object name in namespace.\r
+ * @type {string}\r
+ * @expose\r
+ */\r
+ this.name = name;\r
+\r
+ /**\r
+ * Fully qualified class name\r
+ * @type {string}\r
+ * @expose\r
+ */\r
+ this.className;\r
+ };\r
+\r
+ /**\r
+ * @alias ProtoBuf.Reflect.T.prototype\r
+ * @inner\r
+ */\r
+ var TPrototype = T.prototype;\r
+\r
+ /**\r
+ * Returns the fully qualified name of this object.\r
+ * @returns {string} Fully qualified name as of ".PATH.TO.THIS"\r
+ * @expose\r
+ */\r
+ TPrototype.fqn = function() {\r
+ var name = this.name,\r
+ ptr = this;\r
+ do {\r
+ ptr = ptr.parent;\r
+ if (ptr == null)\r
+ break;\r
+ name = ptr.name+"."+name;\r
+ } while (true);\r
+ return name;\r
+ };\r
+\r
+ /**\r
+ * Returns a string representation of this Reflect object (its fully qualified name).\r
+ * @param {boolean=} includeClass Set to true to include the class name. Defaults to false.\r
+ * @return String representation\r
+ * @expose\r
+ */\r
+ TPrototype.toString = function(includeClass) {\r
+ return (includeClass ? this.className + " " : "") + this.fqn();\r
+ };\r
+\r
+ /**\r
+ * Builds this type.\r
+ * @throws {Error} If this type cannot be built directly\r
+ * @expose\r
+ */\r
+ TPrototype.build = function() {\r
+ throw Error(this.toString(true)+" cannot be built directly");\r
+ };\r
+\r
+ /**\r
+ * @alias ProtoBuf.Reflect.T\r
+ * @expose\r
+ */\r
+ Reflect.T = T;\r
+\r
+ /**\r
+ * Constructs a new Namespace.\r
+ * @exports ProtoBuf.Reflect.Namespace\r
+ * @param {!ProtoBuf.Builder} builder Builder reference\r
+ * @param {?ProtoBuf.Reflect.Namespace} parent Namespace parent\r
+ * @param {string} name Namespace name\r
+ * @param {Object.<string,*>=} options Namespace options\r
+ * @param {string?} syntax The syntax level of this definition (e.g., proto3)\r
+ * @constructor\r
+ * @extends ProtoBuf.Reflect.T\r
+ */\r
+ var Namespace = function(builder, parent, name, options, syntax) {\r
+ T.call(this, builder, parent, name);\r
+\r
+ /**\r
+ * @override\r
+ */\r
+ this.className = "Namespace";\r
+\r
+ /**\r
+ * Children inside the namespace.\r
+ * @type {!Array.<ProtoBuf.Reflect.T>}\r
+ */\r
+ this.children = [];\r
+\r
+ /**\r
+ * Options.\r
+ * @type {!Object.<string, *>}\r
+ */\r
+ this.options = options || {};\r
+\r
+ /**\r
+ * Syntax level (e.g., proto2 or proto3).\r
+ * @type {!string}\r
+ */\r
+ this.syntax = syntax || "proto2";\r
+ };\r
+\r
+ /**\r
+ * @alias ProtoBuf.Reflect.Namespace.prototype\r
+ * @inner\r
+ */\r
+ var NamespacePrototype = Namespace.prototype = Object.create(T.prototype);\r
+\r
+ /**\r
+ * Returns an array of the namespace's children.\r
+ * @param {ProtoBuf.Reflect.T=} type Filter type (returns instances of this type only). Defaults to null (all children).\r
+ * @return {Array.<ProtoBuf.Reflect.T>}\r
+ * @expose\r
+ */\r
+ NamespacePrototype.getChildren = function(type) {\r
+ type = type || null;\r
+ if (type == null)\r
+ return this.children.slice();\r
+ var children = [];\r
+ for (var i=0, k=this.children.length; i<k; ++i)\r
+ if (this.children[i] instanceof type)\r
+ children.push(this.children[i]);\r
+ return children;\r
+ };\r
+\r
+ /**\r
+ * Adds a child to the namespace.\r
+ * @param {ProtoBuf.Reflect.T} child Child\r
+ * @throws {Error} If the child cannot be added (duplicate)\r
+ * @expose\r
+ */\r
+ NamespacePrototype.addChild = function(child) {\r
+ var other;\r
+ if (other = this.getChild(child.name)) {\r
+ // Try to revert camelcase transformation on collision\r
+ if (other instanceof Message.Field && other.name !== other.originalName && this.getChild(other.originalName) === null)\r
+ other.name = other.originalName; // Revert previous first (effectively keeps both originals)\r
+ else if (child instanceof Message.Field && child.name !== child.originalName && this.getChild(child.originalName) === null)\r
+ child.name = child.originalName;\r
+ else\r
+ throw Error("Duplicate name in namespace "+this.toString(true)+": "+child.name);\r
+ }\r
+ this.children.push(child);\r
+ };\r
+\r
+ /**\r
+ * Gets a child by its name or id.\r
+ * @param {string|number} nameOrId Child name or id\r
+ * @return {?ProtoBuf.Reflect.T} The child or null if not found\r
+ * @expose\r
+ */\r
+ NamespacePrototype.getChild = function(nameOrId) {\r
+ var key = typeof nameOrId === 'number' ? 'id' : 'name';\r
+ for (var i=0, k=this.children.length; i<k; ++i)\r
+ if (this.children[i][key] === nameOrId)\r
+ return this.children[i];\r
+ return null;\r
+ };\r
+\r
+ /**\r
+ * Resolves a reflect object inside of this namespace.\r
+ * @param {string|!Array.<string>} qn Qualified name to resolve\r
+ * @param {boolean=} excludeNonNamespace Excludes non-namespace types, defaults to `false`\r
+ * @return {?ProtoBuf.Reflect.Namespace} The resolved type or null if not found\r
+ * @expose\r
+ */\r
+ NamespacePrototype.resolve = function(qn, excludeNonNamespace) {\r
+ var part = typeof qn === 'string' ? qn.split(".") : qn,\r
+ ptr = this,\r
+ i = 0;\r
+ if (part[i] === "") { // Fully qualified name, e.g. ".My.Message'\r
+ while (ptr.parent !== null)\r
+ ptr = ptr.parent;\r
+ i++;\r
+ }\r
+ var child;\r
+ do {\r
+ do {\r
+ if (!(ptr instanceof Reflect.Namespace)) {\r
+ ptr = null;\r
+ break;\r
+ }\r
+ child = ptr.getChild(part[i]);\r
+ if (!child || !(child instanceof Reflect.T) || (excludeNonNamespace && !(child instanceof Reflect.Namespace))) {\r
+ ptr = null;\r
+ break;\r
+ }\r
+ ptr = child; i++;\r
+ } while (i < part.length);\r
+ if (ptr != null)\r
+ break; // Found\r
+ // Else search the parent\r
+ if (this.parent !== null)\r
+ return this.parent.resolve(qn, excludeNonNamespace);\r
+ } while (ptr != null);\r
+ return ptr;\r
+ };\r
+\r
+ /**\r
+ * Determines the shortest qualified name of the specified type, if any, relative to this namespace.\r
+ * @param {!ProtoBuf.Reflect.T} t Reflection type\r
+ * @returns {string} The shortest qualified name or, if there is none, the fqn\r
+ * @expose\r
+ */\r
+ NamespacePrototype.qn = function(t) {\r
+ var part = [], ptr = t;\r
+ do {\r
+ part.unshift(ptr.name);\r
+ ptr = ptr.parent;\r
+ } while (ptr !== null);\r
+ for (var len=1; len <= part.length; len++) {\r
+ var qn = part.slice(part.length-len);\r
+ if (t === this.resolve(qn, t instanceof Reflect.Namespace))\r
+ return qn.join(".");\r
+ }\r
+ return t.fqn();\r
+ };\r
+\r
+ /**\r
+ * Builds the namespace and returns the runtime counterpart.\r
+ * @return {Object.<string,Function|Object>} Runtime namespace\r
+ * @expose\r
+ */\r
+ NamespacePrototype.build = function() {\r
+ /** @dict */\r
+ var ns = {};\r
+ var children = this.children;\r
+ for (var i=0, k=children.length, child; i<k; ++i) {\r
+ child = children[i];\r
+ if (child instanceof Namespace)\r
+ ns[child.name] = child.build();\r
+ }\r
+ if (Object.defineProperty)\r
+ Object.defineProperty(ns, "$options", { "value": this.buildOpt() });\r
+ return ns;\r
+ };\r
+\r
+ /**\r
+ * Builds the namespace's '$options' property.\r
+ * @return {Object.<string,*>}\r
+ */\r
+ NamespacePrototype.buildOpt = function() {\r
+ var opt = {},\r
+ keys = Object.keys(this.options);\r
+ for (var i=0, k=keys.length; i<k; ++i) {\r
+ var key = keys[i],\r
+ val = this.options[keys[i]];\r
+ // TODO: Options are not resolved, yet.\r
+ // if (val instanceof Namespace) {\r
+ // opt[key] = val.build();\r
+ // } else {\r
+ opt[key] = val;\r
+ // }\r
+ }\r
+ return opt;\r
+ };\r
+\r
+ /**\r
+ * Gets the value assigned to the option with the specified name.\r
+ * @param {string=} name Returns the option value if specified, otherwise all options are returned.\r
+ * @return {*|Object.<string,*>}null} Option value or NULL if there is no such option\r
+ */\r
+ NamespacePrototype.getOption = function(name) {\r
+ if (typeof name === 'undefined')\r
+ return this.options;\r
+ return typeof this.options[name] !== 'undefined' ? this.options[name] : null;\r
+ };\r
+\r
+ /**\r
+ * @alias ProtoBuf.Reflect.Namespace\r
+ * @expose\r
+ */\r
+ Reflect.Namespace = Namespace;\r
+\r
+ /**\r
+ * Constructs a new Element implementation that checks and converts values for a\r
+ * particular field type, as appropriate.\r
+ *\r
+ * An Element represents a single value: either the value of a singular field,\r
+ * or a value contained in one entry of a repeated field or map field. This\r
+ * class does not implement these higher-level concepts; it only encapsulates\r
+ * the low-level typechecking and conversion.\r
+ *\r
+ * @exports ProtoBuf.Reflect.Element\r
+ * @param {{name: string, wireType: number}} type Resolved data type\r
+ * @param {ProtoBuf.Reflect.T|null} resolvedType Resolved type, if relevant\r
+ * (e.g. submessage field).\r
+ * @param {boolean} isMapKey Is this element a Map key? The value will be\r
+ * converted to string form if so.\r
+ * @param {string} syntax Syntax level of defining message type, e.g.,\r
+ * proto2 or proto3.\r
+ * @param {string} name Name of the field containing this element (for error\r
+ * messages)\r
+ * @constructor\r
+ */\r
+ var Element = function(type, resolvedType, isMapKey, syntax, name) {\r
+\r
+ /**\r
+ * Element type, as a string (e.g., int32).\r
+ * @type {{name: string, wireType: number}}\r
+ */\r
+ this.type = type;\r
+\r
+ /**\r
+ * Element type reference to submessage or enum definition, if needed.\r
+ * @type {ProtoBuf.Reflect.T|null}\r
+ */\r
+ this.resolvedType = resolvedType;\r
+\r
+ /**\r
+ * Element is a map key.\r
+ * @type {boolean}\r
+ */\r
+ this.isMapKey = isMapKey;\r
+\r
+ /**\r
+ * Syntax level of defining message type, e.g., proto2 or proto3.\r
+ * @type {string}\r
+ */\r
+ this.syntax = syntax;\r
+\r
+ /**\r
+ * Name of the field containing this element (for error messages)\r
+ * @type {string}\r
+ */\r
+ this.name = name;\r
+\r
+ if (isMapKey && ProtoBuf.MAP_KEY_TYPES.indexOf(type) < 0)\r
+ throw Error("Invalid map key type: " + type.name);\r
+ };\r
+\r
+ var ElementPrototype = Element.prototype;\r
+\r
+ /**\r
+ * Obtains a (new) default value for the specified type.\r
+ * @param type {string|{name: string, wireType: number}} Field type\r
+ * @returns {*} Default value\r
+ * @inner\r
+ */\r
+ function mkDefault(type) {\r
+ if (typeof type === 'string')\r
+ type = ProtoBuf.TYPES[type];\r
+ if (typeof type.defaultValue === 'undefined')\r
+ throw Error("default value for type "+type.name+" is not supported");\r
+ if (type == ProtoBuf.TYPES["bytes"])\r
+ return new ByteBuffer(0);\r
+ return type.defaultValue;\r
+ }\r
+\r
+ /**\r
+ * Returns the default value for this field in proto3.\r
+ * @function\r
+ * @param type {string|{name: string, wireType: number}} the field type\r
+ * @returns {*} Default value\r
+ */\r
+ Element.defaultFieldValue = mkDefault;\r
+\r
+ /**\r
+ * Makes a Long from a value.\r
+ * @param {{low: number, high: number, unsigned: boolean}|string|number} value Value\r
+ * @param {boolean=} unsigned Whether unsigned or not, defaults to reuse it from Long-like objects or to signed for\r
+ * strings and numbers\r
+ * @returns {!Long}\r
+ * @throws {Error} If the value cannot be converted to a Long\r
+ * @inner\r
+ */\r
+ function mkLong(value, unsigned) {\r
+ if (value && typeof value.low === 'number' && typeof value.high === 'number' && typeof value.unsigned === 'boolean'\r
+ && value.low === value.low && value.high === value.high)\r
+ return new ProtoBuf.Long(value.low, value.high, typeof unsigned === 'undefined' ? value.unsigned : unsigned);\r
+ if (typeof value === 'string')\r
+ return ProtoBuf.Long.fromString(value, unsigned || false, 10);\r
+ if (typeof value === 'number')\r
+ return ProtoBuf.Long.fromNumber(value, unsigned || false);\r
+ throw Error("not convertible to Long");\r
+ }\r
+\r
+ ElementPrototype.toString = function() {\r
+ return (this.name || '') + (this.isMapKey ? 'map' : 'value') + ' element';\r
+ }\r
+\r
+ /**\r
+ * Checks if the given value can be set for an element of this type (singular\r
+ * field or one element of a repeated field or map).\r
+ * @param {*} value Value to check\r
+ * @return {*} Verified, maybe adjusted, value\r
+ * @throws {Error} If the value cannot be verified for this element slot\r
+ * @expose\r
+ */\r
+ ElementPrototype.verifyValue = function(value) {\r
+ var self = this;\r
+ function fail(val, msg) {\r
+ throw Error("Illegal value for "+self.toString(true)+" of type "+self.type.name+": "+val+" ("+msg+")");\r
+ }\r
+ switch (this.type) {\r
+ // Signed 32bit\r
+ case ProtoBuf.TYPES["int32"]:\r
+ case ProtoBuf.TYPES["sint32"]:\r
+ case ProtoBuf.TYPES["sfixed32"]:\r
+ // Account for !NaN: value === value\r
+ if (typeof value !== 'number' || (value === value && value % 1 !== 0))\r
+ fail(typeof value, "not an integer");\r
+ return value > 4294967295 ? value | 0 : value;\r
+\r
+ // Unsigned 32bit\r
+ case ProtoBuf.TYPES["uint32"]:\r
+ case ProtoBuf.TYPES["fixed32"]:\r
+ if (typeof value !== 'number' || (value === value && value % 1 !== 0))\r
+ fail(typeof value, "not an integer");\r
+ return value < 0 ? value >>> 0 : value;\r
+\r
+ // Signed 64bit\r
+ case ProtoBuf.TYPES["int64"]:\r
+ case ProtoBuf.TYPES["sint64"]:\r
+ case ProtoBuf.TYPES["sfixed64"]: {\r
+ if (ProtoBuf.Long)\r
+ try {\r
+ return mkLong(value, false);\r
+ } catch (e) {\r
+ fail(typeof value, e.message);\r
+ }\r
+ else\r
+ fail(typeof value, "requires Long.js");\r
+ }\r
+\r
+ // Unsigned 64bit\r
+ case ProtoBuf.TYPES["uint64"]:\r
+ case ProtoBuf.TYPES["fixed64"]: {\r
+ if (ProtoBuf.Long)\r
+ try {\r
+ return mkLong(value, true);\r
+ } catch (e) {\r
+ fail(typeof value, e.message);\r
+ }\r
+ else\r
+ fail(typeof value, "requires Long.js");\r
+ }\r
+\r
+ // Bool\r
+ case ProtoBuf.TYPES["bool"]:\r
+ if (typeof value !== 'boolean')\r
+ fail(typeof value, "not a boolean");\r
+ return value;\r
+\r
+ // Float\r
+ case ProtoBuf.TYPES["float"]:\r
+ case ProtoBuf.TYPES["double"]:\r
+ if (typeof value !== 'number')\r
+ fail(typeof value, "not a number");\r
+ return value;\r
+\r
+ // Length-delimited string\r
+ case ProtoBuf.TYPES["string"]:\r
+ if (typeof value !== 'string' && !(value && value instanceof String))\r
+ fail(typeof value, "not a string");\r
+ return ""+value; // Convert String object to string\r
+\r
+ // Length-delimited bytes\r
+ case ProtoBuf.TYPES["bytes"]:\r
+ if (ByteBuffer.isByteBuffer(value))\r
+ return value;\r
+ return ByteBuffer.wrap(value, "base64");\r
+\r
+ // Constant enum value\r
+ case ProtoBuf.TYPES["enum"]: {\r
+ var values = this.resolvedType.getChildren(ProtoBuf.Reflect.Enum.Value);\r
+ for (i=0; i<values.length; i++)\r
+ if (values[i].name == value)\r
+ return values[i].id;\r
+ else if (values[i].id == value)\r
+ return values[i].id;\r
+\r
+ if (this.syntax === 'proto3') {\r
+ // proto3: just make sure it's an integer.\r
+ if (typeof value !== 'number' || (value === value && value % 1 !== 0))\r
+ fail(typeof value, "not an integer");\r
+ if (value > 4294967295 || value < 0)\r
+ fail(typeof value, "not in range for uint32")\r
+ return value;\r
+ } else {\r
+ // proto2 requires enum values to be valid.\r
+ fail(value, "not a valid enum value");\r
+ }\r
+ }\r
+ // Embedded message\r
+ case ProtoBuf.TYPES["group"]:\r
+ case ProtoBuf.TYPES["message"]: {\r
+ if (!value || typeof value !== 'object')\r
+ fail(typeof value, "object expected");\r
+ if (value instanceof this.resolvedType.clazz)\r
+ return value;\r
+ if (value instanceof ProtoBuf.Builder.Message) {\r
+ // Mismatched type: Convert to object (see: https://github.com/dcodeIO/ProtoBuf.js/issues/180)\r
+ var obj = {};\r
+ for (var i in value)\r
+ if (value.hasOwnProperty(i))\r
+ obj[i] = value[i];\r
+ value = obj;\r
+ }\r
+ // Else let's try to construct one from a key-value object\r
+ return new (this.resolvedType.clazz)(value); // May throw for a hundred of reasons\r
+ }\r
+ }\r
+\r
+ // We should never end here\r
+ throw Error("[INTERNAL] Illegal value for "+this.toString(true)+": "+value+" (undefined type "+this.type+")");\r
+ };\r
+\r
+ /**\r
+ * Calculates the byte length of an element on the wire.\r
+ * @param {number} id Field number\r
+ * @param {*} value Field value\r
+ * @returns {number} Byte length\r
+ * @throws {Error} If the value cannot be calculated\r
+ * @expose\r
+ */\r
+ ElementPrototype.calculateLength = function(id, value) {\r
+ if (value === null) return 0; // Nothing to encode\r
+ // Tag has already been written\r
+ var n;\r
+ switch (this.type) {\r
+ case ProtoBuf.TYPES["int32"]:\r
+ return value < 0 ? ByteBuffer.calculateVarint64(value) : ByteBuffer.calculateVarint32(value);\r
+ case ProtoBuf.TYPES["uint32"]:\r
+ return ByteBuffer.calculateVarint32(value);\r
+ case ProtoBuf.TYPES["sint32"]:\r
+ return ByteBuffer.calculateVarint32(ByteBuffer.zigZagEncode32(value));\r
+ case ProtoBuf.TYPES["fixed32"]:\r
+ case ProtoBuf.TYPES["sfixed32"]:\r
+ case ProtoBuf.TYPES["float"]:\r
+ return 4;\r
+ case ProtoBuf.TYPES["int64"]:\r
+ case ProtoBuf.TYPES["uint64"]:\r
+ return ByteBuffer.calculateVarint64(value);\r
+ case ProtoBuf.TYPES["sint64"]:\r
+ return ByteBuffer.calculateVarint64(ByteBuffer.zigZagEncode64(value));\r
+ case ProtoBuf.TYPES["fixed64"]:\r
+ case ProtoBuf.TYPES["sfixed64"]:\r
+ return 8;\r
+ case ProtoBuf.TYPES["bool"]:\r
+ return 1;\r
+ case ProtoBuf.TYPES["enum"]:\r
+ return ByteBuffer.calculateVarint32(value);\r
+ case ProtoBuf.TYPES["double"]:\r
+ return 8;\r
+ case ProtoBuf.TYPES["string"]:\r
+ n = ByteBuffer.calculateUTF8Bytes(value);\r
+ return ByteBuffer.calculateVarint32(n) + n;\r
+ case ProtoBuf.TYPES["bytes"]:\r
+ if (value.remaining() < 0)\r
+ throw Error("Illegal value for "+this.toString(true)+": "+value.remaining()+" bytes remaining");\r
+ return ByteBuffer.calculateVarint32(value.remaining()) + value.remaining();\r
+ case ProtoBuf.TYPES["message"]:\r
+ n = this.resolvedType.calculate(value);\r
+ return ByteBuffer.calculateVarint32(n) + n;\r
+ case ProtoBuf.TYPES["group"]:\r
+ n = this.resolvedType.calculate(value);\r
+ return n + ByteBuffer.calculateVarint32((id << 3) | ProtoBuf.WIRE_TYPES.ENDGROUP);\r
+ }\r
+ // We should never end here\r
+ throw Error("[INTERNAL] Illegal value to encode in "+this.toString(true)+": "+value+" (unknown type)");\r
+ };\r
+\r
+ /**\r
+ * Encodes a value to the specified buffer. Does not encode the key.\r
+ * @param {number} id Field number\r
+ * @param {*} value Field value\r
+ * @param {ByteBuffer} buffer ByteBuffer to encode to\r
+ * @return {ByteBuffer} The ByteBuffer for chaining\r
+ * @throws {Error} If the value cannot be encoded\r
+ * @expose\r
+ */\r
+ ElementPrototype.encodeValue = function(id, value, buffer) {\r
+ if (value === null) return buffer; // Nothing to encode\r
+ // Tag has already been written\r
+\r
+ switch (this.type) {\r
+ // 32bit signed varint\r
+ case ProtoBuf.TYPES["int32"]:\r
+ // "If you use int32 or int64 as the type for a negative number, the resulting varint is always ten bytes\r
+ // long – it is, effectively, treated like a very large unsigned integer." (see #122)\r
+ if (value < 0)\r
+ buffer.writeVarint64(value);\r
+ else\r
+ buffer.writeVarint32(value);\r
+ break;\r
+\r
+ // 32bit unsigned varint\r
+ case ProtoBuf.TYPES["uint32"]:\r
+ buffer.writeVarint32(value);\r
+ break;\r
+\r
+ // 32bit varint zig-zag\r
+ case ProtoBuf.TYPES["sint32"]:\r
+ buffer.writeVarint32ZigZag(value);\r
+ break;\r
+\r
+ // Fixed unsigned 32bit\r
+ case ProtoBuf.TYPES["fixed32"]:\r
+ buffer.writeUint32(value);\r
+ break;\r
+\r
+ // Fixed signed 32bit\r
+ case ProtoBuf.TYPES["sfixed32"]:\r
+ buffer.writeInt32(value);\r
+ break;\r
+\r
+ // 64bit varint as-is\r
+ case ProtoBuf.TYPES["int64"]:\r
+ case ProtoBuf.TYPES["uint64"]:\r
+ buffer.writeVarint64(value); // throws\r
+ break;\r
+\r
+ // 64bit varint zig-zag\r
+ case ProtoBuf.TYPES["sint64"]:\r
+ buffer.writeVarint64ZigZag(value); // throws\r
+ break;\r
+\r
+ // Fixed unsigned 64bit\r
+ case ProtoBuf.TYPES["fixed64"]:\r
+ buffer.writeUint64(value); // throws\r
+ break;\r
+\r
+ // Fixed signed 64bit\r
+ case ProtoBuf.TYPES["sfixed64"]:\r
+ buffer.writeInt64(value); // throws\r
+ break;\r
+\r
+ // Bool\r
+ case ProtoBuf.TYPES["bool"]:\r
+ if (typeof value === 'string')\r
+ buffer.writeVarint32(value.toLowerCase() === 'false' ? 0 : !!value);\r
+ else\r
+ buffer.writeVarint32(value ? 1 : 0);\r
+ break;\r
+\r
+ // Constant enum value\r
+ case ProtoBuf.TYPES["enum"]:\r
+ buffer.writeVarint32(value);\r
+ break;\r
+\r
+ // 32bit float\r
+ case ProtoBuf.TYPES["float"]:\r
+ buffer.writeFloat32(value);\r
+ break;\r
+\r
+ // 64bit float\r
+ case ProtoBuf.TYPES["double"]:\r
+ buffer.writeFloat64(value);\r
+ break;\r
+\r
+ // Length-delimited string\r
+ case ProtoBuf.TYPES["string"]:\r
+ buffer.writeVString(value);\r
+ break;\r
+\r
+ // Length-delimited bytes\r
+ case ProtoBuf.TYPES["bytes"]:\r
+ if (value.remaining() < 0)\r
+ throw Error("Illegal value for "+this.toString(true)+": "+value.remaining()+" bytes remaining");\r
+ var prevOffset = value.offset;\r
+ buffer.writeVarint32(value.remaining());\r
+ buffer.append(value);\r
+ value.offset = prevOffset;\r
+ break;\r
+\r
+ // Embedded message\r
+ case ProtoBuf.TYPES["message"]:\r
+ var bb = new ByteBuffer().LE();\r
+ this.resolvedType.encode(value, bb);\r
+ buffer.writeVarint32(bb.offset);\r
+ buffer.append(bb.flip());\r
+ break;\r
+\r
+ // Legacy group\r
+ case ProtoBuf.TYPES["group"]:\r
+ this.resolvedType.encode(value, buffer);\r
+ buffer.writeVarint32((id << 3) | ProtoBuf.WIRE_TYPES.ENDGROUP);\r
+ break;\r
+\r
+ default:\r
+ // We should never end here\r
+ throw Error("[INTERNAL] Illegal value to encode in "+this.toString(true)+": "+value+" (unknown type)");\r
+ }\r
+ return buffer;\r
+ };\r
+\r
+ /**\r
+ * Decode one element value from the specified buffer.\r
+ * @param {ByteBuffer} buffer ByteBuffer to decode from\r
+ * @param {number} wireType The field wire type\r
+ * @param {number} id The field number\r
+ * @return {*} Decoded value\r
+ * @throws {Error} If the field cannot be decoded\r
+ * @expose\r
+ */\r
+ ElementPrototype.decode = function(buffer, wireType, id) {\r
+ if (wireType != this.type.wireType)\r
+ throw Error("Unexpected wire type for element");\r
+\r
+ var value, nBytes;\r
+ switch (this.type) {\r
+ // 32bit signed varint\r
+ case ProtoBuf.TYPES["int32"]:\r
+ return buffer.readVarint32() | 0;\r
+\r
+ // 32bit unsigned varint\r
+ case ProtoBuf.TYPES["uint32"]:\r
+ return buffer.readVarint32() >>> 0;\r
+\r
+ // 32bit signed varint zig-zag\r
+ case ProtoBuf.TYPES["sint32"]:\r
+ return buffer.readVarint32ZigZag() | 0;\r
+\r
+ // Fixed 32bit unsigned\r
+ case ProtoBuf.TYPES["fixed32"]:\r
+ return buffer.readUint32() >>> 0;\r
+\r
+ case ProtoBuf.TYPES["sfixed32"]:\r
+ return buffer.readInt32() | 0;\r
+\r
+ // 64bit signed varint\r
+ case ProtoBuf.TYPES["int64"]:\r
+ return buffer.readVarint64();\r
+\r
+ // 64bit unsigned varint\r
+ case ProtoBuf.TYPES["uint64"]:\r
+ return buffer.readVarint64().toUnsigned();\r
+\r
+ // 64bit signed varint zig-zag\r
+ case ProtoBuf.TYPES["sint64"]:\r
+ return buffer.readVarint64ZigZag();\r
+\r
+ // Fixed 64bit unsigned\r
+ case ProtoBuf.TYPES["fixed64"]:\r
+ return buffer.readUint64();\r
+\r
+ // Fixed 64bit signed\r
+ case ProtoBuf.TYPES["sfixed64"]:\r
+ return buffer.readInt64();\r
+\r
+ // Bool varint\r
+ case ProtoBuf.TYPES["bool"]:\r
+ return !!buffer.readVarint32();\r
+\r
+ // Constant enum value (varint)\r
+ case ProtoBuf.TYPES["enum"]:\r
+ // The following Builder.Message#set will already throw\r
+ return buffer.readVarint32();\r
+\r
+ // 32bit float\r
+ case ProtoBuf.TYPES["float"]:\r
+ return buffer.readFloat();\r
+\r
+ // 64bit float\r
+ case ProtoBuf.TYPES["double"]:\r
+ return buffer.readDouble();\r
+\r
+ // Length-delimited string\r
+ case ProtoBuf.TYPES["string"]:\r
+ return buffer.readVString();\r
+\r
+ // Length-delimited bytes\r
+ case ProtoBuf.TYPES["bytes"]: {\r
+ nBytes = buffer.readVarint32();\r
+ if (buffer.remaining() < nBytes)\r
+ throw Error("Illegal number of bytes for "+this.toString(true)+": "+nBytes+" required but got only "+buffer.remaining());\r
+ value = buffer.clone(); // Offset already set\r
+ value.limit = value.offset+nBytes;\r
+ buffer.offset += nBytes;\r
+ return value;\r
+ }\r
+\r
+ // Length-delimited embedded message\r
+ case ProtoBuf.TYPES["message"]: {\r
+ nBytes = buffer.readVarint32();\r
+ return this.resolvedType.decode(buffer, nBytes);\r
+ }\r
+\r
+ // Legacy group\r
+ case ProtoBuf.TYPES["group"]:\r
+ return this.resolvedType.decode(buffer, -1, id);\r
+ }\r
+\r
+ // We should never end here\r
+ throw Error("[INTERNAL] Illegal decode type");\r
+ };\r
+\r
+ /**\r
+ * Converts a value from a string to the canonical element type.\r
+ *\r
+ * Legal only when isMapKey is true.\r
+ *\r
+ * @param {string} str The string value\r
+ * @returns {*} The value\r
+ */\r
+ ElementPrototype.valueFromString = function(str) {\r
+ if (!this.isMapKey) {\r
+ throw Error("valueFromString() called on non-map-key element");\r
+ }\r
+\r
+ switch (this.type) {\r
+ case ProtoBuf.TYPES["int32"]:\r
+ case ProtoBuf.TYPES["sint32"]:\r
+ case ProtoBuf.TYPES["sfixed32"]:\r
+ case ProtoBuf.TYPES["uint32"]:\r
+ case ProtoBuf.TYPES["fixed32"]:\r
+ return this.verifyValue(parseInt(str));\r
+\r
+ case ProtoBuf.TYPES["int64"]:\r
+ case ProtoBuf.TYPES["sint64"]:\r
+ case ProtoBuf.TYPES["sfixed64"]:\r
+ case ProtoBuf.TYPES["uint64"]:\r
+ case ProtoBuf.TYPES["fixed64"]:\r
+ // Long-based fields support conversions from string already.\r
+ return this.verifyValue(str);\r
+\r
+ case ProtoBuf.TYPES["bool"]:\r
+ return str === "true";\r
+\r
+ case ProtoBuf.TYPES["string"]:\r
+ return this.verifyValue(str);\r
+\r
+ case ProtoBuf.TYPES["bytes"]:\r
+ return ByteBuffer.fromBinary(str);\r
+ }\r
+ };\r
+\r
+ /**\r
+ * Converts a value from the canonical element type to a string.\r
+ *\r
+ * It should be the case that `valueFromString(valueToString(val))` returns\r
+ * a value equivalent to `verifyValue(val)` for every legal value of `val`\r
+ * according to this element type.\r
+ *\r
+ * This may be used when the element must be stored or used as a string,\r
+ * e.g., as a map key on an Object.\r
+ *\r
+ * Legal only when isMapKey is true.\r
+ *\r
+ * @param {*} val The value\r
+ * @returns {string} The string form of the value.\r
+ */\r
+ ElementPrototype.valueToString = function(value) {\r
+ if (!this.isMapKey) {\r
+ throw Error("valueToString() called on non-map-key element");\r
+ }\r
+\r
+ if (this.type === ProtoBuf.TYPES["bytes"]) {\r
+ return value.toString("binary");\r
+ } else {\r
+ return value.toString();\r
+ }\r
+ };\r
+\r
+ /**\r
+ * @alias ProtoBuf.Reflect.Element\r
+ * @expose\r
+ */\r
+ Reflect.Element = Element;\r
+\r
+ /**\r
+ * Constructs a new Message.\r
+ * @exports ProtoBuf.Reflect.Message\r
+ * @param {!ProtoBuf.Builder} builder Builder reference\r
+ * @param {!ProtoBuf.Reflect.Namespace} parent Parent message or namespace\r
+ * @param {string} name Message name\r
+ * @param {Object.<string,*>=} options Message options\r
+ * @param {boolean=} isGroup `true` if this is a legacy group\r
+ * @param {string?} syntax The syntax level of this definition (e.g., proto3)\r
+ * @constructor\r
+ * @extends ProtoBuf.Reflect.Namespace\r
+ */\r
+ var Message = function(builder, parent, name, options, isGroup, syntax) {\r
+ Namespace.call(this, builder, parent, name, options, syntax);\r
+\r
+ /**\r
+ * @override\r
+ */\r
+ this.className = "Message";\r
+\r
+ /**\r
+ * Extensions range.\r
+ * @type {!Array.<number>|undefined}\r
+ * @expose\r
+ */\r
+ this.extensions = undefined;\r
+\r
+ /**\r
+ * Runtime message class.\r
+ * @type {?function(new:ProtoBuf.Builder.Message)}\r
+ * @expose\r
+ */\r
+ this.clazz = null;\r
+\r
+ /**\r
+ * Whether this is a legacy group or not.\r
+ * @type {boolean}\r
+ * @expose\r
+ */\r
+ this.isGroup = !!isGroup;\r
+\r
+ // The following cached collections are used to efficiently iterate over or look up fields when decoding.\r
+\r
+ /**\r
+ * Cached fields.\r
+ * @type {?Array.<!ProtoBuf.Reflect.Message.Field>}\r
+ * @private\r
+ */\r
+ this._fields = null;\r
+\r
+ /**\r
+ * Cached fields by id.\r
+ * @type {?Object.<number,!ProtoBuf.Reflect.Message.Field>}\r
+ * @private\r
+ */\r
+ this._fieldsById = null;\r
+\r
+ /**\r
+ * Cached fields by name.\r
+ * @type {?Object.<string,!ProtoBuf.Reflect.Message.Field>}\r
+ * @private\r
+ */\r
+ this._fieldsByName = null;\r
+ };\r
+\r
+ /**\r
+ * @alias ProtoBuf.Reflect.Message.prototype\r
+ * @inner\r
+ */\r
+ var MessagePrototype = Message.prototype = Object.create(Namespace.prototype);\r
+\r
+ /**\r
+ * Builds the message and returns the runtime counterpart, which is a fully functional class.\r
+ * @see ProtoBuf.Builder.Message\r
+ * @param {boolean=} rebuild Whether to rebuild or not, defaults to false\r
+ * @return {ProtoBuf.Reflect.Message} Message class\r
+ * @throws {Error} If the message cannot be built\r
+ * @expose\r
+ */\r
+ MessagePrototype.build = function(rebuild) {\r
+ if (this.clazz && !rebuild)\r
+ return this.clazz;\r
+\r
+ // Create the runtime Message class in its own scope\r
+ var clazz = (function(ProtoBuf, T) {\r
+\r
+ var fields = T.getChildren(ProtoBuf.Reflect.Message.Field),\r
+ oneofs = T.getChildren(ProtoBuf.Reflect.Message.OneOf);\r
+\r
+ /**\r
+ * Constructs a new runtime Message.\r
+ * @name ProtoBuf.Builder.Message\r
+ * @class Barebone of all runtime messages.\r
+ * @param {!Object.<string,*>|string} values Preset values\r
+ * @param {...string} var_args\r
+ * @constructor\r
+ * @throws {Error} If the message cannot be created\r
+ */\r
+ var Message = function(values, var_args) {\r
+ ProtoBuf.Builder.Message.call(this);\r
+\r
+ // Create virtual oneof properties\r
+ for (var i=0, k=oneofs.length; i<k; ++i)\r
+ this[oneofs[i].name] = null;\r
+ // Create fields and set default values\r
+ for (i=0, k=fields.length; i<k; ++i) {\r
+ var field = fields[i];\r
+ this[field.name] =\r
+ field.repeated ? [] :\r
+ (field.map ? new ProtoBuf.Map(field) : null);\r
+ if ((field.required || T.syntax === 'proto3') &&\r
+ field.defaultValue !== null)\r
+ this[field.name] = field.defaultValue;\r
+ }\r
+\r
+ if (arguments.length > 0) {\r
+ var value;\r
+ // Set field values from a values object\r
+ if (arguments.length === 1 && values !== null && typeof values === 'object' &&\r
+ /* not _another_ Message */ (typeof values.encode !== 'function' || values instanceof Message) &&\r
+ /* not a repeated field */ !Array.isArray(values) &&\r
+ /* not a Map */ !(values instanceof ProtoBuf.Map) &&\r
+ /* not a ByteBuffer */ !ByteBuffer.isByteBuffer(values) &&\r
+ /* not an ArrayBuffer */ !(values instanceof ArrayBuffer) &&\r
+ /* not a Long */ !(ProtoBuf.Long && values instanceof ProtoBuf.Long)) {\r
+ this.$set(values);\r
+ } else // Set field values from arguments, in declaration order\r
+ for (i=0, k=arguments.length; i<k; ++i)\r
+ if (typeof (value = arguments[i]) !== 'undefined')\r
+ this.$set(fields[i].name, value); // May throw\r
+ }\r
+ };\r
+\r
+ /**\r
+ * @alias ProtoBuf.Builder.Message.prototype\r
+ * @inner\r
+ */\r
+ var MessagePrototype = Message.prototype = Object.create(ProtoBuf.Builder.Message.prototype);\r
+\r
+ /**\r
+ * Adds a value to a repeated field.\r
+ * @name ProtoBuf.Builder.Message#add\r
+ * @function\r
+ * @param {string} key Field name\r
+ * @param {*} value Value to add\r
+ * @param {boolean=} noAssert Whether to assert the value or not (asserts by default)\r
+ * @returns {!ProtoBuf.Builder.Message} this\r
+ * @throws {Error} If the value cannot be added\r
+ * @expose\r
+ */\r
+ MessagePrototype.add = function(key, value, noAssert) {\r
+ var field = T._fieldsByName[key];\r
+ if (!noAssert) {\r
+ if (!field)\r
+ throw Error(this+"#"+key+" is undefined");\r
+ if (!(field instanceof ProtoBuf.Reflect.Message.Field))\r
+ throw Error(this+"#"+key+" is not a field: "+field.toString(true)); // May throw if it's an enum or embedded message\r
+ if (!field.repeated)\r
+ throw Error(this+"#"+key+" is not a repeated field");\r
+ value = field.verifyValue(value, true);\r
+ }\r
+ if (this[key] === null)\r
+ this[key] = [];\r
+ this[key].push(value);\r
+ return this;\r
+ };\r
+\r
+ /**\r
+ * Adds a value to a repeated field. This is an alias for {@link ProtoBuf.Builder.Message#add}.\r
+ * @name ProtoBuf.Builder.Message#$add\r
+ * @function\r
+ * @param {string} key Field name\r
+ * @param {*} value Value to add\r
+ * @param {boolean=} noAssert Whether to assert the value or not (asserts by default)\r
+ * @returns {!ProtoBuf.Builder.Message} this\r
+ * @throws {Error} If the value cannot be added\r
+ * @expose\r
+ */\r
+ MessagePrototype.$add = MessagePrototype.add;\r
+\r
+ /**\r
+ * Sets a field's value.\r
+ * @name ProtoBuf.Builder.Message#set\r
+ * @function\r
+ * @param {string|!Object.<string,*>} keyOrObj String key or plain object holding multiple values\r
+ * @param {(*|boolean)=} value Value to set if key is a string, otherwise omitted\r
+ * @param {boolean=} noAssert Whether to not assert for an actual field / proper value type, defaults to `false`\r
+ * @returns {!ProtoBuf.Builder.Message} this\r
+ * @throws {Error} If the value cannot be set\r
+ * @expose\r
+ */\r
+ MessagePrototype.set = function(keyOrObj, value, noAssert) {\r
+ if (keyOrObj && typeof keyOrObj === 'object') {\r
+ noAssert = value;\r
+ for (var ikey in keyOrObj) {\r
+ // Check if virtual oneof field - don't set these\r
+ if (keyOrObj.hasOwnProperty(ikey) && typeof (value = keyOrObj[ikey]) !== 'undefined' && T._oneofsByName[ikey] === undefined)\r
+ this.$set(ikey, value, noAssert);\r
+ }\r
+ return this;\r
+ }\r
+ var field = T._fieldsByName[keyOrObj];\r
+ if (!noAssert) {\r
+ if (!field)\r
+ throw Error(this+"#"+keyOrObj+" is not a field: undefined");\r
+ if (!(field instanceof ProtoBuf.Reflect.Message.Field))\r
+ throw Error(this+"#"+keyOrObj+" is not a field: "+field.toString(true));\r
+ this[field.name] = (value = field.verifyValue(value)); // May throw\r
+ } else\r
+ this[keyOrObj] = value;\r
+ if (field && field.oneof) { // Field is part of an OneOf (not a virtual OneOf field)\r
+ var currentField = this[field.oneof.name]; // Virtual field references currently set field\r
+ if (value !== null) {\r
+ if (currentField !== null && currentField !== field.name)\r
+ this[currentField] = null; // Clear currently set field\r
+ this[field.oneof.name] = field.name; // Point virtual field at this field\r
+ } else if (/* value === null && */currentField === keyOrObj)\r
+ this[field.oneof.name] = null; // Clear virtual field (current field explicitly cleared)\r
+ }\r
+ return this;\r
+ };\r
+\r
+ /**\r
+ * Sets a field's value. This is an alias for [@link ProtoBuf.Builder.Message#set}.\r
+ * @name ProtoBuf.Builder.Message#$set\r
+ * @function\r
+ * @param {string|!Object.<string,*>} keyOrObj String key or plain object holding multiple values\r
+ * @param {(*|boolean)=} value Value to set if key is a string, otherwise omitted\r
+ * @param {boolean=} noAssert Whether to not assert the value, defaults to `false`\r
+ * @throws {Error} If the value cannot be set\r
+ * @expose\r
+ */\r
+ MessagePrototype.$set = MessagePrototype.set;\r
+\r
+ /**\r
+ * Gets a field's value.\r
+ * @name ProtoBuf.Builder.Message#get\r
+ * @function\r
+ * @param {string} key Key\r
+ * @param {boolean=} noAssert Whether to not assert for an actual field, defaults to `false`\r
+ * @return {*} Value\r
+ * @throws {Error} If there is no such field\r
+ * @expose\r
+ */\r
+ MessagePrototype.get = function(key, noAssert) {\r
+ if (noAssert)\r
+ return this[key];\r
+ var field = T._fieldsByName[key];\r
+ if (!field || !(field instanceof ProtoBuf.Reflect.Message.Field))\r
+ throw Error(this+"#"+key+" is not a field: undefined");\r
+ if (!(field instanceof ProtoBuf.Reflect.Message.Field))\r
+ throw Error(this+"#"+key+" is not a field: "+field.toString(true));\r
+ return this[field.name];\r
+ };\r
+\r
+ /**\r
+ * Gets a field's value. This is an alias for {@link ProtoBuf.Builder.Message#$get}.\r
+ * @name ProtoBuf.Builder.Message#$get\r
+ * @function\r
+ * @param {string} key Key\r
+ * @return {*} Value\r
+ * @throws {Error} If there is no such field\r
+ * @expose\r
+ */\r
+ MessagePrototype.$get = MessagePrototype.get;\r
+\r
+ // Getters and setters\r
+\r
+ for (var i=0; i<fields.length; i++) {\r
+ var field = fields[i];\r
+ // no setters for extension fields as these are named by their fqn\r
+ if (field instanceof ProtoBuf.Reflect.Message.ExtensionField)\r
+ continue;\r
+\r
+ if (T.builder.options['populateAccessors'])\r
+ (function(field) {\r
+ // set/get[SomeValue]\r
+ var Name = field.originalName.replace(/(_[a-zA-Z])/g, function(match) {\r
+ return match.toUpperCase().replace('_','');\r
+ });\r
+ Name = Name.substring(0,1).toUpperCase() + Name.substring(1);\r
+\r
+ // set/get_[some_value] FIXME: Do we really need these?\r
+ var name = field.originalName.replace(/([A-Z])/g, function(match) {\r
+ return "_"+match;\r
+ });\r
+\r
+ /**\r
+ * The current field's unbound setter function.\r
+ * @function\r
+ * @param {*} value\r
+ * @param {boolean=} noAssert\r
+ * @returns {!ProtoBuf.Builder.Message}\r
+ * @inner\r
+ */\r
+ var setter = function(value, noAssert) {\r
+ this[field.name] = noAssert ? value : field.verifyValue(value);\r
+ return this;\r
+ };\r
+\r
+ /**\r
+ * The current field's unbound getter function.\r
+ * @function\r
+ * @returns {*}\r
+ * @inner\r
+ */\r
+ var getter = function() {\r
+ return this[field.name];\r
+ };\r
+\r
+ if (T.getChild("set"+Name) === null)\r
+ /**\r
+ * Sets a value. This method is present for each field, but only if there is no name conflict with\r
+ * another field.\r
+ * @name ProtoBuf.Builder.Message#set[SomeField]\r
+ * @function\r
+ * @param {*} value Value to set\r
+ * @param {boolean=} noAssert Whether to not assert the value, defaults to `false`\r
+ * @returns {!ProtoBuf.Builder.Message} this\r
+ * @abstract\r
+ * @throws {Error} If the value cannot be set\r
+ */\r
+ MessagePrototype["set"+Name] = setter;\r
+\r
+ if (T.getChild("set_"+name) === null)\r
+ /**\r
+ * Sets a value. This method is present for each field, but only if there is no name conflict with\r
+ * another field.\r
+ * @name ProtoBuf.Builder.Message#set_[some_field]\r
+ * @function\r
+ * @param {*} value Value to set\r
+ * @param {boolean=} noAssert Whether to not assert the value, defaults to `false`\r
+ * @returns {!ProtoBuf.Builder.Message} this\r
+ * @abstract\r
+ * @throws {Error} If the value cannot be set\r
+ */\r
+ MessagePrototype["set_"+name] = setter;\r
+\r
+ if (T.getChild("get"+Name) === null)\r
+ /**\r
+ * Gets a value. This method is present for each field, but only if there is no name conflict with\r
+ * another field.\r
+ * @name ProtoBuf.Builder.Message#get[SomeField]\r
+ * @function\r
+ * @abstract\r
+ * @return {*} The value\r
+ */\r
+ MessagePrototype["get"+Name] = getter;\r
+\r
+ if (T.getChild("get_"+name) === null)\r
+ /**\r
+ * Gets a value. This method is present for each field, but only if there is no name conflict with\r
+ * another field.\r
+ * @name ProtoBuf.Builder.Message#get_[some_field]\r
+ * @function\r
+ * @return {*} The value\r
+ * @abstract\r
+ */\r
+ MessagePrototype["get_"+name] = getter;\r
+\r
+ })(field);\r
+ }\r
+\r
+ // En-/decoding\r
+\r
+ /**\r
+ * Encodes the message.\r
+ * @name ProtoBuf.Builder.Message#$encode\r
+ * @function\r
+ * @param {(!ByteBuffer|boolean)=} buffer ByteBuffer to encode to. Will create a new one and flip it if omitted.\r
+ * @param {boolean=} noVerify Whether to not verify field values, defaults to `false`\r
+ * @return {!ByteBuffer} Encoded message as a ByteBuffer\r
+ * @throws {Error} If the message cannot be encoded or if required fields are missing. The later still\r
+ * returns the encoded ByteBuffer in the `encoded` property on the error.\r
+ * @expose\r
+ * @see ProtoBuf.Builder.Message#encode64\r
+ * @see ProtoBuf.Builder.Message#encodeHex\r
+ * @see ProtoBuf.Builder.Message#encodeAB\r
+ */\r
+ MessagePrototype.encode = function(buffer, noVerify) {\r
+ if (typeof buffer === 'boolean')\r
+ noVerify = buffer,\r
+ buffer = undefined;\r
+ var isNew = false;\r
+ if (!buffer)\r
+ buffer = new ByteBuffer(),\r
+ isNew = true;\r
+ var le = buffer.littleEndian;\r
+ try {\r
+ T.encode(this, buffer.LE(), noVerify);\r
+ return (isNew ? buffer.flip() : buffer).LE(le);\r
+ } catch (e) {\r
+ buffer.LE(le);\r
+ throw(e);\r
+ }\r
+ };\r
+\r
+ /**\r
+ * Encodes a message using the specified data payload.\r
+ * @param {!Object.<string,*>} data Data payload\r
+ * @param {(!ByteBuffer|boolean)=} buffer ByteBuffer to encode to. Will create a new one and flip it if omitted.\r
+ * @param {boolean=} noVerify Whether to not verify field values, defaults to `false`\r
+ * @return {!ByteBuffer} Encoded message as a ByteBuffer\r
+ * @expose\r
+ */\r
+ Message.encode = function(data, buffer, noVerify) {\r
+ return new Message(data).encode(buffer, noVerify);\r
+ };\r
+\r
+ /**\r
+ * Calculates the byte length of the message.\r
+ * @name ProtoBuf.Builder.Message#calculate\r
+ * @function\r
+ * @returns {number} Byte length\r
+ * @throws {Error} If the message cannot be calculated or if required fields are missing.\r
+ * @expose\r
+ */\r
+ MessagePrototype.calculate = function() {\r
+ return T.calculate(this);\r
+ };\r
+\r
+ /**\r
+ * Encodes the varint32 length-delimited message.\r
+ * @name ProtoBuf.Builder.Message#encodeDelimited\r
+ * @function\r
+ * @param {(!ByteBuffer|boolean)=} buffer ByteBuffer to encode to. Will create a new one and flip it if omitted.\r
+ * @param {boolean=} noVerify Whether to not verify field values, defaults to `false`\r
+ * @return {!ByteBuffer} Encoded message as a ByteBuffer\r
+ * @throws {Error} If the message cannot be encoded or if required fields are missing. The later still\r
+ * returns the encoded ByteBuffer in the `encoded` property on the error.\r
+ * @expose\r
+ */\r
+ MessagePrototype.encodeDelimited = function(buffer, noVerify) {\r
+ var isNew = false;\r
+ if (!buffer)\r
+ buffer = new ByteBuffer(),\r
+ isNew = true;\r
+ var enc = new ByteBuffer().LE();\r
+ T.encode(this, enc, noVerify).flip();\r
+ buffer.writeVarint32(enc.remaining());\r
+ buffer.append(enc);\r
+ return isNew ? buffer.flip() : buffer;\r
+ };\r
+\r
+ /**\r
+ * Directly encodes the message to an ArrayBuffer.\r
+ * @name ProtoBuf.Builder.Message#encodeAB\r
+ * @function\r
+ * @return {ArrayBuffer} Encoded message as ArrayBuffer\r
+ * @throws {Error} If the message cannot be encoded or if required fields are missing. The later still\r
+ * returns the encoded ArrayBuffer in the `encoded` property on the error.\r
+ * @expose\r
+ */\r
+ MessagePrototype.encodeAB = function() {\r
+ try {\r
+ return this.encode().toArrayBuffer();\r
+ } catch (e) {\r
+ if (e["encoded"]) e["encoded"] = e["encoded"].toArrayBuffer();\r
+ throw(e);\r
+ }\r
+ };\r
+\r
+ /**\r
+ * Returns the message as an ArrayBuffer. This is an alias for {@link ProtoBuf.Builder.Message#encodeAB}.\r
+ * @name ProtoBuf.Builder.Message#toArrayBuffer\r
+ * @function\r
+ * @return {ArrayBuffer} Encoded message as ArrayBuffer\r
+ * @throws {Error} If the message cannot be encoded or if required fields are missing. The later still\r
+ * returns the encoded ArrayBuffer in the `encoded` property on the error.\r
+ * @expose\r
+ */\r
+ MessagePrototype.toArrayBuffer = MessagePrototype.encodeAB;\r
+\r
+ /**\r
+ * Directly encodes the message to a node Buffer.\r
+ * @name ProtoBuf.Builder.Message#encodeNB\r
+ * @function\r
+ * @return {!Buffer}\r
+ * @throws {Error} If the message cannot be encoded, not running under node.js or if required fields are\r
+ * missing. The later still returns the encoded node Buffer in the `encoded` property on the error.\r
+ * @expose\r
+ */\r
+ MessagePrototype.encodeNB = function() {\r
+ try {\r
+ return this.encode().toBuffer();\r
+ } catch (e) {\r
+ if (e["encoded"]) e["encoded"] = e["encoded"].toBuffer();\r
+ throw(e);\r
+ }\r
+ };\r
+\r
+ /**\r
+ * Returns the message as a node Buffer. This is an alias for {@link ProtoBuf.Builder.Message#encodeNB}.\r
+ * @name ProtoBuf.Builder.Message#toBuffer\r
+ * @function\r
+ * @return {!Buffer}\r
+ * @throws {Error} If the message cannot be encoded or if required fields are missing. The later still\r
+ * returns the encoded node Buffer in the `encoded` property on the error.\r
+ * @expose\r
+ */\r
+ MessagePrototype.toBuffer = MessagePrototype.encodeNB;\r
+\r
+ /**\r
+ * Directly encodes the message to a base64 encoded string.\r
+ * @name ProtoBuf.Builder.Message#encode64\r
+ * @function\r
+ * @return {string} Base64 encoded string\r
+ * @throws {Error} If the underlying buffer cannot be encoded or if required fields are missing. The later\r
+ * still returns the encoded base64 string in the `encoded` property on the error.\r
+ * @expose\r
+ */\r
+ MessagePrototype.encode64 = function() {\r
+ try {\r
+ return this.encode().toBase64();\r
+ } catch (e) {\r
+ if (e["encoded"]) e["encoded"] = e["encoded"].toBase64();\r
+ throw(e);\r
+ }\r
+ };\r
+\r
+ /**\r
+ * Returns the message as a base64 encoded string. This is an alias for {@link ProtoBuf.Builder.Message#encode64}.\r
+ * @name ProtoBuf.Builder.Message#toBase64\r
+ * @function\r
+ * @return {string} Base64 encoded string\r
+ * @throws {Error} If the message cannot be encoded or if required fields are missing. The later still\r
+ * returns the encoded base64 string in the `encoded` property on the error.\r
+ * @expose\r
+ */\r
+ MessagePrototype.toBase64 = MessagePrototype.encode64;\r
+\r
+ /**\r
+ * Directly encodes the message to a hex encoded string.\r
+ * @name ProtoBuf.Builder.Message#encodeHex\r
+ * @function\r
+ * @return {string} Hex encoded string\r
+ * @throws {Error} If the underlying buffer cannot be encoded or if required fields are missing. The later\r
+ * still returns the encoded hex string in the `encoded` property on the error.\r
+ * @expose\r
+ */\r
+ MessagePrototype.encodeHex = function() {\r
+ try {\r
+ return this.encode().toHex();\r
+ } catch (e) {\r
+ if (e["encoded"]) e["encoded"] = e["encoded"].toHex();\r
+ throw(e);\r
+ }\r
+ };\r
+\r
+ /**\r
+ * Returns the message as a hex encoded string. This is an alias for {@link ProtoBuf.Builder.Message#encodeHex}.\r
+ * @name ProtoBuf.Builder.Message#toHex\r
+ * @function\r
+ * @return {string} Hex encoded string\r
+ * @throws {Error} If the message cannot be encoded or if required fields are missing. The later still\r
+ * returns the encoded hex string in the `encoded` property on the error.\r
+ * @expose\r
+ */\r
+ MessagePrototype.toHex = MessagePrototype.encodeHex;\r
+\r
+ /**\r
+ * Clones a message object or field value to a raw object.\r
+ * @param {*} obj Object to clone\r
+ * @param {boolean} binaryAsBase64 Whether to include binary data as base64 strings or as a buffer otherwise\r
+ * @param {boolean} longsAsStrings Whether to encode longs as strings\r
+ * @param {!ProtoBuf.Reflect.T=} resolvedType The resolved field type if a field\r
+ * @returns {*} Cloned object\r
+ * @inner\r
+ */\r
+ function cloneRaw(obj, binaryAsBase64, longsAsStrings, resolvedType) {\r
+ if (obj === null || typeof obj !== 'object') {\r
+ // Convert enum values to their respective names\r
+ if (resolvedType && resolvedType instanceof ProtoBuf.Reflect.Enum) {\r
+ var name = ProtoBuf.Reflect.Enum.getName(resolvedType.object, obj);\r
+ if (name !== null)\r
+ return name;\r
+ }\r
+ // Pass-through string, number, boolean, null...\r
+ return obj;\r
+ }\r
+ // Convert ByteBuffers to raw buffer or strings\r
+ if (ByteBuffer.isByteBuffer(obj))\r
+ return binaryAsBase64 ? obj.toBase64() : obj.toBuffer();\r
+ // Convert Longs to proper objects or strings\r
+ if (ProtoBuf.Long.isLong(obj))\r
+ return longsAsStrings ? obj.toString() : ProtoBuf.Long.fromValue(obj);\r
+ var clone;\r
+ // Clone arrays\r
+ if (Array.isArray(obj)) {\r
+ clone = [];\r
+ obj.forEach(function(v, k) {\r
+ clone[k] = cloneRaw(v, binaryAsBase64, longsAsStrings, resolvedType);\r
+ });\r
+ return clone;\r
+ }\r
+ clone = {};\r
+ // Convert maps to objects\r
+ if (obj instanceof ProtoBuf.Map) {\r
+ var it = obj.entries();\r
+ for (var e = it.next(); !e.done; e = it.next())\r
+ clone[obj.keyElem.valueToString(e.value[0])] = cloneRaw(e.value[1], binaryAsBase64, longsAsStrings, obj.valueElem.resolvedType);\r
+ return clone;\r
+ }\r
+ // Everything else is a non-null object\r
+ var type = obj.$type,\r
+ field = undefined;\r
+ for (var i in obj)\r
+ if (obj.hasOwnProperty(i)) {\r
+ if (type && (field = type.getChild(i)))\r
+ clone[i] = cloneRaw(obj[i], binaryAsBase64, longsAsStrings, field.resolvedType);\r
+ else\r
+ clone[i] = cloneRaw(obj[i], binaryAsBase64, longsAsStrings);\r
+ }\r
+ return clone;\r
+ }\r
+\r
+ /**\r
+ * Returns the message's raw payload.\r
+ * @param {boolean=} binaryAsBase64 Whether to include binary data as base64 strings instead of Buffers, defaults to `false`\r
+ * @param {boolean} longsAsStrings Whether to encode longs as strings\r
+ * @returns {Object.<string,*>} Raw payload\r
+ * @expose\r
+ */\r
+ MessagePrototype.toRaw = function(binaryAsBase64, longsAsStrings) {\r
+ return cloneRaw(this, !!binaryAsBase64, !!longsAsStrings, this.$type);\r
+ };\r
+\r
+ /**\r
+ * Encodes a message to JSON.\r
+ * @returns {string} JSON string\r
+ * @expose\r
+ */\r
+ MessagePrototype.encodeJSON = function() {\r
+ return JSON.stringify(\r
+ cloneRaw(this,\r
+ /* binary-as-base64 */ true,\r
+ /* longs-as-strings */ true,\r
+ this.$type\r
+ )\r
+ );\r
+ };\r
+\r
+ /**\r
+ * Decodes a message from the specified buffer or string.\r
+ * @name ProtoBuf.Builder.Message.decode\r
+ * @function\r
+ * @param {!ByteBuffer|!ArrayBuffer|!Buffer|string} buffer Buffer to decode from\r
+ * @param {(number|string)=} length Message length. Defaults to decode all the remainig data.\r
+ * @param {string=} enc Encoding if buffer is a string: hex, utf8 (not recommended), defaults to base64\r
+ * @return {!ProtoBuf.Builder.Message} Decoded message\r
+ * @throws {Error} If the message cannot be decoded or if required fields are missing. The later still\r
+ * returns the decoded message with missing fields in the `decoded` property on the error.\r
+ * @expose\r
+ * @see ProtoBuf.Builder.Message.decode64\r
+ * @see ProtoBuf.Builder.Message.decodeHex\r
+ */\r
+ Message.decode = function(buffer, length, enc) {\r
+ if (typeof length === 'string')\r
+ enc = length,\r
+ length = -1;\r
+ if (typeof buffer === 'string')\r
+ buffer = ByteBuffer.wrap(buffer, enc ? enc : "base64");\r
+ else if (!ByteBuffer.isByteBuffer(buffer))\r
+ buffer = ByteBuffer.wrap(buffer); // May throw\r
+ var le = buffer.littleEndian;\r
+ try {\r
+ var msg = T.decode(buffer.LE(), length);\r
+ buffer.LE(le);\r
+ return msg;\r
+ } catch (e) {\r
+ buffer.LE(le);\r
+ throw(e);\r
+ }\r
+ };\r
+\r
+ /**\r
+ * Decodes a varint32 length-delimited message from the specified buffer or string.\r
+ * @name ProtoBuf.Builder.Message.decodeDelimited\r
+ * @function\r
+ * @param {!ByteBuffer|!ArrayBuffer|!Buffer|string} buffer Buffer to decode from\r
+ * @param {string=} enc Encoding if buffer is a string: hex, utf8 (not recommended), defaults to base64\r
+ * @return {ProtoBuf.Builder.Message} Decoded message or `null` if not enough bytes are available yet\r
+ * @throws {Error} If the message cannot be decoded or if required fields are missing. The later still\r
+ * returns the decoded message with missing fields in the `decoded` property on the error.\r
+ * @expose\r
+ */\r
+ Message.decodeDelimited = function(buffer, enc) {\r
+ if (typeof buffer === 'string')\r
+ buffer = ByteBuffer.wrap(buffer, enc ? enc : "base64");\r
+ else if (!ByteBuffer.isByteBuffer(buffer))\r
+ buffer = ByteBuffer.wrap(buffer); // May throw\r
+ if (buffer.remaining() < 1)\r
+ return null;\r
+ var off = buffer.offset,\r
+ len = buffer.readVarint32();\r
+ if (buffer.remaining() < len) {\r
+ buffer.offset = off;\r
+ return null;\r
+ }\r
+ try {\r
+ var msg = T.decode(buffer.slice(buffer.offset, buffer.offset + len).LE());\r
+ buffer.offset += len;\r
+ return msg;\r
+ } catch (err) {\r
+ buffer.offset += len;\r
+ throw err;\r
+ }\r
+ };\r
+\r
+ /**\r
+ * Decodes the message from the specified base64 encoded string.\r
+ * @name ProtoBuf.Builder.Message.decode64\r
+ * @function\r
+ * @param {string} str String to decode from\r
+ * @return {!ProtoBuf.Builder.Message} Decoded message\r
+ * @throws {Error} If the message cannot be decoded or if required fields are missing. The later still\r
+ * returns the decoded message with missing fields in the `decoded` property on the error.\r
+ * @expose\r
+ */\r
+ Message.decode64 = function(str) {\r
+ return Message.decode(str, "base64");\r
+ };\r
+\r
+ /**\r
+ * Decodes the message from the specified hex encoded string.\r
+ * @name ProtoBuf.Builder.Message.decodeHex\r
+ * @function\r
+ * @param {string} str String to decode from\r
+ * @return {!ProtoBuf.Builder.Message} Decoded message\r
+ * @throws {Error} If the message cannot be decoded or if required fields are missing. The later still\r
+ * returns the decoded message with missing fields in the `decoded` property on the error.\r
+ * @expose\r
+ */\r
+ Message.decodeHex = function(str) {\r
+ return Message.decode(str, "hex");\r
+ };\r
+\r
+ /**\r
+ * Decodes the message from a JSON string.\r
+ * @name ProtoBuf.Builder.Message.decodeJSON\r
+ * @function\r
+ * @param {string} str String to decode from\r
+ * @return {!ProtoBuf.Builder.Message} Decoded message\r
+ * @throws {Error} If the message cannot be decoded or if required fields are\r
+ * missing.\r
+ * @expose\r
+ */\r
+ Message.decodeJSON = function(str) {\r
+ return new Message(JSON.parse(str));\r
+ };\r
+\r
+ // Utility\r
+\r
+ /**\r
+ * Returns a string representation of this Message.\r
+ * @name ProtoBuf.Builder.Message#toString\r
+ * @function\r
+ * @return {string} String representation as of ".Fully.Qualified.MessageName"\r
+ * @expose\r
+ */\r
+ MessagePrototype.toString = function() {\r
+ return T.toString();\r
+ };\r
+\r
+ // Properties\r
+\r
+ /**\r
+ * Message options.\r
+ * @name ProtoBuf.Builder.Message.$options\r
+ * @type {Object.<string,*>}\r
+ * @expose\r
+ */\r
+ var $optionsS; // cc needs this\r
+\r
+ /**\r
+ * Message options.\r
+ * @name ProtoBuf.Builder.Message#$options\r
+ * @type {Object.<string,*>}\r
+ * @expose\r
+ */\r
+ var $options;\r
+\r
+ /**\r
+ * Reflection type.\r
+ * @name ProtoBuf.Builder.Message.$type\r
+ * @type {!ProtoBuf.Reflect.Message}\r
+ * @expose\r
+ */\r
+ var $typeS;\r
+\r
+ /**\r
+ * Reflection type.\r
+ * @name ProtoBuf.Builder.Message#$type\r
+ * @type {!ProtoBuf.Reflect.Message}\r
+ * @expose\r
+ */\r
+ var $type;\r
+\r
+ if (Object.defineProperty)\r
+ Object.defineProperty(Message, '$options', { "value": T.buildOpt() }),\r
+ Object.defineProperty(MessagePrototype, "$options", { "value": Message["$options"] }),\r
+ Object.defineProperty(Message, "$type", { "value": T }),\r
+ Object.defineProperty(MessagePrototype, "$type", { "value": T });\r
+\r
+ return Message;\r
+\r
+ })(ProtoBuf, this);\r
+\r
+ // Static enums and prototyped sub-messages / cached collections\r
+ this._fields = [];\r
+ this._fieldsById = {};\r
+ this._fieldsByName = {};\r
+ this._oneofsByName = {};\r
+ for (var i=0, k=this.children.length, child; i<k; i++) {\r
+ child = this.children[i];\r
+ if (child instanceof Enum || child instanceof Message || child instanceof Service) {\r
+ if (clazz.hasOwnProperty(child.name))\r
+ throw Error("Illegal reflect child of "+this.toString(true)+": "+child.toString(true)+" cannot override static property '"+child.name+"'");\r
+ clazz[child.name] = child.build();\r
+ } else if (child instanceof Message.Field)\r
+ child.build(),\r
+ this._fields.push(child),\r
+ this._fieldsById[child.id] = child,\r
+ this._fieldsByName[child.name] = child;\r
+ else if (child instanceof Message.OneOf) {\r
+ this._oneofsByName[child.name] = child;\r
+ }\r
+ else if (!(child instanceof Message.OneOf) && !(child instanceof Extension)) // Not built\r
+ throw Error("Illegal reflect child of "+this.toString(true)+": "+this.children[i].toString(true));\r
+ }\r
+\r
+ return this.clazz = clazz;\r
+ };\r
+\r
+ /**\r
+ * Encodes a runtime message's contents to the specified buffer.\r
+ * @param {!ProtoBuf.Builder.Message} message Runtime message to encode\r
+ * @param {ByteBuffer} buffer ByteBuffer to write to\r
+ * @param {boolean=} noVerify Whether to not verify field values, defaults to `false`\r
+ * @return {ByteBuffer} The ByteBuffer for chaining\r
+ * @throws {Error} If required fields are missing or the message cannot be encoded for another reason\r
+ * @expose\r
+ */\r
+ MessagePrototype.encode = function(message, buffer, noVerify) {\r
+ var fieldMissing = null,\r
+ field;\r
+ for (var i=0, k=this._fields.length, val; i<k; ++i) {\r
+ field = this._fields[i];\r
+ val = message[field.name];\r
+ if (field.required && val === null) {\r
+ if (fieldMissing === null)\r
+ fieldMissing = field;\r
+ } else\r
+ field.encode(noVerify ? val : field.verifyValue(val), buffer, message);\r
+ }\r
+ if (fieldMissing !== null) {\r
+ var err = Error("Missing at least one required field for "+this.toString(true)+": "+fieldMissing);\r
+ err["encoded"] = buffer; // Still expose what we got\r
+ throw(err);\r
+ }\r
+ return buffer;\r
+ };\r
+\r
+ /**\r
+ * Calculates a runtime message's byte length.\r
+ * @param {!ProtoBuf.Builder.Message} message Runtime message to encode\r
+ * @returns {number} Byte length\r
+ * @throws {Error} If required fields are missing or the message cannot be calculated for another reason\r
+ * @expose\r
+ */\r
+ MessagePrototype.calculate = function(message) {\r
+ for (var n=0, i=0, k=this._fields.length, field, val; i<k; ++i) {\r
+ field = this._fields[i];\r
+ val = message[field.name];\r
+ if (field.required && val === null)\r
+ throw Error("Missing at least one required field for "+this.toString(true)+": "+field);\r
+ else\r
+ n += field.calculate(val, message);\r
+ }\r
+ return n;\r
+ };\r
+\r
+ /**\r
+ * Skips all data until the end of the specified group has been reached.\r
+ * @param {number} expectedId Expected GROUPEND id\r
+ * @param {!ByteBuffer} buf ByteBuffer\r
+ * @returns {boolean} `true` if a value as been skipped, `false` if the end has been reached\r
+ * @throws {Error} If it wasn't possible to find the end of the group (buffer overrun or end tag mismatch)\r
+ * @inner\r
+ */\r
+ function skipTillGroupEnd(expectedId, buf) {\r
+ var tag = buf.readVarint32(), // Throws on OOB\r
+ wireType = tag & 0x07,\r
+ id = tag >>> 3;\r
+ switch (wireType) {\r
+ case ProtoBuf.WIRE_TYPES.VARINT:\r
+ do tag = buf.readUint8();\r
+ while ((tag & 0x80) === 0x80);\r
+ break;\r
+ case ProtoBuf.WIRE_TYPES.BITS64:\r
+ buf.offset += 8;\r
+ break;\r
+ case ProtoBuf.WIRE_TYPES.LDELIM:\r
+ tag = buf.readVarint32(); // reads the varint\r
+ buf.offset += tag; // skips n bytes\r
+ break;\r
+ case ProtoBuf.WIRE_TYPES.STARTGROUP:\r
+ skipTillGroupEnd(id, buf);\r
+ break;\r
+ case ProtoBuf.WIRE_TYPES.ENDGROUP:\r
+ if (id === expectedId)\r
+ return false;\r
+ else\r
+ throw Error("Illegal GROUPEND after unknown group: "+id+" ("+expectedId+" expected)");\r
+ case ProtoBuf.WIRE_TYPES.BITS32:\r
+ buf.offset += 4;\r
+ break;\r
+ default:\r
+ throw Error("Illegal wire type in unknown group "+expectedId+": "+wireType);\r
+ }\r
+ return true;\r
+ }\r
+\r
+ /**\r
+ * Decodes an encoded message and returns the decoded message.\r
+ * @param {ByteBuffer} buffer ByteBuffer to decode from\r
+ * @param {number=} length Message length. Defaults to decode all remaining data.\r
+ * @param {number=} expectedGroupEndId Expected GROUPEND id if this is a legacy group\r
+ * @return {ProtoBuf.Builder.Message} Decoded message\r
+ * @throws {Error} If the message cannot be decoded\r
+ * @expose\r
+ */\r
+ MessagePrototype.decode = function(buffer, length, expectedGroupEndId) {\r
+ if (typeof length !== 'number')\r
+ length = -1;\r
+ var start = buffer.offset,\r
+ msg = new (this.clazz)(),\r
+ tag, wireType, id, field;\r
+ while (buffer.offset < start+length || (length === -1 && buffer.remaining() > 0)) {\r
+ tag = buffer.readVarint32();\r
+ wireType = tag & 0x07;\r
+ id = tag >>> 3;\r
+ if (wireType === ProtoBuf.WIRE_TYPES.ENDGROUP) {\r
+ if (id !== expectedGroupEndId)\r
+ throw Error("Illegal group end indicator for "+this.toString(true)+": "+id+" ("+(expectedGroupEndId ? expectedGroupEndId+" expected" : "not a group")+")");\r
+ break;\r
+ }\r
+ if (!(field = this._fieldsById[id])) {\r
+ // "messages created by your new code can be parsed by your old code: old binaries simply ignore the new field when parsing."\r
+ switch (wireType) {\r
+ case ProtoBuf.WIRE_TYPES.VARINT:\r
+ buffer.readVarint32();\r
+ break;\r
+ case ProtoBuf.WIRE_TYPES.BITS32:\r
+ buffer.offset += 4;\r
+ break;\r
+ case ProtoBuf.WIRE_TYPES.BITS64:\r
+ buffer.offset += 8;\r
+ break;\r
+ case ProtoBuf.WIRE_TYPES.LDELIM:\r
+ var len = buffer.readVarint32();\r
+ buffer.offset += len;\r
+ break;\r
+ case ProtoBuf.WIRE_TYPES.STARTGROUP:\r
+ while (skipTillGroupEnd(id, buffer)) {}\r
+ break;\r
+ default:\r
+ throw Error("Illegal wire type for unknown field "+id+" in "+this.toString(true)+"#decode: "+wireType);\r
+ }\r
+ continue;\r
+ }\r
+ if (field.repeated && !field.options["packed"]) {\r
+ msg[field.name].push(field.decode(wireType, buffer));\r
+ } else if (field.map) {\r
+ var keyval = field.decode(wireType, buffer);\r
+ msg[field.name].set(keyval[0], keyval[1]);\r
+ } else {\r
+ msg[field.name] = field.decode(wireType, buffer);\r
+ if (field.oneof) { // Field is part of an OneOf (not a virtual OneOf field)\r
+ var currentField = msg[field.oneof.name]; // Virtual field references currently set field\r
+ if (currentField !== null && currentField !== field.name)\r
+ msg[currentField] = null; // Clear currently set field\r
+ msg[field.oneof.name] = field.name; // Point virtual field at this field\r
+ }\r
+ }\r
+ }\r
+\r
+ // Check if all required fields are present and set default values for optional fields that are not\r
+ for (var i=0, k=this._fields.length; i<k; ++i) {\r
+ field = this._fields[i];\r
+ if (msg[field.name] === null) {\r
+ if (this.syntax === "proto3") { // Proto3 sets default values by specification\r
+ msg[field.name] = field.defaultValue;\r
+ } else if (field.required) {\r
+ var err = Error("Missing at least one required field for " + this.toString(true) + ": " + field.name);\r
+ err["decoded"] = msg; // Still expose what we got\r
+ throw(err);\r
+ } else if (ProtoBuf.populateDefaults && field.defaultValue !== null)\r
+ msg[field.name] = field.defaultValue;\r
+ }\r
+ }\r
+ return msg;\r
+ };\r
+\r
+ /**\r
+ * @alias ProtoBuf.Reflect.Message\r
+ * @expose\r
+ */\r
+ Reflect.Message = Message;\r
+\r
+ /**\r
+ * Constructs a new Message Field.\r
+ * @exports ProtoBuf.Reflect.Message.Field\r
+ * @param {!ProtoBuf.Builder} builder Builder reference\r
+ * @param {!ProtoBuf.Reflect.Message} message Message reference\r
+ * @param {string} rule Rule, one of requried, optional, repeated\r
+ * @param {string?} keytype Key data type, if any.\r
+ * @param {string} type Data type, e.g. int32\r
+ * @param {string} name Field name\r
+ * @param {number} id Unique field id\r
+ * @param {Object.<string,*>=} options Options\r
+ * @param {!ProtoBuf.Reflect.Message.OneOf=} oneof Enclosing OneOf\r
+ * @param {string?} syntax The syntax level of this definition (e.g., proto3)\r
+ * @constructor\r
+ * @extends ProtoBuf.Reflect.T\r
+ */\r
+ var Field = function(builder, message, rule, keytype, type, name, id, options, oneof, syntax) {\r
+ T.call(this, builder, message, name);\r
+\r
+ /**\r
+ * @override\r
+ */\r
+ this.className = "Message.Field";\r
+\r
+ /**\r
+ * Message field required flag.\r
+ * @type {boolean}\r
+ * @expose\r
+ */\r
+ this.required = rule === "required";\r
+\r
+ /**\r
+ * Message field repeated flag.\r
+ * @type {boolean}\r
+ * @expose\r
+ */\r
+ this.repeated = rule === "repeated";\r
+\r
+ /**\r
+ * Message field map flag.\r
+ * @type {boolean}\r
+ * @expose\r
+ */\r
+ this.map = rule === "map";\r
+\r
+ /**\r
+ * Message field key type. Type reference string if unresolved, protobuf\r
+ * type if resolved. Valid only if this.map === true, null otherwise.\r
+ * @type {string|{name: string, wireType: number}|null}\r
+ * @expose\r
+ */\r
+ this.keyType = keytype || null;\r
+\r
+ /**\r
+ * Message field type. Type reference string if unresolved, protobuf type if\r
+ * resolved. In a map field, this is the value type.\r
+ * @type {string|{name: string, wireType: number}}\r
+ * @expose\r
+ */\r
+ this.type = type;\r
+\r
+ /**\r
+ * Resolved type reference inside the global namespace.\r
+ * @type {ProtoBuf.Reflect.T|null}\r
+ * @expose\r
+ */\r
+ this.resolvedType = null;\r
+\r
+ /**\r
+ * Unique message field id.\r
+ * @type {number}\r
+ * @expose\r
+ */\r
+ this.id = id;\r
+\r
+ /**\r
+ * Message field options.\r
+ * @type {!Object.<string,*>}\r
+ * @dict\r
+ * @expose\r
+ */\r
+ this.options = options || {};\r
+\r
+ /**\r
+ * Default value.\r
+ * @type {*}\r
+ * @expose\r
+ */\r
+ this.defaultValue = null;\r
+\r
+ /**\r
+ * Enclosing OneOf.\r
+ * @type {?ProtoBuf.Reflect.Message.OneOf}\r
+ * @expose\r
+ */\r
+ this.oneof = oneof || null;\r
+\r
+ /**\r
+ * Syntax level of this definition (e.g., proto3).\r
+ * @type {string}\r
+ * @expose\r
+ */\r
+ this.syntax = syntax || 'proto2';\r
+\r
+ /**\r
+ * Original field name.\r
+ * @type {string}\r
+ * @expose\r
+ */\r
+ this.originalName = this.name; // Used to revert camelcase transformation on naming collisions\r
+\r
+ /**\r
+ * Element implementation. Created in build() after types are resolved.\r
+ * @type {ProtoBuf.Element}\r
+ * @expose\r
+ */\r
+ this.element = null;\r
+\r
+ /**\r
+ * Key element implementation, for map fields. Created in build() after\r
+ * types are resolved.\r
+ * @type {ProtoBuf.Element}\r
+ * @expose\r
+ */\r
+ this.keyElement = null;\r
+\r
+ // Convert field names to camel case notation if the override is set\r
+ if (this.builder.options['convertFieldsToCamelCase'] && !(this instanceof Message.ExtensionField))\r
+ this.name = ProtoBuf.Util.toCamelCase(this.name);\r
+ };\r
+\r
+ /**\r
+ * @alias ProtoBuf.Reflect.Message.Field.prototype\r
+ * @inner\r
+ */\r
+ var FieldPrototype = Field.prototype = Object.create(T.prototype);\r
+\r
+ /**\r
+ * Builds the field.\r
+ * @override\r
+ * @expose\r
+ */\r
+ FieldPrototype.build = function() {\r
+ this.element = new Element(this.type, this.resolvedType, false, this.syntax, this.name);\r
+ if (this.map)\r
+ this.keyElement = new Element(this.keyType, undefined, true, this.syntax, this.name);\r
+\r
+ // In proto3, fields do not have field presence, and every field is set to\r
+ // its type's default value ("", 0, 0.0, or false).\r
+ if (this.syntax === 'proto3' && !this.repeated && !this.map)\r
+ this.defaultValue = Element.defaultFieldValue(this.type);\r
+\r
+ // Otherwise, default values are present when explicitly specified\r
+ else if (typeof this.options['default'] !== 'undefined')\r
+ this.defaultValue = this.verifyValue(this.options['default']);\r
+ };\r
+\r
+ /**\r
+ * Checks if the given value can be set for this field.\r
+ * @param {*} value Value to check\r
+ * @param {boolean=} skipRepeated Whether to skip the repeated value check or not. Defaults to false.\r
+ * @return {*} Verified, maybe adjusted, value\r
+ * @throws {Error} If the value cannot be set for this field\r
+ * @expose\r
+ */\r
+ FieldPrototype.verifyValue = function(value, skipRepeated) {\r
+ skipRepeated = skipRepeated || false;\r
+ var self = this;\r
+ function fail(val, msg) {\r
+ throw Error("Illegal value for "+self.toString(true)+" of type "+self.type.name+": "+val+" ("+msg+")");\r
+ }\r
+ if (value === null) { // NULL values for optional fields\r
+ if (this.required)\r
+ fail(typeof value, "required");\r
+ if (this.syntax === 'proto3' && this.type !== ProtoBuf.TYPES["message"])\r
+ fail(typeof value, "proto3 field without field presence cannot be null");\r
+ return null;\r
+ }\r
+ var i;\r
+ if (this.repeated && !skipRepeated) { // Repeated values as arrays\r
+ if (!Array.isArray(value))\r
+ value = [value];\r
+ var res = [];\r
+ for (i=0; i<value.length; i++)\r
+ res.push(this.element.verifyValue(value[i]));\r
+ return res;\r
+ }\r
+ if (this.map && !skipRepeated) { // Map values as objects\r
+ if (!(value instanceof ProtoBuf.Map)) {\r
+ // If not already a Map, attempt to convert.\r
+ if (!(value instanceof Object)) {\r
+ fail(typeof value,\r
+ "expected ProtoBuf.Map or raw object for map field");\r
+ }\r
+ return new ProtoBuf.Map(this, value);\r
+ } else {\r
+ return value;\r
+ }\r
+ }\r
+ // All non-repeated fields expect no array\r
+ if (!this.repeated && Array.isArray(value))\r
+ fail(typeof value, "no array expected");\r
+\r
+ return this.element.verifyValue(value);\r
+ };\r
+\r
+ /**\r
+ * Determines whether the field will have a presence on the wire given its\r
+ * value.\r
+ * @param {*} value Verified field value\r
+ * @param {!ProtoBuf.Builder.Message} message Runtime message\r
+ * @return {boolean} Whether the field will be present on the wire\r
+ */\r
+ FieldPrototype.hasWirePresence = function(value, message) {\r
+ if (this.syntax !== 'proto3')\r
+ return (value !== null);\r
+ if (this.oneof && message[this.oneof.name] === this.name)\r
+ return true;\r
+ switch (this.type) {\r
+ case ProtoBuf.TYPES["int32"]:\r
+ case ProtoBuf.TYPES["sint32"]:\r
+ case ProtoBuf.TYPES["sfixed32"]:\r
+ case ProtoBuf.TYPES["uint32"]:\r
+ case ProtoBuf.TYPES["fixed32"]:\r
+ return value !== 0;\r
+\r
+ case ProtoBuf.TYPES["int64"]:\r
+ case ProtoBuf.TYPES["sint64"]:\r
+ case ProtoBuf.TYPES["sfixed64"]:\r
+ case ProtoBuf.TYPES["uint64"]:\r
+ case ProtoBuf.TYPES["fixed64"]:\r
+ return value.low !== 0 || value.high !== 0;\r
+\r
+ case ProtoBuf.TYPES["bool"]:\r
+ return value;\r
+\r
+ case ProtoBuf.TYPES["float"]:\r
+ case ProtoBuf.TYPES["double"]:\r
+ return value !== 0.0;\r
+\r
+ case ProtoBuf.TYPES["string"]:\r
+ return value.length > 0;\r
+\r
+ case ProtoBuf.TYPES["bytes"]:\r
+ return value.remaining() > 0;\r
+\r
+ case ProtoBuf.TYPES["enum"]:\r
+ return value !== 0;\r
+\r
+ case ProtoBuf.TYPES["message"]:\r
+ return value !== null;\r
+ default:\r
+ return true;\r
+ }\r
+ };\r
+\r
+ /**\r
+ * Encodes the specified field value to the specified buffer.\r
+ * @param {*} value Verified field value\r
+ * @param {ByteBuffer} buffer ByteBuffer to encode to\r
+ * @param {!ProtoBuf.Builder.Message} message Runtime message\r
+ * @return {ByteBuffer} The ByteBuffer for chaining\r
+ * @throws {Error} If the field cannot be encoded\r
+ * @expose\r
+ */\r
+ FieldPrototype.encode = function(value, buffer, message) {\r
+ if (this.type === null || typeof this.type !== 'object')\r
+ throw Error("[INTERNAL] Unresolved type in "+this.toString(true)+": "+this.type);\r
+ if (value === null || (this.repeated && value.length == 0))\r
+ return buffer; // Optional omitted\r
+ try {\r
+ if (this.repeated) {\r
+ var i;\r
+ // "Only repeated fields of primitive numeric types (types which use the varint, 32-bit, or 64-bit wire\r
+ // types) can be declared 'packed'."\r
+ if (this.options["packed"] && ProtoBuf.PACKABLE_WIRE_TYPES.indexOf(this.type.wireType) >= 0) {\r
+ // "All of the elements of the field are packed into a single key-value pair with wire type 2\r
+ // (length-delimited). Each element is encoded the same way it would be normally, except without a\r
+ // tag preceding it."\r
+ buffer.writeVarint32((this.id << 3) | ProtoBuf.WIRE_TYPES.LDELIM);\r
+ buffer.ensureCapacity(buffer.offset += 1); // We do not know the length yet, so let's assume a varint of length 1\r
+ var start = buffer.offset; // Remember where the contents begin\r
+ for (i=0; i<value.length; i++)\r
+ this.element.encodeValue(this.id, value[i], buffer);\r
+ var len = buffer.offset-start,\r
+ varintLen = ByteBuffer.calculateVarint32(len);\r
+ if (varintLen > 1) { // We need to move the contents\r
+ var contents = buffer.slice(start, buffer.offset);\r
+ start += varintLen-1;\r
+ buffer.offset = start;\r
+ buffer.append(contents);\r
+ }\r
+ buffer.writeVarint32(len, start-varintLen);\r
+ } else {\r
+ // "If your message definition has repeated elements (without the [packed=true] option), the encoded\r
+ // message has zero or more key-value pairs with the same tag number"\r
+ for (i=0; i<value.length; i++)\r
+ buffer.writeVarint32((this.id << 3) | this.type.wireType),\r
+ this.element.encodeValue(this.id, value[i], buffer);\r
+ }\r
+ } else if (this.map) {\r
+ // Write out each map entry as a submessage.\r
+ value.forEach(function(val, key, m) {\r
+ // Compute the length of the submessage (key, val) pair.\r
+ var length =\r
+ ByteBuffer.calculateVarint32((1 << 3) | this.keyType.wireType) +\r
+ this.keyElement.calculateLength(1, key) +\r
+ ByteBuffer.calculateVarint32((2 << 3) | this.type.wireType) +\r
+ this.element.calculateLength(2, val);\r
+\r
+ // Submessage with wire type of length-delimited.\r
+ buffer.writeVarint32((this.id << 3) | ProtoBuf.WIRE_TYPES.LDELIM);\r
+ buffer.writeVarint32(length);\r
+\r
+ // Write out the key and val.\r
+ buffer.writeVarint32((1 << 3) | this.keyType.wireType);\r
+ this.keyElement.encodeValue(1, key, buffer);\r
+ buffer.writeVarint32((2 << 3) | this.type.wireType);\r
+ this.element.encodeValue(2, val, buffer);\r
+ }, this);\r
+ } else {\r
+ if (this.hasWirePresence(value, message)) {\r
+ buffer.writeVarint32((this.id << 3) | this.type.wireType);\r
+ this.element.encodeValue(this.id, value, buffer);\r
+ }\r
+ }\r
+ } catch (e) {\r
+ throw Error("Illegal value for "+this.toString(true)+": "+value+" ("+e+")");\r
+ }\r
+ return buffer;\r
+ };\r
+\r
+ /**\r
+ * Calculates the length of this field's value on the network level.\r
+ * @param {*} value Field value\r
+ * @param {!ProtoBuf.Builder.Message} message Runtime message\r
+ * @returns {number} Byte length\r
+ * @expose\r
+ */\r
+ FieldPrototype.calculate = function(value, message) {\r
+ value = this.verifyValue(value); // May throw\r
+ if (this.type === null || typeof this.type !== 'object')\r
+ throw Error("[INTERNAL] Unresolved type in "+this.toString(true)+": "+this.type);\r
+ if (value === null || (this.repeated && value.length == 0))\r
+ return 0; // Optional omitted\r
+ var n = 0;\r
+ try {\r
+ if (this.repeated) {\r
+ var i, ni;\r
+ if (this.options["packed"] && ProtoBuf.PACKABLE_WIRE_TYPES.indexOf(this.type.wireType) >= 0) {\r
+ n += ByteBuffer.calculateVarint32((this.id << 3) | ProtoBuf.WIRE_TYPES.LDELIM);\r
+ ni = 0;\r
+ for (i=0; i<value.length; i++)\r
+ ni += this.element.calculateLength(this.id, value[i]);\r
+ n += ByteBuffer.calculateVarint32(ni);\r
+ n += ni;\r
+ } else {\r
+ for (i=0; i<value.length; i++)\r
+ n += ByteBuffer.calculateVarint32((this.id << 3) | this.type.wireType),\r
+ n += this.element.calculateLength(this.id, value[i]);\r
+ }\r
+ } else if (this.map) {\r
+ // Each map entry becomes a submessage.\r
+ value.forEach(function(val, key, m) {\r
+ // Compute the length of the submessage (key, val) pair.\r
+ var length =\r
+ ByteBuffer.calculateVarint32((1 << 3) | this.keyType.wireType) +\r
+ this.keyElement.calculateLength(1, key) +\r
+ ByteBuffer.calculateVarint32((2 << 3) | this.type.wireType) +\r
+ this.element.calculateLength(2, val);\r
+\r
+ n += ByteBuffer.calculateVarint32((this.id << 3) | ProtoBuf.WIRE_TYPES.LDELIM);\r
+ n += ByteBuffer.calculateVarint32(length);\r
+ n += length;\r
+ }, this);\r
+ } else {\r
+ if (this.hasWirePresence(value, message)) {\r
+ n += ByteBuffer.calculateVarint32((this.id << 3) | this.type.wireType);\r
+ n += this.element.calculateLength(this.id, value);\r
+ }\r
+ }\r
+ } catch (e) {\r
+ throw Error("Illegal value for "+this.toString(true)+": "+value+" ("+e+")");\r
+ }\r
+ return n;\r
+ };\r
+\r
+ /**\r
+ * Decode the field value from the specified buffer.\r
+ * @param {number} wireType Leading wire type\r
+ * @param {ByteBuffer} buffer ByteBuffer to decode from\r
+ * @param {boolean=} skipRepeated Whether to skip the repeated check or not. Defaults to false.\r
+ * @return {*} Decoded value: array for packed repeated fields, [key, value] for\r
+ * map fields, or an individual value otherwise.\r
+ * @throws {Error} If the field cannot be decoded\r
+ * @expose\r
+ */\r
+ FieldPrototype.decode = function(wireType, buffer, skipRepeated) {\r
+ var value, nBytes;\r
+\r
+ // We expect wireType to match the underlying type's wireType unless we see\r
+ // a packed repeated field, or unless this is a map field.\r
+ var wireTypeOK =\r
+ (!this.map && wireType == this.type.wireType) ||\r
+ (!skipRepeated && this.repeated && this.options["packed"] &&\r
+ wireType == ProtoBuf.WIRE_TYPES.LDELIM) ||\r
+ (this.map && wireType == ProtoBuf.WIRE_TYPES.LDELIM);\r
+ if (!wireTypeOK)\r
+ throw Error("Illegal wire type for field "+this.toString(true)+": "+wireType+" ("+this.type.wireType+" expected)");\r
+\r
+ // Handle packed repeated fields.\r
+ if (wireType == ProtoBuf.WIRE_TYPES.LDELIM && this.repeated && this.options["packed"] && ProtoBuf.PACKABLE_WIRE_TYPES.indexOf(this.type.wireType) >= 0) {\r
+ if (!skipRepeated) {\r
+ nBytes = buffer.readVarint32();\r
+ nBytes = buffer.offset + nBytes; // Limit\r
+ var values = [];\r
+ while (buffer.offset < nBytes)\r
+ values.push(this.decode(this.type.wireType, buffer, true));\r
+ return values;\r
+ }\r
+ // Read the next value otherwise...\r
+ }\r
+\r
+ // Handle maps.\r
+ if (this.map) {\r
+ // Read one (key, value) submessage, and return [key, value]\r
+ var key = Element.defaultFieldValue(this.keyType);\r
+ value = Element.defaultFieldValue(this.type);\r
+\r
+ // Read the length\r
+ nBytes = buffer.readVarint32();\r
+ if (buffer.remaining() < nBytes)\r
+ throw Error("Illegal number of bytes for "+this.toString(true)+": "+nBytes+" required but got only "+buffer.remaining());\r
+\r
+ // Get a sub-buffer of this key/value submessage\r
+ var msgbuf = buffer.clone();\r
+ msgbuf.limit = msgbuf.offset + nBytes;\r
+ buffer.offset += nBytes;\r
+\r
+ while (msgbuf.remaining() > 0) {\r
+ var tag = msgbuf.readVarint32();\r
+ wireType = tag & 0x07;\r
+ var id = tag >>> 3;\r
+ if (id === 1) {\r
+ key = this.keyElement.decode(msgbuf, wireType, id);\r
+ } else if (id === 2) {\r
+ value = this.element.decode(msgbuf, wireType, id);\r
+ } else {\r
+ throw Error("Unexpected tag in map field key/value submessage");\r
+ }\r
+ }\r
+\r
+ return [key, value];\r
+ }\r
+\r
+ // Handle singular and non-packed repeated field values.\r
+ return this.element.decode(buffer, wireType, this.id);\r
+ };\r
+\r
+ /**\r
+ * @alias ProtoBuf.Reflect.Message.Field\r
+ * @expose\r
+ */\r
+ Reflect.Message.Field = Field;\r
+\r
+ /**\r
+ * Constructs a new Message ExtensionField.\r
+ * @exports ProtoBuf.Reflect.Message.ExtensionField\r
+ * @param {!ProtoBuf.Builder} builder Builder reference\r
+ * @param {!ProtoBuf.Reflect.Message} message Message reference\r
+ * @param {string} rule Rule, one of requried, optional, repeated\r
+ * @param {string} type Data type, e.g. int32\r
+ * @param {string} name Field name\r
+ * @param {number} id Unique field id\r
+ * @param {!Object.<string,*>=} options Options\r
+ * @constructor\r
+ * @extends ProtoBuf.Reflect.Message.Field\r
+ */\r
+ var ExtensionField = function(builder, message, rule, type, name, id, options) {\r
+ Field.call(this, builder, message, rule, /* keytype = */ null, type, name, id, options);\r
+\r
+ /**\r
+ * Extension reference.\r
+ * @type {!ProtoBuf.Reflect.Extension}\r
+ * @expose\r
+ */\r
+ this.extension;\r
+ };\r
+\r
+ // Extends Field\r
+ ExtensionField.prototype = Object.create(Field.prototype);\r
+\r
+ /**\r
+ * @alias ProtoBuf.Reflect.Message.ExtensionField\r
+ * @expose\r
+ */\r
+ Reflect.Message.ExtensionField = ExtensionField;\r
+\r
+ /**\r
+ * Constructs a new Message OneOf.\r
+ * @exports ProtoBuf.Reflect.Message.OneOf\r
+ * @param {!ProtoBuf.Builder} builder Builder reference\r
+ * @param {!ProtoBuf.Reflect.Message} message Message reference\r
+ * @param {string} name OneOf name\r
+ * @constructor\r
+ * @extends ProtoBuf.Reflect.T\r
+ */\r
+ var OneOf = function(builder, message, name) {\r
+ T.call(this, builder, message, name);\r
+\r
+ /**\r
+ * Enclosed fields.\r
+ * @type {!Array.<!ProtoBuf.Reflect.Message.Field>}\r
+ * @expose\r
+ */\r
+ this.fields = [];\r
+ };\r
+\r
+ /**\r
+ * @alias ProtoBuf.Reflect.Message.OneOf\r
+ * @expose\r
+ */\r
+ Reflect.Message.OneOf = OneOf;\r
+\r
+ /**\r
+ * Constructs a new Enum.\r
+ * @exports ProtoBuf.Reflect.Enum\r
+ * @param {!ProtoBuf.Builder} builder Builder reference\r
+ * @param {!ProtoBuf.Reflect.T} parent Parent Reflect object\r
+ * @param {string} name Enum name\r
+ * @param {Object.<string,*>=} options Enum options\r
+ * @param {string?} syntax The syntax level (e.g., proto3)\r
+ * @constructor\r
+ * @extends ProtoBuf.Reflect.Namespace\r
+ */\r
+ var Enum = function(builder, parent, name, options, syntax) {\r
+ Namespace.call(this, builder, parent, name, options, syntax);\r
+\r
+ /**\r
+ * @override\r
+ */\r
+ this.className = "Enum";\r
+\r
+ /**\r
+ * Runtime enum object.\r
+ * @type {Object.<string,number>|null}\r
+ * @expose\r
+ */\r
+ this.object = null;\r
+ };\r
+\r
+ /**\r
+ * Gets the string name of an enum value.\r
+ * @param {!ProtoBuf.Builder.Enum} enm Runtime enum\r
+ * @param {number} value Enum value\r
+ * @returns {?string} Name or `null` if not present\r
+ * @expose\r
+ */\r
+ Enum.getName = function(enm, value) {\r
+ var keys = Object.keys(enm);\r
+ for (var i=0, key; i<keys.length; ++i)\r
+ if (enm[key = keys[i]] === value)\r
+ return key;\r
+ return null;\r
+ };\r
+\r
+ /**\r
+ * @alias ProtoBuf.Reflect.Enum.prototype\r
+ * @inner\r
+ */\r
+ var EnumPrototype = Enum.prototype = Object.create(Namespace.prototype);\r
+\r
+ /**\r
+ * Builds this enum and returns the runtime counterpart.\r
+ * @param {boolean} rebuild Whether to rebuild or not, defaults to false\r
+ * @returns {!Object.<string,number>}\r
+ * @expose\r
+ */\r
+ EnumPrototype.build = function(rebuild) {\r
+ if (this.object && !rebuild)\r
+ return this.object;\r
+ var enm = new ProtoBuf.Builder.Enum(),\r
+ values = this.getChildren(Enum.Value);\r
+ for (var i=0, k=values.length; i<k; ++i)\r
+ enm[values[i]['name']] = values[i]['id'];\r
+ if (Object.defineProperty)\r
+ Object.defineProperty(enm, '$options', {\r
+ "value": this.buildOpt(),\r
+ "enumerable": false\r
+ });\r
+ return this.object = enm;\r
+ };\r
+\r
+ /**\r
+ * @alias ProtoBuf.Reflect.Enum\r
+ * @expose\r
+ */\r
+ Reflect.Enum = Enum;\r
+\r
+ /**\r
+ * Constructs a new Enum Value.\r
+ * @exports ProtoBuf.Reflect.Enum.Value\r
+ * @param {!ProtoBuf.Builder} builder Builder reference\r
+ * @param {!ProtoBuf.Reflect.Enum} enm Enum reference\r
+ * @param {string} name Field name\r
+ * @param {number} id Unique field id\r
+ * @constructor\r
+ * @extends ProtoBuf.Reflect.T\r
+ */\r
+ var Value = function(builder, enm, name, id) {\r
+ T.call(this, builder, enm, name);\r
+\r
+ /**\r
+ * @override\r
+ */\r
+ this.className = "Enum.Value";\r
+\r
+ /**\r
+ * Unique enum value id.\r
+ * @type {number}\r
+ * @expose\r
+ */\r
+ this.id = id;\r
+ };\r
+\r
+ // Extends T\r
+ Value.prototype = Object.create(T.prototype);\r
+\r
+ /**\r
+ * @alias ProtoBuf.Reflect.Enum.Value\r
+ * @expose\r
+ */\r
+ Reflect.Enum.Value = Value;\r
+\r
+ /**\r
+ * An extension (field).\r
+ * @exports ProtoBuf.Reflect.Extension\r
+ * @constructor\r
+ * @param {!ProtoBuf.Builder} builder Builder reference\r
+ * @param {!ProtoBuf.Reflect.T} parent Parent object\r
+ * @param {string} name Object name\r
+ * @param {!ProtoBuf.Reflect.Message.Field} field Extension field\r
+ */\r
+ var Extension = function(builder, parent, name, field) {\r
+ T.call(this, builder, parent, name);\r
+\r
+ /**\r
+ * Extended message field.\r
+ * @type {!ProtoBuf.Reflect.Message.Field}\r
+ * @expose\r
+ */\r
+ this.field = field;\r
+ };\r
+\r
+ // Extends T\r
+ Extension.prototype = Object.create(T.prototype);\r
+\r
+ /**\r
+ * @alias ProtoBuf.Reflect.Extension\r
+ * @expose\r
+ */\r
+ Reflect.Extension = Extension;\r
+\r
+ /**\r
+ * Constructs a new Service.\r
+ * @exports ProtoBuf.Reflect.Service\r
+ * @param {!ProtoBuf.Builder} builder Builder reference\r
+ * @param {!ProtoBuf.Reflect.Namespace} root Root\r
+ * @param {string} name Service name\r
+ * @param {Object.<string,*>=} options Options\r
+ * @constructor\r
+ * @extends ProtoBuf.Reflect.Namespace\r
+ */\r
+ var Service = function(builder, root, name, options) {\r
+ Namespace.call(this, builder, root, name, options);\r
+\r
+ /**\r
+ * @override\r
+ */\r
+ this.className = "Service";\r
+\r
+ /**\r
+ * Built runtime service class.\r
+ * @type {?function(new:ProtoBuf.Builder.Service)}\r
+ */\r
+ this.clazz = null;\r
+ };\r
+\r
+ /**\r
+ * @alias ProtoBuf.Reflect.Service.prototype\r
+ * @inner\r
+ */\r
+ var ServicePrototype = Service.prototype = Object.create(Namespace.prototype);\r
+\r
+ /**\r
+ * Builds the service and returns the runtime counterpart, which is a fully functional class.\r
+ * @see ProtoBuf.Builder.Service\r
+ * @param {boolean=} rebuild Whether to rebuild or not\r
+ * @return {Function} Service class\r
+ * @throws {Error} If the message cannot be built\r
+ * @expose\r
+ */\r
+ ServicePrototype.build = function(rebuild) {\r
+ if (this.clazz && !rebuild)\r
+ return this.clazz;\r
+\r
+ // Create the runtime Service class in its own scope\r
+ return this.clazz = (function(ProtoBuf, T) {\r
+\r
+ /**\r
+ * Constructs a new runtime Service.\r
+ * @name ProtoBuf.Builder.Service\r
+ * @param {function(string, ProtoBuf.Builder.Message, function(Error, ProtoBuf.Builder.Message=))=} rpcImpl RPC implementation receiving the method name and the message\r
+ * @class Barebone of all runtime services.\r
+ * @constructor\r
+ * @throws {Error} If the service cannot be created\r
+ */\r
+ var Service = function(rpcImpl) {\r
+ ProtoBuf.Builder.Service.call(this);\r
+\r
+ /**\r
+ * Service implementation.\r
+ * @name ProtoBuf.Builder.Service#rpcImpl\r
+ * @type {!function(string, ProtoBuf.Builder.Message, function(Error, ProtoBuf.Builder.Message=))}\r
+ * @expose\r
+ */\r
+ this.rpcImpl = rpcImpl || function(name, msg, callback) {\r
+ // This is what a user has to implement: A function receiving the method name, the actual message to\r
+ // send (type checked) and the callback that's either provided with the error as its first\r
+ // argument or null and the actual response message.\r
+ setTimeout(callback.bind(this, Error("Not implemented, see: https://github.com/dcodeIO/ProtoBuf.js/wiki/Services")), 0); // Must be async!\r
+ };\r
+ };\r
+\r
+ /**\r
+ * @alias ProtoBuf.Builder.Service.prototype\r
+ * @inner\r
+ */\r
+ var ServicePrototype = Service.prototype = Object.create(ProtoBuf.Builder.Service.prototype);\r
+\r
+ /**\r
+ * Asynchronously performs an RPC call using the given RPC implementation.\r
+ * @name ProtoBuf.Builder.Service.[Method]\r
+ * @function\r
+ * @param {!function(string, ProtoBuf.Builder.Message, function(Error, ProtoBuf.Builder.Message=))} rpcImpl RPC implementation\r
+ * @param {ProtoBuf.Builder.Message} req Request\r
+ * @param {function(Error, (ProtoBuf.Builder.Message|ByteBuffer|Buffer|string)=)} callback Callback receiving\r
+ * the error if any and the response either as a pre-parsed message or as its raw bytes\r
+ * @abstract\r
+ */\r
+\r
+ /**\r
+ * Asynchronously performs an RPC call using the instance's RPC implementation.\r
+ * @name ProtoBuf.Builder.Service#[Method]\r
+ * @function\r
+ * @param {ProtoBuf.Builder.Message} req Request\r
+ * @param {function(Error, (ProtoBuf.Builder.Message|ByteBuffer|Buffer|string)=)} callback Callback receiving\r
+ * the error if any and the response either as a pre-parsed message or as its raw bytes\r
+ * @abstract\r
+ */\r
+\r
+ var rpc = T.getChildren(ProtoBuf.Reflect.Service.RPCMethod);\r
+ for (var i=0; i<rpc.length; i++) {\r
+ (function(method) {\r
+\r
+ // service#Method(message, callback)\r
+ ServicePrototype[method.name] = function(req, callback) {\r
+ try {\r
+ try {\r
+ // If given as a buffer, decode the request. Will throw a TypeError if not a valid buffer.\r
+ req = method.resolvedRequestType.clazz.decode(ByteBuffer.wrap(req));\r
+ } catch (err) {\r
+ if (!(err instanceof TypeError))\r
+ throw err;\r
+ }\r
+ if (req === null || typeof req !== 'object')\r
+ throw Error("Illegal arguments");\r
+ if (!(req instanceof method.resolvedRequestType.clazz))\r
+ req = new method.resolvedRequestType.clazz(req);\r
+ this.rpcImpl(method.fqn(), req, function(err, res) { // Assumes that this is properly async\r
+ if (err) {\r
+ callback(err);\r
+ return;\r
+ }\r
+ // Coalesce to empty string when service response has empty content\r
+ if (res === null)\r
+ res = ''\r
+ try { res = method.resolvedResponseType.clazz.decode(res); } catch (notABuffer) {}\r
+ if (!res || !(res instanceof method.resolvedResponseType.clazz)) {\r
+ callback(Error("Illegal response type received in service method "+ T.name+"#"+method.name));\r
+ return;\r
+ }\r
+ callback(null, res);\r
+ });\r
+ } catch (err) {\r
+ setTimeout(callback.bind(this, err), 0);\r
+ }\r
+ };\r
+\r
+ // Service.Method(rpcImpl, message, callback)\r
+ Service[method.name] = function(rpcImpl, req, callback) {\r
+ new Service(rpcImpl)[method.name](req, callback);\r
+ };\r
+\r
+ if (Object.defineProperty)\r
+ Object.defineProperty(Service[method.name], "$options", { "value": method.buildOpt() }),\r
+ Object.defineProperty(ServicePrototype[method.name], "$options", { "value": Service[method.name]["$options"] });\r
+ })(rpc[i]);\r
+ }\r
+\r
+ // Properties\r
+\r
+ /**\r
+ * Service options.\r
+ * @name ProtoBuf.Builder.Service.$options\r
+ * @type {Object.<string,*>}\r
+ * @expose\r
+ */\r
+ var $optionsS; // cc needs this\r
+\r
+ /**\r
+ * Service options.\r
+ * @name ProtoBuf.Builder.Service#$options\r
+ * @type {Object.<string,*>}\r
+ * @expose\r
+ */\r
+ var $options;\r
+\r
+ /**\r
+ * Reflection type.\r
+ * @name ProtoBuf.Builder.Service.$type\r
+ * @type {!ProtoBuf.Reflect.Service}\r
+ * @expose\r
+ */\r
+ var $typeS;\r
+\r
+ /**\r
+ * Reflection type.\r
+ * @name ProtoBuf.Builder.Service#$type\r
+ * @type {!ProtoBuf.Reflect.Service}\r
+ * @expose\r
+ */\r
+ var $type;\r
+\r
+ if (Object.defineProperty)\r
+ Object.defineProperty(Service, "$options", { "value": T.buildOpt() }),\r
+ Object.defineProperty(ServicePrototype, "$options", { "value": Service["$options"] }),\r
+ Object.defineProperty(Service, "$type", { "value": T }),\r
+ Object.defineProperty(ServicePrototype, "$type", { "value": T });\r
+\r
+ return Service;\r
+\r
+ })(ProtoBuf, this);\r
+ };\r
+\r
+ /**\r
+ * @alias ProtoBuf.Reflect.Service\r
+ * @expose\r
+ */\r
+ Reflect.Service = Service;\r
+\r
+ /**\r
+ * Abstract service method.\r
+ * @exports ProtoBuf.Reflect.Service.Method\r
+ * @param {!ProtoBuf.Builder} builder Builder reference\r
+ * @param {!ProtoBuf.Reflect.Service} svc Service\r
+ * @param {string} name Method name\r
+ * @param {Object.<string,*>=} options Options\r
+ * @constructor\r
+ * @extends ProtoBuf.Reflect.T\r
+ */\r
+ var Method = function(builder, svc, name, options) {\r
+ T.call(this, builder, svc, name);\r
+\r
+ /**\r
+ * @override\r
+ */\r
+ this.className = "Service.Method";\r
+\r
+ /**\r
+ * Options.\r
+ * @type {Object.<string, *>}\r
+ * @expose\r
+ */\r
+ this.options = options || {};\r
+ };\r
+\r
+ /**\r
+ * @alias ProtoBuf.Reflect.Service.Method.prototype\r
+ * @inner\r
+ */\r
+ var MethodPrototype = Method.prototype = Object.create(T.prototype);\r
+\r
+ /**\r
+ * Builds the method's '$options' property.\r
+ * @name ProtoBuf.Reflect.Service.Method#buildOpt\r
+ * @function\r
+ * @return {Object.<string,*>}\r
+ */\r
+ MethodPrototype.buildOpt = NamespacePrototype.buildOpt;\r
+\r
+ /**\r
+ * @alias ProtoBuf.Reflect.Service.Method\r
+ * @expose\r
+ */\r
+ Reflect.Service.Method = Method;\r
+\r
+ /**\r
+ * RPC service method.\r
+ * @exports ProtoBuf.Reflect.Service.RPCMethod\r
+ * @param {!ProtoBuf.Builder} builder Builder reference\r
+ * @param {!ProtoBuf.Reflect.Service} svc Service\r
+ * @param {string} name Method name\r
+ * @param {string} request Request message name\r
+ * @param {string} response Response message name\r
+ * @param {boolean} request_stream Whether requests are streamed\r
+ * @param {boolean} response_stream Whether responses are streamed\r
+ * @param {Object.<string,*>=} options Options\r
+ * @constructor\r
+ * @extends ProtoBuf.Reflect.Service.Method\r
+ */\r
+ var RPCMethod = function(builder, svc, name, request, response, request_stream, response_stream, options) {\r
+ Method.call(this, builder, svc, name, options);\r
+\r
+ /**\r
+ * @override\r
+ */\r
+ this.className = "Service.RPCMethod";\r
+\r
+ /**\r
+ * Request message name.\r
+ * @type {string}\r
+ * @expose\r
+ */\r
+ this.requestName = request;\r
+\r
+ /**\r
+ * Response message name.\r
+ * @type {string}\r
+ * @expose\r
+ */\r
+ this.responseName = response;\r
+\r
+ /**\r
+ * Whether requests are streamed\r
+ * @type {bool}\r
+ * @expose\r
+ */\r
+ this.requestStream = request_stream;\r
+\r
+ /**\r
+ * Whether responses are streamed\r
+ * @type {bool}\r
+ * @expose\r
+ */\r
+ this.responseStream = response_stream;\r
+\r
+ /**\r
+ * Resolved request message type.\r
+ * @type {ProtoBuf.Reflect.Message}\r
+ * @expose\r
+ */\r
+ this.resolvedRequestType = null;\r
+\r
+ /**\r
+ * Resolved response message type.\r
+ * @type {ProtoBuf.Reflect.Message}\r
+ * @expose\r
+ */\r
+ this.resolvedResponseType = null;\r
+ };\r
+\r
+ // Extends Method\r
+ RPCMethod.prototype = Object.create(Method.prototype);\r
+\r
+ /**\r
+ * @alias ProtoBuf.Reflect.Service.RPCMethod\r
+ * @expose\r
+ */\r
+ Reflect.Service.RPCMethod = RPCMethod;\r
+\r
+ return Reflect;\r
+\r
+ })(ProtoBuf);\r
+\r
+ /**\r
+ * @alias ProtoBuf.Builder\r
+ * @expose\r
+ */\r
+ ProtoBuf.Builder = (function(ProtoBuf, Lang, Reflect) {\r
+ "use strict";\r
+\r
+ /**\r
+ * Constructs a new Builder.\r
+ * @exports ProtoBuf.Builder\r
+ * @class Provides the functionality to build protocol messages.\r
+ * @param {Object.<string,*>=} options Options\r
+ * @constructor\r
+ */\r
+ var Builder = function(options) {\r
+\r
+ /**\r
+ * Namespace.\r
+ * @type {ProtoBuf.Reflect.Namespace}\r
+ * @expose\r
+ */\r
+ this.ns = new Reflect.Namespace(this, null, ""); // Global namespace\r
+\r
+ /**\r
+ * Namespace pointer.\r
+ * @type {ProtoBuf.Reflect.T}\r
+ * @expose\r
+ */\r
+ this.ptr = this.ns;\r
+\r
+ /**\r
+ * Resolved flag.\r
+ * @type {boolean}\r
+ * @expose\r
+ */\r
+ this.resolved = false;\r
+\r
+ /**\r
+ * The current building result.\r
+ * @type {Object.<string,ProtoBuf.Builder.Message|Object>|null}\r
+ * @expose\r
+ */\r
+ this.result = null;\r
+\r
+ /**\r
+ * Imported files.\r
+ * @type {Array.<string>}\r
+ * @expose\r
+ */\r
+ this.files = {};\r
+\r
+ /**\r
+ * Import root override.\r
+ * @type {?string}\r
+ * @expose\r
+ */\r
+ this.importRoot = null;\r
+\r
+ /**\r
+ * Options.\r
+ * @type {!Object.<string, *>}\r
+ * @expose\r
+ */\r
+ this.options = options || {};\r
+ };\r
+\r
+ /**\r
+ * @alias ProtoBuf.Builder.prototype\r
+ * @inner\r
+ */\r
+ var BuilderPrototype = Builder.prototype;\r
+\r
+ // ----- Definition tests -----\r
+\r
+ /**\r
+ * Tests if a definition most likely describes a message.\r
+ * @param {!Object} def\r
+ * @returns {boolean}\r
+ * @expose\r
+ */\r
+ Builder.isMessage = function(def) {\r
+ // Messages require a string name\r
+ if (typeof def["name"] !== 'string')\r
+ return false;\r
+ // Messages do not contain values (enum) or rpc methods (service)\r
+ if (typeof def["values"] !== 'undefined' || typeof def["rpc"] !== 'undefined')\r
+ return false;\r
+ return true;\r
+ };\r
+\r
+ /**\r
+ * Tests if a definition most likely describes a message field.\r
+ * @param {!Object} def\r
+ * @returns {boolean}\r
+ * @expose\r
+ */\r
+ Builder.isMessageField = function(def) {\r
+ // Message fields require a string rule, name and type and an id\r
+ if (typeof def["rule"] !== 'string' || typeof def["name"] !== 'string' || typeof def["type"] !== 'string' || typeof def["id"] === 'undefined')\r
+ return false;\r
+ return true;\r
+ };\r
+\r
+ /**\r
+ * Tests if a definition most likely describes an enum.\r
+ * @param {!Object} def\r
+ * @returns {boolean}\r
+ * @expose\r
+ */\r
+ Builder.isEnum = function(def) {\r
+ // Enums require a string name\r
+ if (typeof def["name"] !== 'string')\r
+ return false;\r
+ // Enums require at least one value\r
+ if (typeof def["values"] === 'undefined' || !Array.isArray(def["values"]) || def["values"].length === 0)\r
+ return false;\r
+ return true;\r
+ };\r
+\r
+ /**\r
+ * Tests if a definition most likely describes a service.\r
+ * @param {!Object} def\r
+ * @returns {boolean}\r
+ * @expose\r
+ */\r
+ Builder.isService = function(def) {\r
+ // Services require a string name and an rpc object\r
+ if (typeof def["name"] !== 'string' || typeof def["rpc"] !== 'object' || !def["rpc"])\r
+ return false;\r
+ return true;\r
+ };\r
+\r
+ /**\r
+ * Tests if a definition most likely describes an extended message\r
+ * @param {!Object} def\r
+ * @returns {boolean}\r
+ * @expose\r
+ */\r
+ Builder.isExtend = function(def) {\r
+ // Extends rquire a string ref\r
+ if (typeof def["ref"] !== 'string')\r
+ return false;\r
+ return true;\r
+ };\r
+\r
+ // ----- Building -----\r
+\r
+ /**\r
+ * Resets the pointer to the root namespace.\r
+ * @returns {!ProtoBuf.Builder} this\r
+ * @expose\r
+ */\r
+ BuilderPrototype.reset = function() {\r
+ this.ptr = this.ns;\r
+ return this;\r
+ };\r
+\r
+ /**\r
+ * Defines a namespace on top of the current pointer position and places the pointer on it.\r
+ * @param {string} namespace\r
+ * @return {!ProtoBuf.Builder} this\r
+ * @expose\r
+ */\r
+ BuilderPrototype.define = function(namespace) {\r
+ if (typeof namespace !== 'string' || !Lang.TYPEREF.test(namespace))\r
+ throw Error("illegal namespace: "+namespace);\r
+ namespace.split(".").forEach(function(part) {\r
+ var ns = this.ptr.getChild(part);\r
+ if (ns === null) // Keep existing\r
+ this.ptr.addChild(ns = new Reflect.Namespace(this, this.ptr, part));\r
+ this.ptr = ns;\r
+ }, this);\r
+ return this;\r
+ };\r
+\r
+ /**\r
+ * Creates the specified definitions at the current pointer position.\r
+ * @param {!Array.<!Object>} defs Messages, enums or services to create\r
+ * @returns {!ProtoBuf.Builder} this\r
+ * @throws {Error} If a message definition is invalid\r
+ * @expose\r
+ */\r
+ BuilderPrototype.create = function(defs) {\r
+ if (!defs)\r
+ return this; // Nothing to create\r
+ if (!Array.isArray(defs))\r
+ defs = [defs];\r
+ else {\r
+ if (defs.length === 0)\r
+ return this;\r
+ defs = defs.slice();\r
+ }\r
+\r
+ // It's quite hard to keep track of scopes and memory here, so let's do this iteratively.\r
+ var stack = [defs];\r
+ while (stack.length > 0) {\r
+ defs = stack.pop();\r
+\r
+ if (!Array.isArray(defs)) // Stack always contains entire namespaces\r
+ throw Error("not a valid namespace: "+JSON.stringify(defs));\r
+\r
+ while (defs.length > 0) {\r
+ var def = defs.shift(); // Namespaces always contain an array of messages, enums and services\r
+\r
+ if (Builder.isMessage(def)) {\r
+ var obj = new Reflect.Message(this, this.ptr, def["name"], def["options"], def["isGroup"], def["syntax"]);\r
+\r
+ // Create OneOfs\r
+ var oneofs = {};\r
+ if (def["oneofs"])\r
+ Object.keys(def["oneofs"]).forEach(function(name) {\r
+ obj.addChild(oneofs[name] = new Reflect.Message.OneOf(this, obj, name));\r
+ }, this);\r
+\r
+ // Create fields\r
+ if (def["fields"])\r
+ def["fields"].forEach(function(fld) {\r
+ if (obj.getChild(fld["id"]|0) !== null)\r
+ throw Error("duplicate or invalid field id in "+obj.name+": "+fld['id']);\r
+ if (fld["options"] && typeof fld["options"] !== 'object')\r
+ throw Error("illegal field options in "+obj.name+"#"+fld["name"]);\r
+ var oneof = null;\r
+ if (typeof fld["oneof"] === 'string' && !(oneof = oneofs[fld["oneof"]]))\r
+ throw Error("illegal oneof in "+obj.name+"#"+fld["name"]+": "+fld["oneof"]);\r
+ fld = new Reflect.Message.Field(this, obj, fld["rule"], fld["keytype"], fld["type"], fld["name"], fld["id"], fld["options"], oneof, def["syntax"]);\r
+ if (oneof)\r
+ oneof.fields.push(fld);\r
+ obj.addChild(fld);\r
+ }, this);\r
+\r
+ // Push children to stack\r
+ var subObj = [];\r
+ if (def["enums"])\r
+ def["enums"].forEach(function(enm) {\r
+ subObj.push(enm);\r
+ });\r
+ if (def["messages"])\r
+ def["messages"].forEach(function(msg) {\r
+ subObj.push(msg);\r
+ });\r
+ if (def["services"])\r
+ def["services"].forEach(function(svc) {\r
+ subObj.push(svc);\r
+ });\r
+\r
+ // Set extension ranges\r
+ if (def["extensions"]) {\r
+ if (typeof def["extensions"][0] === 'number') // pre 5.0.1\r
+ obj.extensions = [ def["extensions"] ];\r
+ else\r
+ obj.extensions = def["extensions"];\r
+ }\r
+\r
+ // Create on top of current namespace\r
+ this.ptr.addChild(obj);\r
+ if (subObj.length > 0) {\r
+ stack.push(defs); // Push the current level back\r
+ defs = subObj; // Continue processing sub level\r
+ subObj = null;\r
+ this.ptr = obj; // And move the pointer to this namespace\r
+ obj = null;\r
+ continue;\r
+ }\r
+ subObj = null;\r
+\r
+ } else if (Builder.isEnum(def)) {\r
+\r
+ obj = new Reflect.Enum(this, this.ptr, def["name"], def["options"], def["syntax"]);\r
+ def["values"].forEach(function(val) {\r
+ obj.addChild(new Reflect.Enum.Value(this, obj, val["name"], val["id"]));\r
+ }, this);\r
+ this.ptr.addChild(obj);\r
+\r
+ } else if (Builder.isService(def)) {\r
+\r
+ obj = new Reflect.Service(this, this.ptr, def["name"], def["options"]);\r
+ Object.keys(def["rpc"]).forEach(function(name) {\r
+ var mtd = def["rpc"][name];\r
+ obj.addChild(new Reflect.Service.RPCMethod(this, obj, name, mtd["request"], mtd["response"], !!mtd["request_stream"], !!mtd["response_stream"], mtd["options"]));\r
+ }, this);\r
+ this.ptr.addChild(obj);\r
+\r
+ } else if (Builder.isExtend(def)) {\r
+\r
+ obj = this.ptr.resolve(def["ref"], true);\r
+ if (obj) {\r
+ def["fields"].forEach(function(fld) {\r
+ if (obj.getChild(fld['id']|0) !== null)\r
+ throw Error("duplicate extended field id in "+obj.name+": "+fld['id']);\r
+ // Check if field id is allowed to be extended\r
+ if (obj.extensions) {\r
+ var valid = false;\r
+ obj.extensions.forEach(function(range) {\r
+ if (fld["id"] >= range[0] && fld["id"] <= range[1])\r
+ valid = true;\r
+ });\r
+ if (!valid)\r
+ throw Error("illegal extended field id in "+obj.name+": "+fld['id']+" (not within valid ranges)");\r
+ }\r
+ // Convert extension field names to camel case notation if the override is set\r
+ var name = fld["name"];\r
+ if (this.options['convertFieldsToCamelCase'])\r
+ name = ProtoBuf.Util.toCamelCase(name);\r
+ // see #161: Extensions use their fully qualified name as their runtime key and...\r
+ var field = new Reflect.Message.ExtensionField(this, obj, fld["rule"], fld["type"], this.ptr.fqn()+'.'+name, fld["id"], fld["options"]);\r
+ // ...are added on top of the current namespace as an extension which is used for\r
+ // resolving their type later on (the extension always keeps the original name to\r
+ // prevent naming collisions)\r
+ var ext = new Reflect.Extension(this, this.ptr, fld["name"], field);\r
+ field.extension = ext;\r
+ this.ptr.addChild(ext);\r
+ obj.addChild(field);\r
+ }, this);\r
+\r
+ } else if (!/\.?google\.protobuf\./.test(def["ref"])) // Silently skip internal extensions\r
+ throw Error("extended message "+def["ref"]+" is not defined");\r
+\r
+ } else\r
+ throw Error("not a valid definition: "+JSON.stringify(def));\r
+\r
+ def = null;\r
+ obj = null;\r
+ }\r
+ // Break goes here\r
+ defs = null;\r
+ this.ptr = this.ptr.parent; // Namespace done, continue at parent\r
+ }\r
+ this.resolved = false; // Require re-resolve\r
+ this.result = null; // Require re-build\r
+ return this;\r
+ };\r
+\r
+ /**\r
+ * Propagates syntax to all children.\r
+ * @param {!Object} parent\r
+ * @inner\r
+ */\r
+ function propagateSyntax(parent) {\r
+ if (parent['messages']) {\r
+ parent['messages'].forEach(function(child) {\r
+ child["syntax"] = parent["syntax"];\r
+ propagateSyntax(child);\r
+ });\r
+ }\r
+ if (parent['enums']) {\r
+ parent['enums'].forEach(function(child) {\r
+ child["syntax"] = parent["syntax"];\r
+ });\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Imports another definition into this builder.\r
+ * @param {Object.<string,*>} json Parsed import\r
+ * @param {(string|{root: string, file: string})=} filename Imported file name\r
+ * @returns {!ProtoBuf.Builder} this\r
+ * @throws {Error} If the definition or file cannot be imported\r
+ * @expose\r
+ */\r
+ BuilderPrototype["import"] = function(json, filename) {\r
+ var delim = '/';\r
+\r
+ // Make sure to skip duplicate imports\r
+\r
+ if (typeof filename === 'string') {\r
+\r
+ if (ProtoBuf.Util.IS_NODE)\r
+ filename = require("path")['resolve'](filename);\r
+ if (this.files[filename] === true)\r
+ return this.reset();\r
+ this.files[filename] = true;\r
+\r
+ } else if (typeof filename === 'object') { // Object with root, file.\r
+\r
+ var root = filename.root;\r
+ if (ProtoBuf.Util.IS_NODE)\r
+ root = require("path")['resolve'](root);\r
+ if (root.indexOf("\\") >= 0 || filename.file.indexOf("\\") >= 0)\r
+ delim = '\\';\r
+ var fname;\r
+ if (ProtoBuf.Util.IS_NODE)\r
+ fname = require("path")['join'](root, filename.file);\r
+ else\r
+ fname = root + delim + filename.file;\r
+ if (this.files[fname] === true)\r
+ return this.reset();\r
+ this.files[fname] = true;\r
+ }\r
+\r
+ // Import imports\r
+\r
+ if (json['imports'] && json['imports'].length > 0) {\r
+ var importRoot,\r
+ resetRoot = false;\r
+\r
+ if (typeof filename === 'object') { // If an import root is specified, override\r
+\r
+ this.importRoot = filename["root"]; resetRoot = true; // ... and reset afterwards\r
+ importRoot = this.importRoot;\r
+ filename = filename["file"];\r
+ if (importRoot.indexOf("\\") >= 0 || filename.indexOf("\\") >= 0)\r
+ delim = '\\';\r
+\r
+ } else if (typeof filename === 'string') {\r
+\r
+ if (this.importRoot) // If import root is overridden, use it\r
+ importRoot = this.importRoot;\r
+ else { // Otherwise compute from filename\r
+ if (filename.indexOf("/") >= 0) { // Unix\r
+ importRoot = filename.replace(/\/[^\/]*$/, "");\r
+ if (/* /file.proto */ importRoot === "")\r
+ importRoot = "/";\r
+ } else if (filename.indexOf("\\") >= 0) { // Windows\r
+ importRoot = filename.replace(/\\[^\\]*$/, "");\r
+ delim = '\\';\r
+ } else\r
+ importRoot = ".";\r
+ }\r
+\r
+ } else\r
+ importRoot = null;\r
+\r
+ for (var i=0; i<json['imports'].length; i++) {\r
+ if (typeof json['imports'][i] === 'string') { // Import file\r
+ if (!importRoot)\r
+ throw Error("cannot determine import root");\r
+ var importFilename = json['imports'][i];\r
+ if (importFilename === "google/protobuf/descriptor.proto")\r
+ continue; // Not needed and therefore not used\r
+ if (ProtoBuf.Util.IS_NODE)\r
+ importFilename = require("path")['join'](importRoot, importFilename);\r
+ else\r
+ importFilename = importRoot + delim + importFilename;\r
+ if (this.files[importFilename] === true)\r
+ continue; // Already imported\r
+ if (/\.proto$/i.test(importFilename) && !ProtoBuf.DotProto) // If this is a light build\r
+ importFilename = importFilename.replace(/\.proto$/, ".json"); // always load the JSON file\r
+ var contents = ProtoBuf.Util.fetch(importFilename);\r
+ if (contents === null)\r
+ throw Error("failed to import '"+importFilename+"' in '"+filename+"': file not found");\r
+ if (/\.json$/i.test(importFilename)) // Always possible\r
+ this["import"](JSON.parse(contents+""), importFilename); // May throw\r
+ else\r
+ this["import"](ProtoBuf.DotProto.Parser.parse(contents), importFilename); // May throw\r
+ } else // Import structure\r
+ if (!filename)\r
+ this["import"](json['imports'][i]);\r
+ else if (/\.(\w+)$/.test(filename)) // With extension: Append _importN to the name portion to make it unique\r
+ this["import"](json['imports'][i], filename.replace(/^(.+)\.(\w+)$/, function($0, $1, $2) { return $1+"_import"+i+"."+$2; }));\r
+ else // Without extension: Append _importN to make it unique\r
+ this["import"](json['imports'][i], filename+"_import"+i);\r
+ }\r
+ if (resetRoot) // Reset import root override when all imports are done\r
+ this.importRoot = null;\r
+ }\r
+\r
+ // Import structures\r
+\r
+ if (json['package'])\r
+ this.define(json['package']);\r
+ if (json['syntax'])\r
+ propagateSyntax(json);\r
+ var base = this.ptr;\r
+ if (json['options'])\r
+ Object.keys(json['options']).forEach(function(key) {\r
+ base.options[key] = json['options'][key];\r
+ });\r
+ if (json['messages'])\r
+ this.create(json['messages']),\r
+ this.ptr = base;\r
+ if (json['enums'])\r
+ this.create(json['enums']),\r
+ this.ptr = base;\r
+ if (json['services'])\r
+ this.create(json['services']),\r
+ this.ptr = base;\r
+ if (json['extends'])\r
+ this.create(json['extends']);\r
+\r
+ return this.reset();\r
+ };\r
+\r
+ /**\r
+ * Resolves all namespace objects.\r
+ * @throws {Error} If a type cannot be resolved\r
+ * @returns {!ProtoBuf.Builder} this\r
+ * @expose\r
+ */\r
+ BuilderPrototype.resolveAll = function() {\r
+ // Resolve all reflected objects\r
+ var res;\r
+ if (this.ptr == null || typeof this.ptr.type === 'object')\r
+ return this; // Done (already resolved)\r
+\r
+ if (this.ptr instanceof Reflect.Namespace) { // Resolve children\r
+\r
+ this.ptr.children.forEach(function(child) {\r
+ this.ptr = child;\r
+ this.resolveAll();\r
+ }, this);\r
+\r
+ } else if (this.ptr instanceof Reflect.Message.Field) { // Resolve type\r
+\r
+ if (!Lang.TYPE.test(this.ptr.type)) {\r
+ if (!Lang.TYPEREF.test(this.ptr.type))\r
+ throw Error("illegal type reference in "+this.ptr.toString(true)+": "+this.ptr.type);\r
+ res = (this.ptr instanceof Reflect.Message.ExtensionField ? this.ptr.extension.parent : this.ptr.parent).resolve(this.ptr.type, true);\r
+ if (!res)\r
+ throw Error("unresolvable type reference in "+this.ptr.toString(true)+": "+this.ptr.type);\r
+ this.ptr.resolvedType = res;\r
+ if (res instanceof Reflect.Enum) {\r
+ this.ptr.type = ProtoBuf.TYPES["enum"];\r
+ if (this.ptr.syntax === 'proto3' && res.syntax !== 'proto3')\r
+ throw Error("proto3 message cannot reference proto2 enum");\r
+ }\r
+ else if (res instanceof Reflect.Message)\r
+ this.ptr.type = res.isGroup ? ProtoBuf.TYPES["group"] : ProtoBuf.TYPES["message"];\r
+ else\r
+ throw Error("illegal type reference in "+this.ptr.toString(true)+": "+this.ptr.type);\r
+ } else\r
+ this.ptr.type = ProtoBuf.TYPES[this.ptr.type];\r
+\r
+ // If it's a map field, also resolve the key type. The key type can be only a numeric, string, or bool type\r
+ // (i.e., no enums or messages), so we don't need to resolve against the current namespace.\r
+ if (this.ptr.map) {\r
+ if (!Lang.TYPE.test(this.ptr.keyType))\r
+ throw Error("illegal key type for map field in "+this.ptr.toString(true)+": "+this.ptr.keyType);\r
+ this.ptr.keyType = ProtoBuf.TYPES[this.ptr.keyType];\r
+ }\r
+\r
+ // If it's a repeated and packable field then proto3 mandates it should be packed by\r
+ // default\r
+ if (\r
+ this.ptr.syntax === 'proto3' &&\r
+ this.ptr.repeated && this.ptr.options.packed === undefined &&\r
+ ProtoBuf.PACKABLE_WIRE_TYPES.indexOf(this.ptr.type.wireType) !== -1\r
+ ) {\r
+ this.ptr.options.packed = true;\r
+ }\r
+\r
+ } else if (this.ptr instanceof ProtoBuf.Reflect.Service.Method) {\r
+\r
+ if (this.ptr instanceof ProtoBuf.Reflect.Service.RPCMethod) {\r
+ res = this.ptr.parent.resolve(this.ptr.requestName, true);\r
+ if (!res || !(res instanceof ProtoBuf.Reflect.Message))\r
+ throw Error("Illegal type reference in "+this.ptr.toString(true)+": "+this.ptr.requestName);\r
+ this.ptr.resolvedRequestType = res;\r
+ res = this.ptr.parent.resolve(this.ptr.responseName, true);\r
+ if (!res || !(res instanceof ProtoBuf.Reflect.Message))\r
+ throw Error("Illegal type reference in "+this.ptr.toString(true)+": "+this.ptr.responseName);\r
+ this.ptr.resolvedResponseType = res;\r
+ } else // Should not happen as nothing else is implemented\r
+ throw Error("illegal service type in "+this.ptr.toString(true));\r
+\r
+ } else if (\r
+ !(this.ptr instanceof ProtoBuf.Reflect.Message.OneOf) && // Not built\r
+ !(this.ptr instanceof ProtoBuf.Reflect.Extension) && // Not built\r
+ !(this.ptr instanceof ProtoBuf.Reflect.Enum.Value) // Built in enum\r
+ )\r
+ throw Error("illegal object in namespace: "+typeof(this.ptr)+": "+this.ptr);\r
+\r
+ return this.reset();\r
+ };\r
+\r
+ /**\r
+ * Builds the protocol. This will first try to resolve all definitions and, if this has been successful,\r
+ * return the built package.\r
+ * @param {(string|Array.<string>)=} path Specifies what to return. If omitted, the entire namespace will be returned.\r
+ * @returns {!ProtoBuf.Builder.Message|!Object.<string,*>}\r
+ * @throws {Error} If a type could not be resolved\r
+ * @expose\r
+ */\r
+ BuilderPrototype.build = function(path) {\r
+ this.reset();\r
+ if (!this.resolved)\r
+ this.resolveAll(),\r
+ this.resolved = true,\r
+ this.result = null; // Require re-build\r
+ if (this.result === null) // (Re-)Build\r
+ this.result = this.ns.build();\r
+ if (!path)\r
+ return this.result;\r
+ var part = typeof path === 'string' ? path.split(".") : path,\r
+ ptr = this.result; // Build namespace pointer (no hasChild etc.)\r
+ for (var i=0; i<part.length; i++)\r
+ if (ptr[part[i]])\r
+ ptr = ptr[part[i]];\r
+ else {\r
+ ptr = null;\r
+ break;\r
+ }\r
+ return ptr;\r
+ };\r
+\r
+ /**\r
+ * Similar to {@link ProtoBuf.Builder#build}, but looks up the internal reflection descriptor.\r
+ * @param {string=} path Specifies what to return. If omitted, the entire namespace wiil be returned.\r
+ * @param {boolean=} excludeNonNamespace Excludes non-namespace types like fields, defaults to `false`\r
+ * @returns {?ProtoBuf.Reflect.T} Reflection descriptor or `null` if not found\r
+ */\r
+ BuilderPrototype.lookup = function(path, excludeNonNamespace) {\r
+ return path ? this.ns.resolve(path, excludeNonNamespace) : this.ns;\r
+ };\r
+\r
+ /**\r
+ * Returns a string representation of this object.\r
+ * @return {string} String representation as of "Builder"\r
+ * @expose\r
+ */\r
+ BuilderPrototype.toString = function() {\r
+ return "Builder";\r
+ };\r
+\r
+ // ----- Base classes -----\r
+ // Exist for the sole purpose of being able to "... instanceof ProtoBuf.Builder.Message" etc.\r
+\r
+ /**\r
+ * @alias ProtoBuf.Builder.Message\r
+ */\r
+ Builder.Message = function() {};\r
+\r
+ /**\r
+ * @alias ProtoBuf.Builder.Enum\r
+ */\r
+ Builder.Enum = function() {};\r
+\r
+ /**\r
+ * @alias ProtoBuf.Builder.Message\r
+ */\r
+ Builder.Service = function() {};\r
+\r
+ return Builder;\r
+\r
+ })(ProtoBuf, ProtoBuf.Lang, ProtoBuf.Reflect);\r
+\r
+ /**\r
+ * @alias ProtoBuf.Map\r
+ * @expose\r
+ */\r
+ ProtoBuf.Map = (function(ProtoBuf, Reflect) {\r
+ "use strict";\r
+\r
+ /**\r
+ * Constructs a new Map. A Map is a container that is used to implement map\r
+ * fields on message objects. It closely follows the ES6 Map API; however,\r
+ * it is distinct because we do not want to depend on external polyfills or\r
+ * on ES6 itself.\r
+ *\r
+ * @exports ProtoBuf.Map\r
+ * @param {!ProtoBuf.Reflect.Field} field Map field\r
+ * @param {Object.<string,*>=} contents Initial contents\r
+ * @constructor\r
+ */\r
+ var Map = function(field, contents) {\r
+ if (!field.map)\r
+ throw Error("field is not a map");\r
+\r
+ /**\r
+ * The field corresponding to this map.\r
+ * @type {!ProtoBuf.Reflect.Field}\r
+ */\r
+ this.field = field;\r
+\r
+ /**\r
+ * Element instance corresponding to key type.\r
+ * @type {!ProtoBuf.Reflect.Element}\r
+ */\r
+ this.keyElem = new Reflect.Element(field.keyType, null, true, field.syntax);\r
+\r
+ /**\r
+ * Element instance corresponding to value type.\r
+ * @type {!ProtoBuf.Reflect.Element}\r
+ */\r
+ this.valueElem = new Reflect.Element(field.type, field.resolvedType, false, field.syntax);\r
+\r
+ /**\r
+ * Internal map: stores mapping of (string form of key) -> (key, value)\r
+ * pair.\r
+ *\r
+ * We provide map semantics for arbitrary key types, but we build on top\r
+ * of an Object, which has only string keys. In order to avoid the need\r
+ * to convert a string key back to its native type in many situations,\r
+ * we store the native key value alongside the value. Thus, we only need\r
+ * a one-way mapping from a key type to its string form that guarantees\r
+ * uniqueness and equality (i.e., str(K1) === str(K2) if and only if K1\r
+ * === K2).\r
+ *\r
+ * @type {!Object<string, {key: *, value: *}>}\r
+ */\r
+ this.map = {};\r
+\r
+ /**\r
+ * Returns the number of elements in the map.\r
+ */\r
+ Object.defineProperty(this, "size", {\r
+ get: function() { return Object.keys(this.map).length; }\r
+ });\r
+\r
+ // Fill initial contents from a raw object.\r
+ if (contents) {\r
+ var keys = Object.keys(contents);\r
+ for (var i = 0; i < keys.length; i++) {\r
+ var key = this.keyElem.valueFromString(keys[i]);\r
+ var val = this.valueElem.verifyValue(contents[keys[i]]);\r
+ this.map[this.keyElem.valueToString(key)] =\r
+ { key: key, value: val };\r
+ }\r
+ }\r
+ };\r
+\r
+ var MapPrototype = Map.prototype;\r
+\r
+ /**\r
+ * Helper: return an iterator over an array.\r
+ * @param {!Array<*>} arr the array\r
+ * @returns {!Object} an iterator\r
+ * @inner\r
+ */\r
+ function arrayIterator(arr) {\r
+ var idx = 0;\r
+ return {\r
+ next: function() {\r
+ if (idx < arr.length)\r
+ return { done: false, value: arr[idx++] };\r
+ return { done: true };\r
+ }\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Clears the map.\r
+ */\r
+ MapPrototype.clear = function() {\r
+ this.map = {};\r
+ };\r
+\r
+ /**\r
+ * Deletes a particular key from the map.\r
+ * @returns {boolean} Whether any entry with this key was deleted.\r
+ */\r
+ MapPrototype["delete"] = function(key) {\r
+ var keyValue = this.keyElem.valueToString(this.keyElem.verifyValue(key));\r
+ var hadKey = keyValue in this.map;\r
+ delete this.map[keyValue];\r
+ return hadKey;\r
+ };\r
+\r
+ /**\r
+ * Returns an iterator over [key, value] pairs in the map.\r
+ * @returns {Object} The iterator\r
+ */\r
+ MapPrototype.entries = function() {\r
+ var entries = [];\r
+ var strKeys = Object.keys(this.map);\r
+ for (var i = 0, entry; i < strKeys.length; i++)\r
+ entries.push([(entry=this.map[strKeys[i]]).key, entry.value]);\r
+ return arrayIterator(entries);\r
+ };\r
+\r
+ /**\r
+ * Returns an iterator over keys in the map.\r
+ * @returns {Object} The iterator\r
+ */\r
+ MapPrototype.keys = function() {\r
+ var keys = [];\r
+ var strKeys = Object.keys(this.map);\r
+ for (var i = 0; i < strKeys.length; i++)\r
+ keys.push(this.map[strKeys[i]].key);\r
+ return arrayIterator(keys);\r
+ };\r
+\r
+ /**\r
+ * Returns an iterator over values in the map.\r
+ * @returns {!Object} The iterator\r
+ */\r
+ MapPrototype.values = function() {\r
+ var values = [];\r
+ var strKeys = Object.keys(this.map);\r
+ for (var i = 0; i < strKeys.length; i++)\r
+ values.push(this.map[strKeys[i]].value);\r
+ return arrayIterator(values);\r
+ };\r
+\r
+ /**\r
+ * Iterates over entries in the map, calling a function on each.\r
+ * @param {function(this:*, *, *, *)} cb The callback to invoke with value, key, and map arguments.\r
+ * @param {Object=} thisArg The `this` value for the callback\r
+ */\r
+ MapPrototype.forEach = function(cb, thisArg) {\r
+ var strKeys = Object.keys(this.map);\r
+ for (var i = 0, entry; i < strKeys.length; i++)\r
+ cb.call(thisArg, (entry=this.map[strKeys[i]]).value, entry.key, this);\r
+ };\r
+\r
+ /**\r
+ * Sets a key in the map to the given value.\r
+ * @param {*} key The key\r
+ * @param {*} value The value\r
+ * @returns {!ProtoBuf.Map} The map instance\r
+ */\r
+ MapPrototype.set = function(key, value) {\r
+ var keyValue = this.keyElem.verifyValue(key);\r
+ var valValue = this.valueElem.verifyValue(value);\r
+ this.map[this.keyElem.valueToString(keyValue)] =\r
+ { key: keyValue, value: valValue };\r
+ return this;\r
+ };\r
+\r
+ /**\r
+ * Gets the value corresponding to a key in the map.\r
+ * @param {*} key The key\r
+ * @returns {*|undefined} The value, or `undefined` if key not present\r
+ */\r
+ MapPrototype.get = function(key) {\r
+ var keyValue = this.keyElem.valueToString(this.keyElem.verifyValue(key));\r
+ if (!(keyValue in this.map))\r
+ return undefined;\r
+ return this.map[keyValue].value;\r
+ };\r
+\r
+ /**\r
+ * Determines whether the given key is present in the map.\r
+ * @param {*} key The key\r
+ * @returns {boolean} `true` if the key is present\r
+ */\r
+ MapPrototype.has = function(key) {\r
+ var keyValue = this.keyElem.valueToString(this.keyElem.verifyValue(key));\r
+ return (keyValue in this.map);\r
+ };\r
+\r
+ return Map;\r
+ })(ProtoBuf, ProtoBuf.Reflect);\r
+\r
+\r
+ /**\r
+ * Loads a .proto string and returns the Builder.\r
+ * @param {string} proto .proto file contents\r
+ * @param {(ProtoBuf.Builder|string|{root: string, file: string})=} builder Builder to append to. Will create a new one if omitted.\r
+ * @param {(string|{root: string, file: string})=} filename The corresponding file name if known. Must be specified for imports.\r
+ * @return {ProtoBuf.Builder} Builder to create new messages\r
+ * @throws {Error} If the definition cannot be parsed or built\r
+ * @expose\r
+ */\r
+ ProtoBuf.loadProto = function(proto, builder, filename) {\r
+ if (typeof builder === 'string' || (builder && typeof builder["file"] === 'string' && typeof builder["root"] === 'string'))\r
+ filename = builder,\r
+ builder = undefined;\r
+ return ProtoBuf.loadJson(ProtoBuf.DotProto.Parser.parse(proto), builder, filename);\r
+ };\r
+\r
+ /**\r
+ * Loads a .proto string and returns the Builder. This is an alias of {@link ProtoBuf.loadProto}.\r
+ * @function\r
+ * @param {string} proto .proto file contents\r
+ * @param {(ProtoBuf.Builder|string)=} builder Builder to append to. Will create a new one if omitted.\r
+ * @param {(string|{root: string, file: string})=} filename The corresponding file name if known. Must be specified for imports.\r
+ * @return {ProtoBuf.Builder} Builder to create new messages\r
+ * @throws {Error} If the definition cannot be parsed or built\r
+ * @expose\r
+ */\r
+ ProtoBuf.protoFromString = ProtoBuf.loadProto; // Legacy\r
+\r
+ /**\r
+ * Loads a .proto file and returns the Builder.\r
+ * @param {string|{root: string, file: string}} filename Path to proto file or an object specifying 'file' with\r
+ * an overridden 'root' path for all imported files.\r
+ * @param {function(?Error, !ProtoBuf.Builder=)=} callback Callback that will receive `null` as the first and\r
+ * the Builder as its second argument on success, otherwise the error as its first argument. If omitted, the\r
+ * file will be read synchronously and this function will return the Builder.\r
+ * @param {ProtoBuf.Builder=} builder Builder to append to. Will create a new one if omitted.\r
+ * @return {?ProtoBuf.Builder|undefined} The Builder if synchronous (no callback specified, will be NULL if the\r
+ * request has failed), else undefined\r
+ * @expose\r
+ */\r
+ ProtoBuf.loadProtoFile = function(filename, callback, builder) {\r
+ if (callback && typeof callback === 'object')\r
+ builder = callback,\r
+ callback = null;\r
+ else if (!callback || typeof callback !== 'function')\r
+ callback = null;\r
+ if (callback)\r
+ return ProtoBuf.Util.fetch(typeof filename === 'string' ? filename : filename["root"]+"/"+filename["file"], function(contents) {\r
+ if (contents === null) {\r
+ callback(Error("Failed to fetch file"));\r
+ return;\r
+ }\r
+ try {\r
+ callback(null, ProtoBuf.loadProto(contents, builder, filename));\r
+ } catch (e) {\r
+ callback(e);\r
+ }\r
+ });\r
+ var contents = ProtoBuf.Util.fetch(typeof filename === 'object' ? filename["root"]+"/"+filename["file"] : filename);\r
+ return contents === null ? null : ProtoBuf.loadProto(contents, builder, filename);\r
+ };\r
+\r
+ /**\r
+ * Loads a .proto file and returns the Builder. This is an alias of {@link ProtoBuf.loadProtoFile}.\r
+ * @function\r
+ * @param {string|{root: string, file: string}} filename Path to proto file or an object specifying 'file' with\r
+ * an overridden 'root' path for all imported files.\r
+ * @param {function(?Error, !ProtoBuf.Builder=)=} callback Callback that will receive `null` as the first and\r
+ * the Builder as its second argument on success, otherwise the error as its first argument. If omitted, the\r
+ * file will be read synchronously and this function will return the Builder.\r
+ * @param {ProtoBuf.Builder=} builder Builder to append to. Will create a new one if omitted.\r
+ * @return {!ProtoBuf.Builder|undefined} The Builder if synchronous (no callback specified, will be NULL if the\r
+ * request has failed), else undefined\r
+ * @expose\r
+ */\r
+ ProtoBuf.protoFromFile = ProtoBuf.loadProtoFile; // Legacy\r
+\r
+\r
+ /**\r
+ * Constructs a new empty Builder.\r
+ * @param {Object.<string,*>=} options Builder options, defaults to global options set on ProtoBuf\r
+ * @return {!ProtoBuf.Builder} Builder\r
+ * @expose\r
+ */\r
+ ProtoBuf.newBuilder = function(options) {\r
+ options = options || {};\r
+ if (typeof options['convertFieldsToCamelCase'] === 'undefined')\r
+ options['convertFieldsToCamelCase'] = ProtoBuf.convertFieldsToCamelCase;\r
+ if (typeof options['populateAccessors'] === 'undefined')\r
+ options['populateAccessors'] = ProtoBuf.populateAccessors;\r
+ return new ProtoBuf.Builder(options);\r
+ };\r
+\r
+ /**\r
+ * Loads a .json definition and returns the Builder.\r
+ * @param {!*|string} json JSON definition\r
+ * @param {(ProtoBuf.Builder|string|{root: string, file: string})=} builder Builder to append to. Will create a new one if omitted.\r
+ * @param {(string|{root: string, file: string})=} filename The corresponding file name if known. Must be specified for imports.\r
+ * @return {ProtoBuf.Builder} Builder to create new messages\r
+ * @throws {Error} If the definition cannot be parsed or built\r
+ * @expose\r
+ */\r
+ ProtoBuf.loadJson = function(json, builder, filename) {\r
+ if (typeof builder === 'string' || (builder && typeof builder["file"] === 'string' && typeof builder["root"] === 'string'))\r
+ filename = builder,\r
+ builder = null;\r
+ if (!builder || typeof builder !== 'object')\r
+ builder = ProtoBuf.newBuilder();\r
+ if (typeof json === 'string')\r
+ json = JSON.parse(json);\r
+ builder["import"](json, filename);\r
+ builder.resolveAll();\r
+ return builder;\r
+ };\r
+\r
+ /**\r
+ * Loads a .json file and returns the Builder.\r
+ * @param {string|!{root: string, file: string}} filename Path to json file or an object specifying 'file' with\r
+ * an overridden 'root' path for all imported files.\r
+ * @param {function(?Error, !ProtoBuf.Builder=)=} callback Callback that will receive `null` as the first and\r
+ * the Builder as its second argument on success, otherwise the error as its first argument. If omitted, the\r
+ * file will be read synchronously and this function will return the Builder.\r
+ * @param {ProtoBuf.Builder=} builder Builder to append to. Will create a new one if omitted.\r
+ * @return {?ProtoBuf.Builder|undefined} The Builder if synchronous (no callback specified, will be NULL if the\r
+ * request has failed), else undefined\r
+ * @expose\r
+ */\r
+ ProtoBuf.loadJsonFile = function(filename, callback, builder) {\r
+ if (callback && typeof callback === 'object')\r
+ builder = callback,\r
+ callback = null;\r
+ else if (!callback || typeof callback !== 'function')\r
+ callback = null;\r
+ if (callback)\r
+ return ProtoBuf.Util.fetch(typeof filename === 'string' ? filename : filename["root"]+"/"+filename["file"], function(contents) {\r
+ if (contents === null) {\r
+ callback(Error("Failed to fetch file"));\r
+ return;\r
+ }\r
+ try {\r
+ callback(null, ProtoBuf.loadJson(JSON.parse(contents), builder, filename));\r
+ } catch (e) {\r
+ callback(e);\r
+ }\r
+ });\r
+ var contents = ProtoBuf.Util.fetch(typeof filename === 'object' ? filename["root"]+"/"+filename["file"] : filename);\r
+ return contents === null ? null : ProtoBuf.loadJson(JSON.parse(contents), builder, filename);\r
+ };\r
+\r
+ return ProtoBuf;\r
+});\r