// Protocol Buffers - Google's data interchange format // Copyright 2008 Google Inc. // http://code.google.com/p/protobuf/ // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. using System; using System.Collections.Generic; using System.IO; using Google.ProtocolBuffers.Descriptors; namespace Google.ProtocolBuffers { /// /// An implementation of IMessage that can represent arbitrary types, given a MessageaDescriptor. /// public sealed 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) { Builder builder = CreateBuilder(type); Builder dynamicBuilder = 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) { Builder builder = CreateBuilder(type); Builder dynamicBuilder = 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) { Builder builder = CreateBuilder(type); Builder dynamicBuilder = 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) { Builder builder = CreateBuilder(type); Builder dynamicBuilder = 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) { Builder builder = CreateBuilder(type); Builder dynamicBuilder = 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) { Builder builder = CreateBuilder(type); Builder dynamicBuilder = 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) { Builder builder = CreateBuilder(type); Builder dynamicBuilder = 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) { Builder builder = CreateBuilder(type); Builder dynamicBuilder = 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 new Builder(prototype.DescriptorForType).MergeFrom(prototype); } // ----------------------------------------------------------------- // Implementation of IMessage interface. public override MessageDescriptor DescriptorForType { get { return type; } } public override DynamicMessage DefaultInstanceForType { 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; } } public override Builder CreateBuilderForType() { 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."); } } /// /// Builder for dynamic messages. Instances are created with DynamicMessage.CreateBuilder. /// public sealed class Builder : AbstractBuilder { private readonly MessageDescriptor type; private FieldSet fields; private UnknownFieldSet unknownFields; internal Builder(MessageDescriptor type) { this.type = type; this.fields = FieldSet.CreateInstance(); this.unknownFields = UnknownFieldSet.DefaultInstance; } protected override Builder ThisBuilder { get { return this; } } public override Builder Clear() { fields.Clear(); return this; } public override Builder 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; } public override Builder MergeFrom(DynamicMessage other) { if (other.DescriptorForType != type) { throw new ArgumentException("MergeFrom(IMessage) can only merge messages of the same type."); } fields.MergeFrom(other); return this; } public override DynamicMessage Build() { if (!IsInitialized) { throw new UninitializedMessageException(new DynamicMessage(type, fields, unknownFields)); } return BuildPartial(); } /// /// Helper for DynamicMessage.ParseFrom() methods to call. Throws /// InvalidProtocolBufferException /// /// internal DynamicMessage BuildParsed() { if (!IsInitialized) { throw new UninitializedMessageException(new DynamicMessage(type, fields, unknownFields)).AsInvalidProtocolBufferException(); } return BuildPartial(); } public override DynamicMessage BuildPartial() { fields.MakeImmutable(); DynamicMessage result = new DynamicMessage(type, fields, unknownFields); fields = null; unknownFields = null; return result; } public override Builder Clone() { Builder result = new Builder(type); result.fields.MergeFrom(fields); return result; } public override bool IsInitialized { get { return fields.IsInitializedWithRespectTo(type); } } public override Builder MergeFrom(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; } } public override DynamicMessage DefaultInstanceForType { 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; } } public override Builder ClearField(FieldDescriptor field) { VerifyContainingType(field); fields.ClearField(field); return this; } public override int GetRepeatedFieldCount(FieldDescriptor field) { VerifyContainingType(field); return fields.GetRepeatedFieldCount(field); } public override Builder AddRepeatedField(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."); } } } } }