using System; using System.Collections.Generic; using System.IO; using System.Text; using Google.ProtocolBuffers.Descriptors; namespace Google.ProtocolBuffers { /// /// An implementation of IMessage that can represent arbitrary types, given a MessageaDescriptor. /// TODO: Implement appropriate generics. /// public class DynamicMessage : AbstractMessage { private readonly MessageDescriptor type; private readonly FieldSet fields; private readonly UnknownFieldSet unknownFields; private int memoizedSize = -1; /// /// Creates a DynamicMessage with the given FieldSet. /// /// /// /// private DynamicMessage(MessageDescriptor type, FieldSet fields, UnknownFieldSet unknownFields) { this.type = type; this.fields = fields; this.unknownFields = unknownFields; } /// /// Returns a DynamicMessage representing the default instance of the given type. /// /// /// public static DynamicMessage GetDefaultInstance(MessageDescriptor type) { return new DynamicMessage(type, FieldSet.DefaultInstance, UnknownFieldSet.DefaultInstance); } /// /// Parses a message of the given type from the given stream. /// public static DynamicMessage ParseFrom(MessageDescriptor type, CodedInputStream input) { IBuilder builder = CreateBuilder(type); Builder dynamicBuilder = (Builder)builder.MergeFrom(input); return dynamicBuilder.BuildParsed(); } /// /// Parse a message of the given type from the given stream and extension registry. /// /// /// /// /// public static DynamicMessage ParseFrom(MessageDescriptor type, CodedInputStream input, ExtensionRegistry extensionRegistry) { IBuilder builder = CreateBuilder(type); Builder dynamicBuilder = (Builder) builder.MergeFrom(input, extensionRegistry); return dynamicBuilder.BuildParsed(); } /// /// Parses a message of the given type from the given stream. /// public static DynamicMessage ParseFrom(MessageDescriptor type, Stream input) { IBuilder builder = CreateBuilder(type); Builder dynamicBuilder = (Builder)builder.MergeFrom(input); return dynamicBuilder.BuildParsed(); } /// /// Parse a message of the given type from the given stream and extension registry. /// /// /// /// /// public static DynamicMessage ParseFrom(MessageDescriptor type, Stream input, ExtensionRegistry extensionRegistry) { IBuilder builder = CreateBuilder(type); Builder dynamicBuilder = (Builder)builder.MergeFrom(input, extensionRegistry); return dynamicBuilder.BuildParsed(); } /// /// Parse as a message of the given type and return it. /// public static DynamicMessage ParseFrom(MessageDescriptor type, ByteString data) { IBuilder builder = CreateBuilder(type); Builder dynamicBuilder = (Builder)builder.MergeFrom(data); return dynamicBuilder.BuildParsed(); } /// /// Parse as a message of the given type and return it. /// public static DynamicMessage ParseFrom(MessageDescriptor type, ByteString data, ExtensionRegistry extensionRegistry) { IBuilder builder = CreateBuilder(type); Builder dynamicBuilder = (Builder)builder.MergeFrom(data, extensionRegistry); return dynamicBuilder.BuildParsed(); } /// /// Parse as a message of the given type and return it. /// public static DynamicMessage ParseFrom(MessageDescriptor type, byte[] data) { IBuilder builder = CreateBuilder(type); Builder dynamicBuilder = (Builder)builder.MergeFrom(data); return dynamicBuilder.BuildParsed(); } /// /// Parse as a message of the given type and return it. /// public static DynamicMessage ParseFrom(MessageDescriptor type, byte[] data, ExtensionRegistry extensionRegistry) { IBuilder builder = CreateBuilder(type); Builder dynamicBuilder = (Builder)builder.MergeFrom(data, extensionRegistry); return dynamicBuilder.BuildParsed(); } /// /// Constructs a builder for the given type. /// public static Builder CreateBuilder(MessageDescriptor type) { return new Builder(type); } /// /// Constructs a builder for a message of the same type as , /// and initializes it with the same contents. /// /// /// public static Builder CreateBuilder(IMessage prototype) { return (Builder) new Builder(prototype.DescriptorForType).MergeFrom(prototype); } // ----------------------------------------------------------------- // Implementation of IMessage interface. public override MessageDescriptor DescriptorForType { get { return type; } } protected override IMessage DefaultInstanceForTypeImpl { get { return GetDefaultInstance(type); } } public override IDictionary AllFields { get { return fields.AllFields; } } public override bool HasField(FieldDescriptor field) { VerifyContainingType(field); return fields.HasField(field); } public override object this[FieldDescriptor field] { get { VerifyContainingType(field); object result = fields[field]; if (result == null) { result = GetDefaultInstance(field.MessageType); } return result; } } public override int GetRepeatedFieldCount(FieldDescriptor field) { VerifyContainingType(field); return fields.GetRepeatedFieldCount(field); } public override object this[FieldDescriptor field, int index] { get { VerifyContainingType(field); return fields[field, index]; } } public override UnknownFieldSet UnknownFields { get { return unknownFields; } } public bool Initialized { get { return fields.IsInitializedWithRespectTo(type); } } public override void WriteTo(CodedOutputStream output) { fields.WriteTo(output); if (type.Options.MessageSetWireFormat) { unknownFields.WriteAsMessageSetTo(output); } else { unknownFields.WriteTo(output); } } public override int SerializedSize { get { int size = memoizedSize; if (size != -1) return size; size = fields.SerializedSize; if (type.Options.MessageSetWireFormat) { size += unknownFields.SerializedSizeAsMessageSet; } else { size += unknownFields.SerializedSize; } memoizedSize = size; return size; } } protected override IBuilder CreateBuilderForTypeImpl() { return new Builder(type); } /// /// Verifies that the field is a field of this message. /// private void VerifyContainingType(FieldDescriptor field) { if (field.ContainingType != type) { throw new ArgumentException("FieldDescriptor does not match message type."); } } public class Builder : AbstractBuilder { private readonly MessageDescriptor type; private FieldSet fields; private UnknownFieldSet unknownFields; internal Builder(MessageDescriptor type) { this.type = type; this.fields = FieldSet.CreateFieldSet(); this.unknownFields = UnknownFieldSet.DefaultInstance; } public DynamicMessage Build() { return (DynamicMessage)((IBuilder)this).Build(); } public override IBuilder Clear() { fields.Clear(); return this; } public override IBuilder MergeFrom(IMessage other) { if (other.DescriptorForType != type) { throw new ArgumentException("MergeFrom(IMessage) can only merge messages of the same type."); } fields.MergeFrom(other); return this; } protected override IMessage BuildImpl() { if (!IsInitialized) { throw new UninitializedMessageException(new DynamicMessage(type, fields, unknownFields)); } return BuildPartialImpl(); } /// /// Helper for DynamicMessage.ParseFrom() methods to call. Throws /// InvalidProtocolBufferException /// /// internal DynamicMessage BuildParsed() { if (!IsInitialized) { throw new UninitializedMessageException(new DynamicMessage(type, fields, unknownFields)).AsInvalidProtocolBufferException(); } return (DynamicMessage) BuildPartialImpl(); } protected override IMessage BuildPartialImpl() { fields.MakeImmutable(); DynamicMessage result = new DynamicMessage(type, fields, unknownFields); fields = null; unknownFields = null; return result; } protected override IBuilder CloneImpl() { Builder result = new Builder(type); result.fields.MergeFrom(fields); return result; } public override bool IsInitialized { get { return fields.IsInitializedWithRespectTo(type); } } protected override IBuilder MergeFromImpl(CodedInputStream input, ExtensionRegistry extensionRegistry) { UnknownFieldSet.Builder unknownFieldsBuilder = UnknownFieldSet.CreateBuilder(unknownFields); FieldSet.MergeFrom(input, unknownFieldsBuilder, extensionRegistry, this); unknownFields = unknownFieldsBuilder.Build(); return this; } public override MessageDescriptor DescriptorForType { get { return type; } } protected override IMessage DefaultInstanceForTypeImpl { get { return GetDefaultInstance(type); } } public override IDictionary AllFields { get { return fields.AllFields; } } public override IBuilder CreateBuilderForField(FieldDescriptor field) { VerifyContainingType(field); if (field.MappedType != MappedType.Message) { throw new ArgumentException("CreateBuilderForField is only valid for fields with message type."); } return new Builder(field.MessageType); } public override bool HasField(FieldDescriptor field) { VerifyContainingType(field); return fields.HasField(field); } public override object this[FieldDescriptor field, int index] { get { VerifyContainingType(field); return fields[field, index]; } set { VerifyContainingType(field); fields[field, index] = value; } } public override object this[FieldDescriptor field] { get { VerifyContainingType(field); object result = fields[field]; if (result == null) { result = GetDefaultInstance(field.MessageType); } return result; } set { VerifyContainingType(field); fields[field] = value; } } protected override IBuilder ClearFieldImpl(FieldDescriptor field) { VerifyContainingType(field); fields.ClearField(field); return this; } public override int GetRepeatedFieldCount(FieldDescriptor field) { VerifyContainingType(field); return fields.GetRepeatedFieldCount(field); } protected override IBuilder AddRepeatedFieldImpl(FieldDescriptor field, object value) { VerifyContainingType(field); fields.AddRepeatedField(field, value); return this; } public override UnknownFieldSet UnknownFields { get { return unknownFields; } set { unknownFields = value; } } /// /// Verifies that the field is a field of this message. /// /// private void VerifyContainingType(FieldDescriptor field) { if (field.ContainingType != type) { throw new ArgumentException("FieldDescriptor does not match message type."); } } } } }