| #region Copyright notice and license | |
| // Protocol Buffers - Google's data interchange format | |
| // Copyright 2008 Google Inc. All rights reserved. | |
| // http://github.com/jskeet/dotnet-protobufs/ | |
| // Original C++/Java/Python code: | |
| // http://code.google.com/p/protobuf/ | |
| // | |
| // Redistribution and use in source and binary forms, with or without | |
| // modification, are permitted provided that the following conditions are | |
| // met: | |
| // | |
| // * Redistributions of source code must retain the above copyright | |
| // notice, this list of conditions and the following disclaimer. | |
| // * Redistributions in binary form must reproduce the above | |
| // copyright notice, this list of conditions and the following disclaimer | |
| // in the documentation and/or other materials provided with the | |
| // distribution. | |
| // * Neither the name of Google Inc. nor the names of its | |
| // contributors may be used to endorse or promote products derived from | |
| // this software without specific prior written permission. | |
| // | |
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
| // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
| // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
| // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
| // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
| // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
| // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| #endregion | |
| using System; | |
| using System.Collections.Generic; | |
| using System.IO; | |
| using Google.ProtocolBuffers.Collections; | |
| using Google.ProtocolBuffers.Descriptors; | |
| namespace Google.ProtocolBuffers | |
| { | |
| /// <summary> | |
| /// Used to keep track of fields which were seen when parsing a protocol message | |
| /// but whose field numbers or types are unrecognized. This most frequently | |
| /// occurs when new fields are added to a message type and then messages containing | |
| /// those fields are read by old software that was built before the new types were | |
| /// added. | |
| /// | |
| /// Every message contains an UnknownFieldSet. | |
| /// | |
| /// Most users will never need to use this class directly. | |
| /// </summary> | |
| public sealed partial class UnknownFieldSet : IMessageLite | |
| { | |
| private static readonly UnknownFieldSet defaultInstance = | |
| new UnknownFieldSet(new Dictionary<int, UnknownField>()); | |
| private readonly IDictionary<int, UnknownField> fields; | |
| private UnknownFieldSet(IDictionary<int, UnknownField> fields) | |
| { | |
| this.fields = fields; | |
| } | |
| /// <summary> | |
| /// Creates a new unknown field set builder. | |
| /// </summary> | |
| public static Builder CreateBuilder() | |
| { | |
| return new Builder(); | |
| } | |
| /// <summary> | |
| /// Creates a new unknown field set builder | |
| /// and initialize it from <paramref name="original"/>. | |
| /// </summary> | |
| public static Builder CreateBuilder(UnknownFieldSet original) | |
| { | |
| return new Builder().MergeFrom(original); | |
| } | |
| public static UnknownFieldSet DefaultInstance | |
| { | |
| get { return defaultInstance; } | |
| } | |
| /// <summary> | |
| /// Returns a read-only view of the mapping from field numbers to values. | |
| /// </summary> | |
| public IDictionary<int, UnknownField> FieldDictionary | |
| { | |
| get { return Dictionaries.AsReadOnly(fields); } | |
| } | |
| /// <summary> | |
| /// Checks whether or not the given field number is present in the set. | |
| /// </summary> | |
| public bool HasField(int field) | |
| { | |
| return fields.ContainsKey(field); | |
| } | |
| /// <summary> | |
| /// Fetches a field by number, returning an empty field if not present. | |
| /// Never returns null. | |
| /// </summary> | |
| public UnknownField this[int number] | |
| { | |
| get | |
| { | |
| UnknownField ret; | |
| if (!fields.TryGetValue(number, out ret)) | |
| { | |
| ret = UnknownField.DefaultInstance; | |
| } | |
| return ret; | |
| } | |
| } | |
| /// <summary> | |
| /// Serializes the set and writes it to <paramref name="output"/>. | |
| /// </summary> | |
| public void WriteTo(ICodedOutputStream output) | |
| { | |
| // Avoid creating enumerator for the most common code path. | |
| if (fields.Count > 0) | |
| { | |
| foreach (KeyValuePair<int, UnknownField> entry in fields) | |
| { | |
| entry.Value.WriteTo(entry.Key, output); | |
| } | |
| } | |
| } | |
| /// <summary> | |
| /// Gets the number of bytes required to encode this set. | |
| /// </summary> | |
| public int SerializedSize | |
| { | |
| get | |
| { | |
| // Avoid creating enumerator for the most common code path. | |
| if (fields.Count == 0) | |
| { | |
| return 0; | |
| } | |
| int result = 0; | |
| foreach (KeyValuePair<int, UnknownField> entry in fields) | |
| { | |
| result += entry.Value.GetSerializedSize(entry.Key); | |
| } | |
| return result; | |
| } | |
| } | |
| /// <summary> | |
| /// Converts the set to a string in protocol buffer text format. This | |
| /// is just a trivial wrapper around TextFormat.PrintToString. | |
| /// </summary> | |
| public override String ToString() | |
| { | |
| return TextFormat.PrintToString(this); | |
| } | |
| /// <summary> | |
| /// Converts the set to a string in protocol buffer text format. This | |
| /// is just a trivial wrapper around TextFormat.PrintToString. | |
| /// </summary> | |
| public void PrintTo(TextWriter writer) | |
| { | |
| TextFormat.Print(this, writer); | |
| } | |
| /// <summary> | |
| /// Serializes the message to a ByteString and returns it. This is | |
| /// just a trivial wrapper around WriteTo(ICodedOutputStream). | |
| /// </summary> | |
| /// <returns></returns> | |
| public ByteString ToByteString() | |
| { | |
| ByteString.CodedBuilder codedBuilder = new ByteString.CodedBuilder(SerializedSize); | |
| WriteTo(codedBuilder.CodedOutput); | |
| return codedBuilder.Build(); | |
| } | |
| /// <summary> | |
| /// Serializes the message to a byte array and returns it. This is | |
| /// just a trivial wrapper around WriteTo(ICodedOutputStream). | |
| /// </summary> | |
| /// <returns></returns> | |
| public byte[] ToByteArray() | |
| { | |
| byte[] data = new byte[SerializedSize]; | |
| CodedOutputStream output = CodedOutputStream.CreateInstance(data); | |
| WriteTo(output); | |
| output.CheckNoSpaceLeft(); | |
| return data; | |
| } | |
| /// <summary> | |
| /// Serializes the message and writes it to <paramref name="output"/>. This is | |
| /// just a trivial wrapper around WriteTo(ICodedOutputStream). | |
| /// </summary> | |
| /// <param name="output"></param> | |
| public void WriteTo(Stream output) | |
| { | |
| CodedOutputStream codedOutput = CodedOutputStream.CreateInstance(output); | |
| WriteTo(codedOutput); | |
| codedOutput.Flush(); | |
| } | |
| /// <summary> | |
| /// Serializes the set and writes it to <paramref name="output"/> using | |
| /// the MessageSet wire format. | |
| /// </summary> | |
| public void WriteAsMessageSetTo(ICodedOutputStream output) | |
| { | |
| // Avoid creating enumerator for the most common code path. | |
| if (fields.Count > 0) | |
| { | |
| foreach (KeyValuePair<int, UnknownField> entry in fields) | |
| { | |
| entry.Value.WriteAsMessageSetExtensionTo(entry.Key, output); | |
| } | |
| } | |
| } | |
| /// <summary> | |
| /// Gets the number of bytes required to encode this set using the MessageSet | |
| /// wire format. | |
| /// </summary> | |
| public int SerializedSizeAsMessageSet | |
| { | |
| get | |
| { | |
| // Avoid creating enumerator for the most common code path. | |
| if (fields.Count == 0) | |
| { | |
| return 0; | |
| } | |
| int result = 0; | |
| foreach (KeyValuePair<int, UnknownField> entry in fields) | |
| { | |
| result += entry.Value.GetSerializedSizeAsMessageSetExtension(entry.Key); | |
| } | |
| return result; | |
| } | |
| } | |
| public override bool Equals(object other) | |
| { | |
| if (ReferenceEquals(this, other)) | |
| { | |
| return true; | |
| } | |
| UnknownFieldSet otherSet = other as UnknownFieldSet; | |
| return otherSet != null && Dictionaries.Equals(fields, otherSet.fields); | |
| } | |
| public override int GetHashCode() | |
| { | |
| return Dictionaries.GetHashCode(fields); | |
| } | |
| /// <summary> | |
| /// Parses an UnknownFieldSet from the given input. | |
| /// </summary> | |
| public static UnknownFieldSet ParseFrom(ICodedInputStream input) | |
| { | |
| return CreateBuilder().MergeFrom(input).Build(); | |
| } | |
| /// <summary> | |
| /// Parses an UnknownFieldSet from the given data. | |
| /// </summary> | |
| public static UnknownFieldSet ParseFrom(ByteString data) | |
| { | |
| return CreateBuilder().MergeFrom(data).Build(); | |
| } | |
| /// <summary> | |
| /// Parses an UnknownFieldSet from the given data. | |
| /// </summary> | |
| public static UnknownFieldSet ParseFrom(byte[] data) | |
| { | |
| return CreateBuilder().MergeFrom(data).Build(); | |
| } | |
| /// <summary> | |
| /// Parses an UnknownFieldSet from the given input. | |
| /// </summary> | |
| public static UnknownFieldSet ParseFrom(Stream input) | |
| { | |
| return CreateBuilder().MergeFrom(input).Build(); | |
| } | |
| #region IMessageLite Members | |
| public bool IsInitialized | |
| { | |
| get { return fields != null; } | |
| } | |
| public void WriteDelimitedTo(Stream output) | |
| { | |
| CodedOutputStream codedOutput = CodedOutputStream.CreateInstance(output); | |
| codedOutput.WriteRawVarint32((uint) SerializedSize); | |
| WriteTo(codedOutput); | |
| codedOutput.Flush(); | |
| } | |
| public IBuilderLite WeakCreateBuilderForType() | |
| { | |
| return new Builder(); | |
| } | |
| public IBuilderLite WeakToBuilder() | |
| { | |
| return new Builder(fields); | |
| } | |
| public IMessageLite WeakDefaultInstanceForType | |
| { | |
| get { return defaultInstance; } | |
| } | |
| #endregion | |
| /// <summary> | |
| /// Builder for UnknownFieldSets. | |
| /// </summary> | |
| public sealed partial class Builder : IBuilderLite | |
| { | |
| /// <summary> | |
| /// Mapping from number to field. Note that by using a SortedList we ensure | |
| /// that the fields will be serialized in ascending order. | |
| /// </summary> | |
| private IDictionary<int, UnknownField> fields; | |
| // Optimization: We keep around a builder for the last field that was | |
| // modified so that we can efficiently add to it multiple times in a | |
| // row (important when parsing an unknown repeated field). | |
| private int lastFieldNumber; | |
| private UnknownField.Builder lastField; | |
| internal Builder() | |
| { | |
| fields = new SortedDictionary<int, UnknownField>(); | |
| } | |
| internal Builder(IDictionary<int, UnknownField> dictionary) | |
| { | |
| fields = new SortedDictionary<int, UnknownField>(dictionary); | |
| } | |
| /// <summary> | |
| /// Returns a field builder for the specified field number, including any values | |
| /// which already exist. | |
| /// </summary> | |
| private UnknownField.Builder GetFieldBuilder(int number) | |
| { | |
| if (lastField != null) | |
| { | |
| if (number == lastFieldNumber) | |
| { | |
| return lastField; | |
| } | |
| // Note: AddField() will reset lastField and lastFieldNumber. | |
| AddField(lastFieldNumber, lastField.Build()); | |
| } | |
| if (number == 0) | |
| { | |
| return null; | |
| } | |
| lastField = UnknownField.CreateBuilder(); | |
| UnknownField existing; | |
| if (fields.TryGetValue(number, out existing)) | |
| { | |
| lastField.MergeFrom(existing); | |
| } | |
| lastFieldNumber = number; | |
| return lastField; | |
| } | |
| /// <summary> | |
| /// Build the UnknownFieldSet and return it. Once this method has been called, | |
| /// this instance will no longer be usable. Calling any method after this | |
| /// will throw a NullReferenceException. | |
| /// </summary> | |
| public UnknownFieldSet Build() | |
| { | |
| GetFieldBuilder(0); // Force lastField to be built. | |
| UnknownFieldSet result = fields.Count == 0 ? DefaultInstance : new UnknownFieldSet(fields); | |
| fields = null; | |
| return result; | |
| } | |
| /// <summary> | |
| /// Adds a field to the set. If a field with the same number already exists, it | |
| /// is replaced. | |
| /// </summary> | |
| public Builder AddField(int number, UnknownField field) | |
| { | |
| if (number == 0) | |
| { | |
| throw new ArgumentOutOfRangeException("number", "Zero is not a valid field number."); | |
| } | |
| if (lastField != null && lastFieldNumber == number) | |
| { | |
| // Discard this. | |
| lastField = null; | |
| lastFieldNumber = 0; | |
| } | |
| fields[number] = field; | |
| return this; | |
| } | |
| /// <summary> | |
| /// Resets the builder to an empty set. | |
| /// </summary> | |
| public Builder Clear() | |
| { | |
| fields.Clear(); | |
| lastFieldNumber = 0; | |
| lastField = null; | |
| return this; | |
| } | |
| /// <summary> | |
| /// Parse an entire message from <paramref name="input"/> and merge | |
| /// its fields into this set. | |
| /// </summary> | |
| public Builder MergeFrom(ICodedInputStream input) | |
| { | |
| uint tag; | |
| string name; | |
| while (input.ReadTag(out tag, out name)) | |
| { | |
| if (tag == 0) | |
| { | |
| if (input.SkipField()) | |
| { | |
| continue; //can't merge unknown without field tag | |
| } | |
| break; | |
| } | |
| if (!MergeFieldFrom(tag, input)) | |
| { | |
| break; | |
| } | |
| } | |
| return this; | |
| } | |
| /// <summary> | |
| /// Parse a single field from <paramref name="input"/> and merge it | |
| /// into this set. | |
| /// </summary> | |
| /// <param name="tag">The field's tag number, which was already parsed.</param> | |
| /// <param name="input">The coded input stream containing the field</param> | |
| /// <returns>false if the tag is an "end group" tag, true otherwise</returns> | |
| public bool MergeFieldFrom(uint tag, ICodedInputStream input) | |
| { | |
| if (tag == 0) | |
| { | |
| input.SkipField(); | |
| return true; | |
| } | |
| int number = WireFormat.GetTagFieldNumber(tag); | |
| switch (WireFormat.GetTagWireType(tag)) | |
| { | |
| case WireFormat.WireType.Varint: | |
| { | |
| ulong uint64 = 0; | |
| if (input.ReadUInt64(ref uint64)) | |
| { | |
| GetFieldBuilder(number).AddVarint(uint64); | |
| } | |
| return true; | |
| } | |
| case WireFormat.WireType.Fixed32: | |
| { | |
| uint uint32 = 0; | |
| if (input.ReadFixed32(ref uint32)) | |
| { | |
| GetFieldBuilder(number).AddFixed32(uint32); | |
| } | |
| return true; | |
| } | |
| case WireFormat.WireType.Fixed64: | |
| { | |
| ulong uint64 = 0; | |
| if (input.ReadFixed64(ref uint64)) | |
| { | |
| GetFieldBuilder(number).AddFixed64(uint64); | |
| } | |
| return true; | |
| } | |
| case WireFormat.WireType.LengthDelimited: | |
| { | |
| ByteString bytes = null; | |
| if (input.ReadBytes(ref bytes)) | |
| { | |
| GetFieldBuilder(number).AddLengthDelimited(bytes); | |
| } | |
| return true; | |
| } | |
| case WireFormat.WireType.StartGroup: | |
| { | |
| Builder subBuilder = CreateBuilder(); | |
| #pragma warning disable 0612 | |
| input.ReadUnknownGroup(number, subBuilder); | |
| #pragma warning restore 0612 | |
| GetFieldBuilder(number).AddGroup(subBuilder.Build()); | |
| return true; | |
| } | |
| case WireFormat.WireType.EndGroup: | |
| return false; | |
| default: | |
| throw InvalidProtocolBufferException.InvalidWireType(); | |
| } | |
| } | |
| /// <summary> | |
| /// Parses <paramref name="input"/> as an UnknownFieldSet and merge it | |
| /// with the set being built. This is just a small wrapper around | |
| /// MergeFrom(ICodedInputStream). | |
| /// </summary> | |
| public Builder MergeFrom(Stream input) | |
| { | |
| CodedInputStream codedInput = CodedInputStream.CreateInstance(input); | |
| MergeFrom(codedInput); | |
| codedInput.CheckLastTagWas(0); | |
| return this; | |
| } | |
| /// <summary> | |
| /// Parses <paramref name="data"/> as an UnknownFieldSet and merge it | |
| /// with the set being built. This is just a small wrapper around | |
| /// MergeFrom(ICodedInputStream). | |
| /// </summary> | |
| public Builder MergeFrom(ByteString data) | |
| { | |
| CodedInputStream input = data.CreateCodedInput(); | |
| MergeFrom(input); | |
| input.CheckLastTagWas(0); | |
| return this; | |
| } | |
| /// <summary> | |
| /// Parses <paramref name="data"/> as an UnknownFieldSet and merge it | |
| /// with the set being built. This is just a small wrapper around | |
| /// MergeFrom(ICodedInputStream). | |
| /// </summary> | |
| public Builder MergeFrom(byte[] data) | |
| { | |
| CodedInputStream input = CodedInputStream.CreateInstance(data); | |
| MergeFrom(input); | |
| input.CheckLastTagWas(0); | |
| return this; | |
| } | |
| /// <summary> | |
| /// Convenience method for merging a new field containing a single varint | |
| /// value. This is used in particular when an unknown enum value is | |
| /// encountered. | |
| /// </summary> | |
| public Builder MergeVarintField(int number, ulong value) | |
| { | |
| if (number == 0) | |
| { | |
| throw new ArgumentOutOfRangeException("number", "Zero is not a valid field number."); | |
| } | |
| GetFieldBuilder(number).AddVarint(value); | |
| return this; | |
| } | |
| /// <summary> | |
| /// Merges the fields from <paramref name="other"/> into this set. | |
| /// If a field number exists in both sets, the values in <paramref name="other"/> | |
| /// will be appended to the values in this set. | |
| /// </summary> | |
| public Builder MergeFrom(UnknownFieldSet other) | |
| { | |
| if (other != DefaultInstance) | |
| { | |
| foreach (KeyValuePair<int, UnknownField> entry in other.fields) | |
| { | |
| MergeField(entry.Key, entry.Value); | |
| } | |
| } | |
| return this; | |
| } | |
| /// <summary> | |
| /// Checks if the given field number is present in the set. | |
| /// </summary> | |
| public bool HasField(int number) | |
| { | |
| if (number == 0) | |
| { | |
| throw new ArgumentOutOfRangeException("number", "Zero is not a valid field number."); | |
| } | |
| return number == lastFieldNumber || fields.ContainsKey(number); | |
| } | |
| /// <summary> | |
| /// Adds a field to the unknown field set. If a field with the same | |
| /// number already exists, the two are merged. | |
| /// </summary> | |
| public Builder MergeField(int number, UnknownField field) | |
| { | |
| if (number == 0) | |
| { | |
| throw new ArgumentOutOfRangeException("number", "Zero is not a valid field number."); | |
| } | |
| if (HasField(number)) | |
| { | |
| GetFieldBuilder(number).MergeFrom(field); | |
| } | |
| else | |
| { | |
| // Optimization: We could call getFieldBuilder(number).mergeFrom(field) | |
| // in this case, but that would create a copy of the Field object. | |
| // We'd rather reuse the one passed to us, so call AddField() instead. | |
| AddField(number, field); | |
| } | |
| return this; | |
| } | |
| 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> | |
| /// Called by MergeFieldFrom to parse a MessageSet extension. | |
| /// </summary> | |
| private void MergeMessageSetExtensionFromCodedStream(ICodedInputStream 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; | |
| uint lastTag = WireFormat.MessageSetTag.ItemStart; | |
| uint tag; | |
| string name; | |
| while (input.ReadTag(out tag, out name)) | |
| { | |
| if (tag == 0 && name != null) | |
| { | |
| if (name == "type_id") | |
| { | |
| tag = WireFormat.MessageSetTag.TypeID; | |
| } | |
| else if (name == "message") | |
| { | |
| tag = WireFormat.MessageSetTag.Message; | |
| } | |
| } | |
| if (tag == 0) | |
| { | |
| if (input.SkipField()) | |
| { | |
| continue; //can't merge unknown without field tag | |
| } | |
| break; | |
| } | |
| lastTag = tag; | |
| if (tag == WireFormat.MessageSetTag.TypeID) | |
| { | |
| typeId = 0; | |
| // Zero is not a valid type ID. | |
| if (input.ReadInt32(ref typeId) && 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 (subBuilder != null) | |
| { | |
| // We already know the type, so we can parse directly from the input | |
| // with no copying. Hooray! | |
| input.ReadMessage(subBuilder, extensionRegistry); | |
| } | |
| else if (input.ReadBytes(ref rawBytes)) | |
| { | |
| if (typeId != 0) | |
| { | |
| // We don't know how to parse this. Ignore it. | |
| MergeField(typeId, | |
| UnknownField.CreateBuilder().AddLengthDelimited(rawBytes).Build()); | |
| } | |
| } | |
| } | |
| else | |
| { | |
| // Unknown tag. Skip it. | |
| if (!input.SkipField()) | |
| { | |
| break; // end of group | |
| } | |
| } | |
| } | |
| if (lastTag != WireFormat.MessageSetTag.ItemEnd) | |
| { | |
| throw InvalidProtocolBufferException.InvalidEndTag(); | |
| } | |
| if (subBuilder != null) | |
| { | |
| builder[field] = subBuilder.WeakBuild(); | |
| } | |
| } | |
| #region IBuilderLite Members | |
| bool IBuilderLite.IsInitialized | |
| { | |
| get { return fields != null; } | |
| } | |
| IBuilderLite IBuilderLite.WeakClear() | |
| { | |
| return Clear(); | |
| } | |
| IBuilderLite IBuilderLite.WeakMergeFrom(IMessageLite message) | |
| { | |
| return MergeFrom((UnknownFieldSet) message); | |
| } | |
| IBuilderLite IBuilderLite.WeakMergeFrom(ByteString data) | |
| { | |
| return MergeFrom(data); | |
| } | |
| IBuilderLite IBuilderLite.WeakMergeFrom(ByteString data, ExtensionRegistry registry) | |
| { | |
| return MergeFrom(data); | |
| } | |
| IBuilderLite IBuilderLite.WeakMergeFrom(ICodedInputStream input) | |
| { | |
| return MergeFrom(input); | |
| } | |
| IBuilderLite IBuilderLite.WeakMergeFrom(ICodedInputStream input, ExtensionRegistry registry) | |
| { | |
| return MergeFrom(input); | |
| } | |
| IMessageLite IBuilderLite.WeakBuild() | |
| { | |
| return Build(); | |
| } | |
| IMessageLite IBuilderLite.WeakBuildPartial() | |
| { | |
| return Build(); | |
| } | |
| IBuilderLite IBuilderLite.WeakClone() | |
| { | |
| return Build().WeakToBuilder(); | |
| } | |
| IMessageLite IBuilderLite.WeakDefaultInstanceForType | |
| { | |
| get { return DefaultInstance; } | |
| } | |
| #endregion | |
| } | |
| } | |
| } |