--- /dev/null
+/**\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