| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620 | // 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.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 class UnknownFieldSet {    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(CodedOutputStream output) {      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 {        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>    /// Serializes the message to a ByteString and returns it. This is    /// just a trivial wrapper around WriteTo(CodedOutputStream).    /// </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(CodedOutputStream).    /// </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(CodedOutputStream).    /// </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(CodedOutputStream output) {      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 {        int result = 0;        foreach (KeyValuePair<int, UnknownField> entry in fields) {          result += entry.Value.GetSerializedSizeAsMessageSetExtension(entry.Key);        }        return result;      }    }    /// <summary>    /// Parses an UnknownFieldSet from the given input.    /// </summary>    public static UnknownFieldSet ParseFrom(CodedInputStream 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();    }    /// <summary>    /// Builder for UnknownFieldSets.    /// </summary>    public sealed class Builder    {      /// <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 = new SortedList<int, UnknownField>();      // 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).      int lastFieldNumber;      UnknownField.Builder lastField;      internal Builder() {      }      /// <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(CodedInputStream input) {        while (true) {          uint tag = input.ReadTag();          if (tag == 0 || !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, CodedInputStream input) {        int number = WireFormat.GetTagFieldNumber(tag);        switch (WireFormat.GetTagWireType(tag)) {          case WireFormat.WireType.Varint:            GetFieldBuilder(number).AddVarint(input.ReadUInt64());            return true;          case WireFormat.WireType.Fixed64:            GetFieldBuilder(number).AddFixed64(input.ReadFixed64());            return true;          case WireFormat.WireType.LengthDelimited:            GetFieldBuilder(number).AddLengthDelimited(input.ReadBytes());            return true;          case WireFormat.WireType.StartGroup: {            Builder subBuilder = CreateBuilder();            input.ReadUnknownGroup(number, subBuilder);            GetFieldBuilder(number).AddGroup(subBuilder.Build());            return true;          }          case WireFormat.WireType.EndGroup:            return false;          case WireFormat.WireType.Fixed32:            GetFieldBuilder(number).AddFixed32(input.ReadFixed32());            return true;          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(CodedInputStream).      /// </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(CodedInputStream).      /// </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(CodedInputStream).      /// </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(CodedInputStream input, ExtensionRegistry extensionRegistry, IBuilder builder) {        while (true) {          uint tag = input.ReadTag();          if (tag == 0) {            break;          }          if (!MergeFieldFrom(input, extensionRegistry, builder, tag)) {            // end group tag            break;          }        }      }      /// <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;        IMessage 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.FieldType)) {          return MergeFieldFrom(tag, input);        }        object value;        switch (field.FieldType) {          case FieldType.Group:          case FieldType.Message: {              IBuilder subBuilder;              if (defaultFieldInstance != null) {                subBuilder = defaultFieldInstance.WeakCreateBuilderForType();              } else {                subBuilder = builder.CreateBuilderForField(field);              }              if (!field.IsRepeated) {                subBuilder.WeakMergeFrom((IMessage)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"        IBuilder 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();                IMessage originalMessage = (IMessage)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();        }      }    }  }}
 |