Built motion from commit 6a09e18b.|2.6.11
[motion2.git] / legacy-libs / grpc-cloned / node_modules / protobufjs / src / ProtoBuf / Reflect / Message.js
1 /**\r
2  * Constructs a new Message.\r
3  * @exports ProtoBuf.Reflect.Message\r
4  * @param {!ProtoBuf.Builder} builder Builder reference\r
5  * @param {!ProtoBuf.Reflect.Namespace} parent Parent message or namespace\r
6  * @param {string} name Message name\r
7  * @param {Object.<string,*>=} options Message options\r
8  * @param {boolean=} isGroup `true` if this is a legacy group\r
9  * @param {string?} syntax The syntax level of this definition (e.g., proto3)\r
10  * @constructor\r
11  * @extends ProtoBuf.Reflect.Namespace\r
12  */\r
13 var Message = function(builder, parent, name, options, isGroup, syntax) {\r
14     Namespace.call(this, builder, parent, name, options, syntax);\r
15 \r
16     /**\r
17      * @override\r
18      */\r
19     this.className = "Message";\r
20 \r
21     /**\r
22      * Extensions range.\r
23      * @type {!Array.<number>|undefined}\r
24      * @expose\r
25      */\r
26     this.extensions = undefined;\r
27 \r
28     /**\r
29      * Runtime message class.\r
30      * @type {?function(new:ProtoBuf.Builder.Message)}\r
31      * @expose\r
32      */\r
33     this.clazz = null;\r
34 \r
35     /**\r
36      * Whether this is a legacy group or not.\r
37      * @type {boolean}\r
38      * @expose\r
39      */\r
40     this.isGroup = !!isGroup;\r
41 \r
42     // The following cached collections are used to efficiently iterate over or look up fields when decoding.\r
43 \r
44     /**\r
45      * Cached fields.\r
46      * @type {?Array.<!ProtoBuf.Reflect.Message.Field>}\r
47      * @private\r
48      */\r
49     this._fields = null;\r
50 \r
51     /**\r
52      * Cached fields by id.\r
53      * @type {?Object.<number,!ProtoBuf.Reflect.Message.Field>}\r
54      * @private\r
55      */\r
56     this._fieldsById = null;\r
57 \r
58     /**\r
59      * Cached fields by name.\r
60      * @type {?Object.<string,!ProtoBuf.Reflect.Message.Field>}\r
61      * @private\r
62      */\r
63     this._fieldsByName = null;\r
64 };\r
65 \r
66 /**\r
67  * @alias ProtoBuf.Reflect.Message.prototype\r
68  * @inner\r
69  */\r
70 var MessagePrototype = Message.prototype = Object.create(Namespace.prototype);\r
71 \r
72 /**\r
73  * Builds the message and returns the runtime counterpart, which is a fully functional class.\r
74  * @see ProtoBuf.Builder.Message\r
75  * @param {boolean=} rebuild Whether to rebuild or not, defaults to false\r
76  * @return {ProtoBuf.Reflect.Message} Message class\r
77  * @throws {Error} If the message cannot be built\r
78  * @expose\r
79  */\r
80 MessagePrototype.build = function(rebuild) {\r
81     if (this.clazz && !rebuild)\r
82         return this.clazz;\r
83 \r
84     // Create the runtime Message class in its own scope\r
85     var clazz = (function(ProtoBuf, T) {\r
86 \r
87         //? include("../Builder/Message.js");\r
88 \r
89         return Message;\r
90 \r
91     })(ProtoBuf, this);\r
92 \r
93     // Static enums and prototyped sub-messages / cached collections\r
94     this._fields = [];\r
95     this._fieldsById = {};\r
96     this._fieldsByName = {};\r
97     this._oneofsByName = {};\r
98     for (var i=0, k=this.children.length, child; i<k; i++) {\r
99         child = this.children[i];\r
100         if (child instanceof Enum || child instanceof Message || child instanceof Service) {\r
101             if (clazz.hasOwnProperty(child.name))\r
102                 throw Error("Illegal reflect child of "+this.toString(true)+": "+child.toString(true)+" cannot override static property '"+child.name+"'");\r
103             clazz[child.name] = child.build();\r
104         } else if (child instanceof Message.Field)\r
105             child.build(),\r
106             this._fields.push(child),\r
107             this._fieldsById[child.id] = child,\r
108             this._fieldsByName[child.name] = child;\r
109         else if (child instanceof Message.OneOf) {\r
110             this._oneofsByName[child.name] = child;\r
111         }\r
112         else if (!(child instanceof Message.OneOf) && !(child instanceof Extension)) // Not built\r
113             throw Error("Illegal reflect child of "+this.toString(true)+": "+this.children[i].toString(true));\r
114     }\r
115 \r
116     return this.clazz = clazz;\r
117 };\r
118 \r
119 /**\r
120  * Encodes a runtime message's contents to the specified buffer.\r
121  * @param {!ProtoBuf.Builder.Message} message Runtime message to encode\r
122  * @param {ByteBuffer} buffer ByteBuffer to write to\r
123  * @param {boolean=} noVerify Whether to not verify field values, defaults to `false`\r
124  * @return {ByteBuffer} The ByteBuffer for chaining\r
125  * @throws {Error} If required fields are missing or the message cannot be encoded for another reason\r
126  * @expose\r
127  */\r
128 MessagePrototype.encode = function(message, buffer, noVerify) {\r
129     var fieldMissing = null,\r
130         field;\r
131     for (var i=0, k=this._fields.length, val; i<k; ++i) {\r
132         field = this._fields[i];\r
133         val = message[field.name];\r
134         if (field.required && val === null) {\r
135             if (fieldMissing === null)\r
136                 fieldMissing = field;\r
137         } else\r
138             field.encode(noVerify ? val : field.verifyValue(val), buffer, message);\r
139     }\r
140     if (fieldMissing !== null) {\r
141         var err = Error("Missing at least one required field for "+this.toString(true)+": "+fieldMissing);\r
142         err["encoded"] = buffer; // Still expose what we got\r
143         throw(err);\r
144     }\r
145     return buffer;\r
146 };\r
147 \r
148 /**\r
149  * Calculates a runtime message's byte length.\r
150  * @param {!ProtoBuf.Builder.Message} message Runtime message to encode\r
151  * @returns {number} Byte length\r
152  * @throws {Error} If required fields are missing or the message cannot be calculated for another reason\r
153  * @expose\r
154  */\r
155 MessagePrototype.calculate = function(message) {\r
156     for (var n=0, i=0, k=this._fields.length, field, val; i<k; ++i) {\r
157         field = this._fields[i];\r
158         val = message[field.name];\r
159         if (field.required && val === null)\r
160            throw Error("Missing at least one required field for "+this.toString(true)+": "+field);\r
161         else\r
162             n += field.calculate(val, message);\r
163     }\r
164     return n;\r
165 };\r
166 \r
167 /**\r
168  * Skips all data until the end of the specified group has been reached.\r
169  * @param {number} expectedId Expected GROUPEND id\r
170  * @param {!ByteBuffer} buf ByteBuffer\r
171  * @returns {boolean} `true` if a value as been skipped, `false` if the end has been reached\r
172  * @throws {Error} If it wasn't possible to find the end of the group (buffer overrun or end tag mismatch)\r
173  * @inner\r
174  */\r
175 function skipTillGroupEnd(expectedId, buf) {\r
176     var tag = buf.readVarint32(), // Throws on OOB\r
177         wireType = tag & 0x07,\r
178         id = tag >>> 3;\r
179     switch (wireType) {\r
180         case ProtoBuf.WIRE_TYPES.VARINT:\r
181             do tag = buf.readUint8();\r
182             while ((tag & 0x80) === 0x80);\r
183             break;\r
184         case ProtoBuf.WIRE_TYPES.BITS64:\r
185             buf.offset += 8;\r
186             break;\r
187         case ProtoBuf.WIRE_TYPES.LDELIM:\r
188             tag = buf.readVarint32(); // reads the varint\r
189             buf.offset += tag;        // skips n bytes\r
190             break;\r
191         case ProtoBuf.WIRE_TYPES.STARTGROUP:\r
192             skipTillGroupEnd(id, buf);\r
193             break;\r
194         case ProtoBuf.WIRE_TYPES.ENDGROUP:\r
195             if (id === expectedId)\r
196                 return false;\r
197             else\r
198                 throw Error("Illegal GROUPEND after unknown group: "+id+" ("+expectedId+" expected)");\r
199         case ProtoBuf.WIRE_TYPES.BITS32:\r
200             buf.offset += 4;\r
201             break;\r
202         default:\r
203             throw Error("Illegal wire type in unknown group "+expectedId+": "+wireType);\r
204     }\r
205     return true;\r
206 }\r
207 \r
208 /**\r
209  * Decodes an encoded message and returns the decoded message.\r
210  * @param {ByteBuffer} buffer ByteBuffer to decode from\r
211  * @param {number=} length Message length. Defaults to decode all remaining data.\r
212  * @param {number=} expectedGroupEndId Expected GROUPEND id if this is a legacy group\r
213  * @return {ProtoBuf.Builder.Message} Decoded message\r
214  * @throws {Error} If the message cannot be decoded\r
215  * @expose\r
216  */\r
217 MessagePrototype.decode = function(buffer, length, expectedGroupEndId) {\r
218     if (typeof length !== 'number')\r
219         length = -1;\r
220     var start = buffer.offset,\r
221         msg = new (this.clazz)(),\r
222         tag, wireType, id, field;\r
223     while (buffer.offset < start+length || (length === -1 && buffer.remaining() > 0)) {\r
224         tag = buffer.readVarint32();\r
225         wireType = tag & 0x07;\r
226         id = tag >>> 3;\r
227         if (wireType === ProtoBuf.WIRE_TYPES.ENDGROUP) {\r
228             if (id !== expectedGroupEndId)\r
229                 throw Error("Illegal group end indicator for "+this.toString(true)+": "+id+" ("+(expectedGroupEndId ? expectedGroupEndId+" expected" : "not a group")+")");\r
230             break;\r
231         }\r
232         if (!(field = this._fieldsById[id])) {\r
233             // "messages created by your new code can be parsed by your old code: old binaries simply ignore the new field when parsing."\r
234             switch (wireType) {\r
235                 case ProtoBuf.WIRE_TYPES.VARINT:\r
236                     buffer.readVarint32();\r
237                     break;\r
238                 case ProtoBuf.WIRE_TYPES.BITS32:\r
239                     buffer.offset += 4;\r
240                     break;\r
241                 case ProtoBuf.WIRE_TYPES.BITS64:\r
242                     buffer.offset += 8;\r
243                     break;\r
244                 case ProtoBuf.WIRE_TYPES.LDELIM:\r
245                     var len = buffer.readVarint32();\r
246                     buffer.offset += len;\r
247                     break;\r
248                 case ProtoBuf.WIRE_TYPES.STARTGROUP:\r
249                     while (skipTillGroupEnd(id, buffer)) {}\r
250                     break;\r
251                 default:\r
252                     throw Error("Illegal wire type for unknown field "+id+" in "+this.toString(true)+"#decode: "+wireType);\r
253             }\r
254             continue;\r
255         }\r
256         if (field.repeated && !field.options["packed"]) {\r
257             msg[field.name].push(field.decode(wireType, buffer));\r
258         } else if (field.map) {\r
259             var keyval = field.decode(wireType, buffer);\r
260             msg[field.name].set(keyval[0], keyval[1]);\r
261         } else {\r
262             msg[field.name] = field.decode(wireType, buffer);\r
263             if (field.oneof) { // Field is part of an OneOf (not a virtual OneOf field)\r
264                 var currentField = msg[field.oneof.name]; // Virtual field references currently set field\r
265                 if (currentField !== null && currentField !== field.name)\r
266                     msg[currentField] = null; // Clear currently set field\r
267                 msg[field.oneof.name] = field.name; // Point virtual field at this field\r
268             }\r
269         }\r
270     }\r
271 \r
272     // Check if all required fields are present and set default values for optional fields that are not\r
273     for (var i=0, k=this._fields.length; i<k; ++i) {\r
274         field = this._fields[i];\r
275         if (msg[field.name] === null) {\r
276             if (this.syntax === "proto3") { // Proto3 sets default values by specification\r
277                 msg[field.name] = field.defaultValue;\r
278             } else if (field.required) {\r
279                 var err = Error("Missing at least one required field for " + this.toString(true) + ": " + field.name);\r
280                 err["decoded"] = msg; // Still expose what we got\r
281                 throw(err);\r
282             } else if (ProtoBuf.populateDefaults && field.defaultValue !== null)\r
283                 msg[field.name] = field.defaultValue;\r
284         }\r
285     }\r
286     return msg;\r
287 };\r