/// <summary> /// Parses a single field from the specified tokenizer and merges it into /// the builder. /// </summary> private static void MergeField(TextTokenizer tokenizer, ExtensionRegistry extensionRegistry, IBuilder builder) { FieldDescriptor field; MessageDescriptor type = builder.DescriptorForType; ExtensionInfo extension = null; if (tokenizer.TryConsume("[")) { // An extension. StringBuilder name = new StringBuilder(tokenizer.ConsumeIdentifier()); while (tokenizer.TryConsume(".")) { name.Append("."); name.Append(tokenizer.ConsumeIdentifier()); } extension = extensionRegistry[name.ToString()]; if (extension == null) { throw tokenizer.CreateFormatExceptionPreviousToken("Extension \"" + name + "\" not found in the ExtensionRegistry."); } else if (extension.Descriptor.ContainingType != type) { throw tokenizer.CreateFormatExceptionPreviousToken("Extension \"" + name + "\" does not extend message type \"" + type.FullName + "\"."); } tokenizer.Consume("]"); field = extension.Descriptor; } else { String name = tokenizer.ConsumeIdentifier(); field = type.FindDescriptor <FieldDescriptor>(name); // Group names are expected to be capitalized as they appear in the // .proto file, which actually matches their type names, not their field // names. if (field == null) { // Explicitly specify the invariant culture so that this code does not break when // executing in Turkey. String lowerName = name.ToLower(CultureInfo.InvariantCulture); field = type.FindDescriptor <FieldDescriptor>(lowerName); // If the case-insensitive match worked but the field is NOT a group, // TODO(jonskeet): What? Java comment ends here! if (field != null && field.FieldType != FieldType.Group) { field = null; } } // Again, special-case group names as described above. if (field != null && field.FieldType == FieldType.Group && field.MessageType.Name != name) { field = null; } if (field == null) { throw tokenizer.CreateFormatExceptionPreviousToken( "Message type \"" + type.FullName + "\" has no field named \"" + name + "\"."); } } object value = null; if (field.MappedType == MappedType.Message) { tokenizer.TryConsume(":"); // optional String endToken; if (tokenizer.TryConsume("<")) { endToken = ">"; } else { tokenizer.Consume("{"); endToken = "}"; } IBuilder subBuilder; if (extension == null) { subBuilder = builder.CreateBuilderForField(field); } else { subBuilder = extension.DefaultInstance.WeakCreateBuilderForType() as IBuilder; if (subBuilder == null) { throw new NotSupportedException("Lite messages are not supported."); } } while (!tokenizer.TryConsume(endToken)) { if (tokenizer.AtEnd) { throw tokenizer.CreateFormatException("Expected \"" + endToken + "\"."); } MergeField(tokenizer, extensionRegistry, subBuilder); } value = subBuilder.WeakBuild(); } else { tokenizer.Consume(":"); switch (field.FieldType) { case FieldType.Int32: case FieldType.SInt32: case FieldType.SFixed32: value = tokenizer.ConsumeInt32(); break; case FieldType.Int64: case FieldType.SInt64: case FieldType.SFixed64: value = tokenizer.ConsumeInt64(); break; case FieldType.UInt32: case FieldType.Fixed32: value = tokenizer.ConsumeUInt32(); break; case FieldType.UInt64: case FieldType.Fixed64: value = tokenizer.ConsumeUInt64(); break; case FieldType.Float: value = tokenizer.ConsumeFloat(); break; case FieldType.Double: value = tokenizer.ConsumeDouble(); break; case FieldType.Bool: value = tokenizer.ConsumeBoolean(); break; case FieldType.String: value = tokenizer.ConsumeString(); break; case FieldType.Bytes: value = tokenizer.ConsumeByteString(); break; case FieldType.Enum: { EnumDescriptor enumType = field.EnumType; if (tokenizer.LookingAtInteger()) { int number = tokenizer.ConsumeInt32(); value = enumType.FindValueByNumber(number); if (value == null) { throw tokenizer.CreateFormatExceptionPreviousToken( "Enum type \"" + enumType.FullName + "\" has no value with number " + number + "."); } } else { String id = tokenizer.ConsumeIdentifier(); value = enumType.FindValueByName(id); if (value == null) { throw tokenizer.CreateFormatExceptionPreviousToken( "Enum type \"" + enumType.FullName + "\" has no value named \"" + id + "\"."); } } break; } case FieldType.Message: case FieldType.Group: throw new InvalidOperationException("Can't get here."); } } if (field.IsRepeated) { builder.WeakAddRepeatedField(field, value); } else { builder.SetField(field, value); } }
/// <summary> /// Like <see cref="MergeFrom(CodedInputStream, ExtensionRegistry, IBuilder)" /> /// but parses a single field. /// </summary> /// <param name="input">The input to read the field from</param> /// <param name="extensionRegistry">Registry to use when an extension field is encountered</param> /// <param name="builder">Builder to merge field into, if it's a known field</param> /// <param name="tag">The tag, which should already have been read from the input</param> /// <returns>true unless the tag is an end-group tag</returns> internal bool MergeFieldFrom(CodedInputStream input, ExtensionRegistry extensionRegistry, IBuilder builder, uint tag) { MessageDescriptor type = builder.DescriptorForType; if (type.Options.MessageSetWireFormat && tag == WireFormat.MessageSetTag.ItemStart) { MergeMessageSetExtensionFromCodedStream(input, extensionRegistry, builder); return(true); } WireFormat.WireType wireType = WireFormat.GetTagWireType(tag); int fieldNumber = WireFormat.GetTagFieldNumber(tag); FieldDescriptor field; IMessageLite defaultFieldInstance = null; if (type.IsExtensionNumber(fieldNumber)) { ExtensionInfo extension = extensionRegistry[type, fieldNumber]; if (extension == null) { field = null; } else { field = extension.Descriptor; defaultFieldInstance = extension.DefaultInstance; } } else { field = type.FindFieldByNumber(fieldNumber); } // Unknown field or wrong wire type. Skip. if (field == null || wireType != WireFormat.GetWireType(field)) { return(MergeFieldFrom(tag, input)); } if (field.IsPacked) { int length = (int)input.ReadRawVarint32(); int limit = input.PushLimit(length); if (field.FieldType == FieldType.Enum) { while (!input.ReachedLimit) { int rawValue = input.ReadEnum(); object value = field.EnumType.FindValueByNumber(rawValue); if (value == null) { // If the number isn't recognized as a valid value for this // enum, drop it (don't even add it to unknownFields). return(true); } builder.WeakAddRepeatedField(field, value); } } else { while (!input.ReachedLimit) { Object value = input.ReadPrimitiveField(field.FieldType); builder.WeakAddRepeatedField(field, value); } } input.PopLimit(limit); } else { object value; switch (field.FieldType) { case FieldType.Group: case FieldType.Message: { IBuilderLite subBuilder; if (defaultFieldInstance != null) { subBuilder = defaultFieldInstance.WeakCreateBuilderForType(); } else { subBuilder = builder.CreateBuilderForField(field); } if (!field.IsRepeated) { subBuilder.WeakMergeFrom((IMessageLite)builder[field]); } if (field.FieldType == FieldType.Group) { input.ReadGroup(field.FieldNumber, subBuilder, extensionRegistry); } else { input.ReadMessage(subBuilder, extensionRegistry); } value = subBuilder.WeakBuild(); break; } case FieldType.Enum: { int rawValue = input.ReadEnum(); value = field.EnumType.FindValueByNumber(rawValue); // If the number isn't recognized as a valid value for this enum, // drop it. if (value == null) { MergeVarintField(fieldNumber, (ulong)rawValue); return(true); } break; } default: value = input.ReadPrimitiveField(field.FieldType); break; } if (field.IsRepeated) { builder.WeakAddRepeatedField(field, value); } else { builder[field] = value; } } return(true); }
/// <summary> /// Called by MergeFieldFrom to parse a MessageSet extension. /// </summary> private void MergeMessageSetExtensionFromCodedStream(CodedInputStream input, ExtensionRegistry extensionRegistry, IBuilder builder) { MessageDescriptor type = builder.DescriptorForType; // The wire format for MessageSet is: // message MessageSet { // repeated group Item = 1 { // required int32 typeId = 2; // required bytes message = 3; // } // } // "typeId" is the extension's field number. The extension can only be // a message type, where "message" contains the encoded bytes of that // message. // // In practice, we will probably never see a MessageSet item in which // the message appears before the type ID, or where either field does not // appear exactly once. However, in theory such cases are valid, so we // should be prepared to accept them. int typeId = 0; ByteString rawBytes = null; // If we encounter "message" before "typeId" IBuilderLite subBuilder = null; FieldDescriptor field = null; while (true) { uint tag = input.ReadTag(); if (tag == 0) { break; } if (tag == WireFormat.MessageSetTag.TypeID) { typeId = input.ReadInt32(); // Zero is not a valid type ID. if (typeId != 0) { ExtensionInfo extension = extensionRegistry[type, typeId]; if (extension != null) { field = extension.Descriptor; subBuilder = extension.DefaultInstance.WeakCreateBuilderForType(); IMessageLite originalMessage = (IMessageLite)builder[field]; if (originalMessage != null) { subBuilder.WeakMergeFrom(originalMessage); } if (rawBytes != null) { // We already encountered the message. Parse it now. // TODO(jonskeet): Check this is okay. It's subtly different from the Java, as it doesn't create an input stream from rawBytes. // In fact, why don't we just call MergeFrom(rawBytes)? And what about the extension registry? subBuilder.WeakMergeFrom(rawBytes.CreateCodedInput()); rawBytes = null; } } else { // Unknown extension number. If we already saw data, put it // in rawBytes. if (rawBytes != null) { MergeField(typeId, UnknownField.CreateBuilder().AddLengthDelimited(rawBytes).Build()); rawBytes = null; } } } } else if (tag == WireFormat.MessageSetTag.Message) { if (typeId == 0) { // We haven't seen a type ID yet, so we have to store the raw bytes for now. rawBytes = input.ReadBytes(); } else if (subBuilder == null) { // We don't know how to parse this. Ignore it. MergeField(typeId, UnknownField.CreateBuilder().AddLengthDelimited(input.ReadBytes()).Build()); } else { // We already know the type, so we can parse directly from the input // with no copying. Hooray! input.ReadMessage(subBuilder, extensionRegistry); } } else { // Unknown tag. Skip it. if (!input.SkipField(tag)) { break; // end of group } } } input.CheckLastTagWas(WireFormat.MessageSetTag.ItemEnd); if (subBuilder != null) { builder[field] = subBuilder.WeakBuild(); } }
/// <summary> /// Like <see cref="MergeFrom(ICodedInputStream, ExtensionRegistry, IBuilder)" /> /// but parses a single field. /// </summary> /// <param name="input">The input to read the field from</param> /// <param name="extensionRegistry">Registry to use when an extension field is encountered</param> /// <param name="builder">Builder to merge field into, if it's a known field</param> /// <param name="tag">The tag, which should already have been read from the input</param> /// <returns>true unless the tag is an end-group tag</returns> internal bool MergeFieldFrom(ICodedInputStream input, ExtensionRegistry extensionRegistry, IBuilder builder, uint tag, string fieldName) { if (tag == 0 && fieldName != null) { FieldDescriptor fieldByName = builder.DescriptorForType.FindFieldByName(fieldName); if (fieldByName != null) { tag = WireFormat.MakeTag(fieldByName); } else { ExtensionInfo extension = extensionRegistry.FindByName(builder.DescriptorForType, fieldName); if (extension != null) { tag = WireFormat.MakeTag(extension.Descriptor); } } } MessageDescriptor type = builder.DescriptorForType; if (type.Options.MessageSetWireFormat && tag == WireFormat.MessageSetTag.ItemStart) { MergeMessageSetExtensionFromCodedStream(input, extensionRegistry, builder); return(true); } WireFormat.WireType wireType = WireFormat.GetTagWireType(tag); int fieldNumber = WireFormat.GetTagFieldNumber(tag); FieldDescriptor field; IMessageLite defaultFieldInstance = null; if (type.IsExtensionNumber(fieldNumber)) { ExtensionInfo extension = extensionRegistry[type, fieldNumber]; if (extension == null) { field = null; } else { field = extension.Descriptor; defaultFieldInstance = extension.DefaultInstance; } } else { field = type.FindFieldByNumber(fieldNumber); } // Unknown field or wrong wire type. Skip. if (field == null) { return(MergeFieldFrom(tag, input)); } if (wireType != WireFormat.GetWireType(field)) { WireFormat.WireType expectedType = WireFormat.GetWireType(field.FieldType); if (wireType == expectedType) { //Allowed as of 2.3, this is unpacked data for a packed array } else if (field.IsRepeated && wireType == WireFormat.WireType.LengthDelimited && (expectedType == WireFormat.WireType.Varint || expectedType == WireFormat.WireType.Fixed32 || expectedType == WireFormat.WireType.Fixed64)) { //Allowed as of 2.3, this is packed data for an unpacked array } else { return(MergeFieldFrom(tag, input)); } } switch (field.FieldType) { case FieldType.Group: case FieldType.Message: { IBuilderLite subBuilder = (defaultFieldInstance != null) ? defaultFieldInstance.WeakCreateBuilderForType() : builder.CreateBuilderForField(field); if (!field.IsRepeated) { subBuilder.WeakMergeFrom((IMessageLite)builder[field]); if (field.FieldType == FieldType.Group) { input.ReadGroup(field.FieldNumber, subBuilder, extensionRegistry); } else { input.ReadMessage(subBuilder, extensionRegistry); } builder[field] = subBuilder.WeakBuild(); } else { List <IMessageLite> list = new List <IMessageLite>(); if (field.FieldType == FieldType.Group) { input.ReadGroupArray(tag, fieldName, list, subBuilder.WeakDefaultInstanceForType, extensionRegistry); } else { input.ReadMessageArray(tag, fieldName, list, subBuilder.WeakDefaultInstanceForType, extensionRegistry); } foreach (IMessageLite m in list) { builder.WeakAddRepeatedField(field, m); } return(true); } break; } case FieldType.Enum: { if (!field.IsRepeated) { object unknown; IEnumLite value = null; if (input.ReadEnum(ref value, out unknown, field.EnumType)) { builder[field] = value; } else if (unknown is int) { MergeVarintField(fieldNumber, (ulong)(int)unknown); } } else { ICollection <object> unknown; List <IEnumLite> list = new List <IEnumLite>(); input.ReadEnumArray(tag, fieldName, list, out unknown, field.EnumType); foreach (IEnumLite en in list) { builder.WeakAddRepeatedField(field, en); } if (unknown != null) { foreach (object oval in unknown) { if (oval is int) { MergeVarintField(fieldNumber, (ulong)(int)oval); } } } } break; } default: { if (!field.IsRepeated) { object value = null; if (input.ReadPrimitiveField(field.FieldType, ref value)) { builder[field] = value; } } else { List <object> list = new List <object>(); input.ReadPrimitiveArray(field.FieldType, tag, fieldName, list); foreach (object oval in list) { builder.WeakAddRepeatedField(field, oval); } } break; } } return(true); }