| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376 | #region Copyright notice and license// Protocol Buffers - Google's data interchange format// Copyright 2015 Google Inc.  All rights reserved.// https://developers.google.com/protocol-buffers///// 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.#endregionusing System;using System.Collections.Generic;using System.IO;using System.Security;using Google.Protobuf.Reflection;namespace Google.Protobuf{    /// <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.    ///    /// Most users will never need to use this class directly.    /// </summary>    public sealed partial class UnknownFieldSet    {        private readonly IDictionary<int, UnknownField> fields;        /// <summary>        /// Creates a new UnknownFieldSet.        /// </summary>        internal UnknownFieldSet()        {            this.fields = new Dictionary<int, UnknownField>();        }        /// <summary>        /// Checks whether or not the given field number is present in the set.        /// </summary>        internal bool HasField(int field)        {            return fields.ContainsKey(field);        }        /// <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 CalculateSize()        {            int result = 0;            foreach (KeyValuePair<int, UnknownField> entry in fields)            {                result += entry.Value.GetSerializedSize(entry.Key);            }            return result;        }        /// <summary>        /// Checks if two unknown field sets are equal.        /// </summary>        public override bool Equals(object other)        {            if (ReferenceEquals(this, other))            {                return true;            }            UnknownFieldSet otherSet = other as UnknownFieldSet;            IDictionary<int, UnknownField> otherFields = otherSet.fields;            if (fields.Count  != otherFields.Count)            {                return false;            }            foreach (KeyValuePair<int, UnknownField> leftEntry in fields)            {                UnknownField rightValue;                if (!otherFields.TryGetValue(leftEntry.Key, out rightValue))                {                    return false;                }                if (!leftEntry.Value.Equals(rightValue))                {                    return false;                }            }            return true;        }        /// <summary>        /// Gets the unknown field set's hash code.        /// </summary>        public override int GetHashCode()        {            int ret = 1;            foreach (KeyValuePair<int, UnknownField> field in fields)            {                // Use ^ here to make the field order irrelevant.                int hash = field.Key.GetHashCode() ^ field.Value.GetHashCode();                ret ^= hash;            }            return ret;        }        // Optimization:  We keep around 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 lastField;        private UnknownField GetOrAddField(int number)        {            if (lastField != null && number == lastFieldNumber)            {                return lastField;            }            if (number == 0)            {                return null;            }            UnknownField existing;            if (fields.TryGetValue(number, out existing))            {                return existing;            }            lastField = new UnknownField();            AddOrReplaceField(number, lastField);            lastFieldNumber = number;            return lastField;        }        /// <summary>        /// Adds a field to the set. If a field with the same number already exists, it        /// is replaced.        /// </summary>        internal UnknownFieldSet AddOrReplaceField(int number, UnknownField field)        {            if (number == 0)            {                throw new ArgumentOutOfRangeException("number", "Zero is not a valid field number.");            }            fields[number] = field;            return this;        }                /// <summary>        /// Parse a single field from <paramref name="ctx"/> and merge it        /// into this set.        /// </summary>        /// <param name="ctx">The parse context from which to read the field</param>        /// <returns>false if the tag is an "end group" tag, true otherwise</returns>        private bool MergeFieldFrom(ref ParseContext ctx)        {            uint tag = ctx.LastTag;            int number = WireFormat.GetTagFieldNumber(tag);            switch (WireFormat.GetTagWireType(tag))            {                case WireFormat.WireType.Varint:                    {                        ulong uint64 = ctx.ReadUInt64();                        GetOrAddField(number).AddVarint(uint64);                        return true;                    }                case WireFormat.WireType.Fixed32:                    {                        uint uint32 = ctx.ReadFixed32();                        GetOrAddField(number).AddFixed32(uint32);                        return true;                    }                case WireFormat.WireType.Fixed64:                    {                        ulong uint64 = ctx.ReadFixed64();                        GetOrAddField(number).AddFixed64(uint64);                        return true;                    }                case WireFormat.WireType.LengthDelimited:                    {                        ByteString bytes = ctx.ReadBytes();                        GetOrAddField(number).AddLengthDelimited(bytes);                        return true;                    }                case WireFormat.WireType.StartGroup:                    {                        UnknownFieldSet set = new UnknownFieldSet();                        ParsingPrimitivesMessages.ReadGroup(ref ctx, number, set);                        GetOrAddField(number).AddGroup(set);                        return true;                    }                case WireFormat.WireType.EndGroup:                    {                        return false;                    }                default:                    throw InvalidProtocolBufferException.InvalidWireType();            }        }        internal void MergeGroupFrom(ref ParseContext ctx)        {            while (true)            {                uint tag = ctx.ReadTag();                if (tag == 0)                {                    break;                }                if (!MergeFieldFrom(ref ctx))                {                    break;                }            }        }        /// <summary>        /// Create a new UnknownFieldSet if unknownFields is null.        /// Parse a single field from <paramref name="input"/> and merge it        /// into unknownFields. If <paramref name="input"/> is configured to discard unknown fields,        /// <paramref name="unknownFields"/> will be returned as-is and the field will be skipped.        /// </summary>        /// <param name="unknownFields">The UnknownFieldSet which need to be merged</param>        /// <param name="input">The coded input stream containing the field</param>        /// <returns>The merged UnknownFieldSet</returns>        public static UnknownFieldSet MergeFieldFrom(UnknownFieldSet unknownFields,                                                     CodedInputStream input)        {            ParseContext.Initialize(input, out ParseContext ctx);            try            {                return MergeFieldFrom(unknownFields, ref ctx);            }            finally            {                ctx.CopyStateTo(input);            }        }        /// <summary>        /// Create a new UnknownFieldSet if unknownFields is null.        /// Parse a single field from <paramref name="ctx"/> and merge it        /// into unknownFields. If <paramref name="ctx"/> is configured to discard unknown fields,        /// <paramref name="unknownFields"/> will be returned as-is and the field will be skipped.        /// </summary>        /// <param name="unknownFields">The UnknownFieldSet which need to be merged</param>        /// <param name="ctx">The parse context from which to read the field</param>        /// <returns>The merged UnknownFieldSet</returns>        [SecuritySafeCritical]        public static UnknownFieldSet MergeFieldFrom(UnknownFieldSet unknownFields,                                                     ref ParseContext ctx)        {            if (ctx.DiscardUnknownFields)            {                ParsingPrimitivesMessages.SkipLastField(ref ctx.buffer, ref ctx.state);                return unknownFields;            }            if (unknownFields == null)            {                unknownFields = new UnknownFieldSet();            }            if (!unknownFields.MergeFieldFrom(ref ctx))            {                throw new InvalidProtocolBufferException("Merge an unknown field of end-group tag, indicating that the corresponding start-group was missing."); // match the old code-gen            }            return unknownFields;        }        /// <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>        private UnknownFieldSet MergeFrom(UnknownFieldSet other)        {            if (other != null)            {                foreach (KeyValuePair<int, UnknownField> entry in other.fields)                {                    MergeField(entry.Key, entry.Value);                }            }            return this;        }        /// <summary>        /// Created a new UnknownFieldSet to <paramref name="unknownFields"/> if        /// needed and merges the fields from <paramref name="other"/> into the first 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 static UnknownFieldSet MergeFrom(UnknownFieldSet unknownFields,                                                UnknownFieldSet other)        {            if (other == null)            {                return unknownFields;            }            if (unknownFields == null)            {                unknownFields = new UnknownFieldSet();            }            unknownFields.MergeFrom(other);            return unknownFields;        }        /// <summary>        /// Adds a field to the unknown field set. If a field with the same        /// number already exists, the two are merged.        /// </summary>        private UnknownFieldSet MergeField(int number, UnknownField field)        {            if (number == 0)            {                throw new ArgumentOutOfRangeException("number", "Zero is not a valid field number.");            }            if (HasField(number))            {                GetOrAddField(number).MergeFrom(field);            }            else            {                AddOrReplaceField(number, field);            }            return this;        }        /// <summary>        /// Clone an unknown field set from <paramref name="other"/>.        /// </summary>        public static UnknownFieldSet Clone(UnknownFieldSet other)        {            if (other == null)            {                return null;            }            UnknownFieldSet unknownFields = new UnknownFieldSet();            unknownFields.MergeFrom(other);            return unknownFields;        }    }}
 |