internal void MergeFrom(ICodedInputStream input, ExtensionRegistry extensionRegistry, IBuilder builder) { uint tag; string name; while (input.ReadTag(out tag, out name)) { if (tag == 0 && name != null) { FieldDescriptor fieldByName = builder.DescriptorForType.FindFieldByName(name); if (fieldByName != null) { tag = WireFormat.MakeTag(fieldByName); } else { ExtensionInfo extension = extensionRegistry.FindByName(builder.DescriptorForType, name); if (extension != null) { tag = WireFormat.MakeTag(extension.Descriptor); } } } if (tag == 0) { if (input.SkipField()) { continue; //can't merge unknown without field tag } break; } if (!MergeFieldFrom(input, extensionRegistry, builder, tag, name)) { // end group tag break; } } }
/// <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); }
/// <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.FindByName(type, 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. #if PORTABLE_LIBRARY String lowerName = name.ToLowerInvariant(); #else String lowerName = name.ToLower(FrameworkPortability.InvariantCulture); #endif 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); } }