--- /dev/null
+/**\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
+ //? include("../Builder/Message.js");\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