| using System; | |
| using System.Collections.Generic; | |
| using System.Globalization; | |
| using Google.ProtocolBuffers.Descriptors; | |
| //Disable CS3011: only CLS-compliant members can be abstract | |
| #pragma warning disable 3011 | |
| namespace Google.ProtocolBuffers.Serialization | |
| { | |
| /// <summary> | |
| /// Provides a base-class that provides some basic functionality for handling type dispatching | |
| /// </summary> | |
| public abstract class AbstractReader : ICodedInputStream | |
| { | |
| private const int DefaultMaxDepth = 64; | |
| private int _depth; | |
| /// <summary> Constructs a new reader </summary> | |
| protected AbstractReader() { MaxDepth = DefaultMaxDepth; } | |
| /// <summary> Gets or sets the maximum recursion depth allowed </summary> | |
| public int MaxDepth { get; set; } | |
| /// <summary> | |
| /// Merges the contents of stream into the provided message builder | |
| /// </summary> | |
| public TBuilder Merge<TBuilder>(TBuilder builder) where TBuilder : IBuilderLite | |
| { | |
| return Merge(builder, ExtensionRegistry.Empty); | |
| } | |
| /// <summary> | |
| /// Merges the contents of stream into the provided message builder | |
| /// </summary> | |
| public abstract TBuilder Merge<TBuilder>(TBuilder builder, ExtensionRegistry registry) | |
| where TBuilder : IBuilderLite; | |
| /// <summary> | |
| /// Peeks at the next field in the input stream and returns what information is available. | |
| /// </summary> | |
| /// <remarks> | |
| /// This may be called multiple times without actually reading the field. Only after the field | |
| /// is either read, or skipped, should PeekNext return a different value. | |
| /// </remarks> | |
| protected abstract bool PeekNext(out string field); | |
| /// <summary> | |
| /// Causes the reader to skip past this field | |
| /// </summary> | |
| protected abstract void Skip(); | |
| /// <summary> | |
| /// Returns true if it was able to read a Boolean from the input | |
| /// </summary> | |
| protected abstract bool Read(ref bool value); | |
| /// <summary> | |
| /// Returns true if it was able to read a Int32 from the input | |
| /// </summary> | |
| protected abstract bool Read(ref int value); | |
| /// <summary> | |
| /// Returns true if it was able to read a UInt32 from the input | |
| /// </summary> | |
| protected abstract bool Read(ref uint value); | |
| /// <summary> | |
| /// Returns true if it was able to read a Int64 from the input | |
| /// </summary> | |
| protected abstract bool Read(ref long value); | |
| /// <summary> | |
| /// Returns true if it was able to read a UInt64 from the input | |
| /// </summary> | |
| protected abstract bool Read(ref ulong value); | |
| /// <summary> | |
| /// Returns true if it was able to read a Single from the input | |
| /// </summary> | |
| protected abstract bool Read(ref float value); | |
| /// <summary> | |
| /// Returns true if it was able to read a Double from the input | |
| /// </summary> | |
| protected abstract bool Read(ref double value); | |
| /// <summary> | |
| /// Returns true if it was able to read a String from the input | |
| /// </summary> | |
| protected abstract bool Read(ref string value); | |
| /// <summary> | |
| /// Returns true if it was able to read a ByteString from the input | |
| /// </summary> | |
| protected abstract bool Read(ref ByteString value); | |
| /// <summary> | |
| /// returns true if it was able to read a single value into the value reference. The value | |
| /// stored may be of type System.String, System.Int32, or an IEnumLite from the IEnumLiteMap. | |
| /// </summary> | |
| protected abstract bool ReadEnum(ref object value); | |
| /// <summary> | |
| /// Merges the input stream into the provided IBuilderLite | |
| /// </summary> | |
| protected abstract bool ReadMessage(IBuilderLite builder, ExtensionRegistry registry); | |
| /// <summary> | |
| /// Reads the root-message preamble specific to this formatter | |
| /// </summary> | |
| public abstract void ReadMessageStart(); | |
| /// <summary> | |
| /// Reads the root-message close specific to this formatter | |
| /// </summary> | |
| public abstract void ReadMessageEnd(); | |
| /// <summary> | |
| /// Merges the input stream into the provided IBuilderLite | |
| /// </summary> | |
| public virtual bool ReadGroup(IBuilderLite value, ExtensionRegistry registry) | |
| { | |
| return ReadMessage(value, registry); | |
| } | |
| /// <summary> | |
| /// Cursors through the array elements and stops at the end of the array | |
| /// </summary> | |
| protected virtual IEnumerable<string> ForeachArrayItem(string field) | |
| { | |
| string next = field; | |
| while (true) | |
| { | |
| yield return next; | |
| if (!PeekNext(out next) || next != field) | |
| { | |
| break; | |
| } | |
| } | |
| } | |
| /// <summary> | |
| /// Reads an array of T messages | |
| /// </summary> | |
| public virtual bool ReadMessageArray<T>(string field, ICollection<T> items, IMessageLite messageType, | |
| ExtensionRegistry registry) | |
| { | |
| bool success = false; | |
| foreach (string next in ForeachArrayItem(field)) | |
| { | |
| IBuilderLite builder = messageType.WeakCreateBuilderForType(); | |
| if (ReadMessage(builder, registry)) | |
| { | |
| items.Add((T) builder.WeakBuild()); | |
| success |= true; | |
| } | |
| } | |
| return success; | |
| } | |
| /// <summary> | |
| /// Reads an array of T messages as a proto-buffer group | |
| /// </summary> | |
| public virtual bool ReadGroupArray<T>(string field, ICollection<T> items, IMessageLite messageType, | |
| ExtensionRegistry registry) | |
| { | |
| bool success = false; | |
| foreach (string next in ForeachArrayItem(field)) | |
| { | |
| IBuilderLite builder = messageType.WeakCreateBuilderForType(); | |
| if (ReadGroup(builder, registry)) | |
| { | |
| items.Add((T) builder.WeakBuild()); | |
| success |= true; | |
| } | |
| } | |
| return success; | |
| } | |
| /// <summary> | |
| /// Reads an array of System.Enum type T and adds them to the collection | |
| /// </summary> | |
| public virtual bool ReadEnumArray(string field, ICollection<object> items) | |
| { | |
| bool success = false; | |
| foreach (string next in ForeachArrayItem(field)) | |
| { | |
| object temp = null; | |
| if (ReadEnum(ref temp)) | |
| { | |
| items.Add(temp); | |
| success |= true; | |
| } | |
| } | |
| return success; | |
| } | |
| /// <summary> | |
| /// Reads an array of T, where T is a primitive type defined by FieldType | |
| /// </summary> | |
| public virtual bool ReadArray<T>(FieldType type, string field, ICollection<T> items) | |
| { | |
| bool success = false; | |
| foreach (string next in ForeachArrayItem(field)) | |
| { | |
| object temp = null; | |
| if (ReadField(type, ref temp)) | |
| { | |
| items.Add((T) temp); | |
| success |= true; | |
| } | |
| } | |
| return success; | |
| } | |
| /// <summary> | |
| /// returns true if it was able to read a single primitive value of FieldType into the value reference | |
| /// </summary> | |
| public virtual bool ReadField(FieldType type, ref object value) | |
| { | |
| switch (type) | |
| { | |
| case FieldType.Bool: | |
| { | |
| bool temp = false; | |
| if (Read(ref temp)) | |
| { | |
| value = temp; | |
| } | |
| else | |
| { | |
| return false; | |
| } | |
| break; | |
| } | |
| case FieldType.Int64: | |
| case FieldType.SInt64: | |
| case FieldType.SFixed64: | |
| { | |
| long temp = 0; | |
| if (Read(ref temp)) | |
| { | |
| value = temp; | |
| } | |
| else | |
| { | |
| return false; | |
| } | |
| break; | |
| } | |
| case FieldType.UInt64: | |
| case FieldType.Fixed64: | |
| { | |
| ulong temp = 0; | |
| if (Read(ref temp)) | |
| { | |
| value = temp; | |
| } | |
| else | |
| { | |
| return false; | |
| } | |
| break; | |
| } | |
| case FieldType.Int32: | |
| case FieldType.SInt32: | |
| case FieldType.SFixed32: | |
| { | |
| int temp = 0; | |
| if (Read(ref temp)) | |
| { | |
| value = temp; | |
| } | |
| else | |
| { | |
| return false; | |
| } | |
| break; | |
| } | |
| case FieldType.UInt32: | |
| case FieldType.Fixed32: | |
| { | |
| uint temp = 0; | |
| if (Read(ref temp)) | |
| { | |
| value = temp; | |
| } | |
| else | |
| { | |
| return false; | |
| } | |
| break; | |
| } | |
| case FieldType.Float: | |
| { | |
| float temp = float.NaN; | |
| if (Read(ref temp)) | |
| { | |
| value = temp; | |
| } | |
| else | |
| { | |
| return false; | |
| } | |
| break; | |
| } | |
| case FieldType.Double: | |
| { | |
| double temp = float.NaN; | |
| if (Read(ref temp)) | |
| { | |
| value = temp; | |
| } | |
| else | |
| { | |
| return false; | |
| } | |
| break; | |
| } | |
| case FieldType.String: | |
| { | |
| string temp = null; | |
| if (Read(ref temp)) | |
| { | |
| value = temp; | |
| } | |
| else | |
| { | |
| return false; | |
| } | |
| break; | |
| } | |
| case FieldType.Bytes: | |
| { | |
| ByteString temp = null; | |
| if (Read(ref temp)) | |
| { | |
| value = temp; | |
| } | |
| else | |
| { | |
| return false; | |
| } | |
| break; | |
| } | |
| default: | |
| throw InvalidProtocolBufferException.InvalidTag(); | |
| } | |
| return true; | |
| } | |
| #region ICodedInputStream Members | |
| bool ICodedInputStream.ReadTag(out uint fieldTag, out string fieldName) | |
| { | |
| fieldTag = 0; | |
| if (PeekNext(out fieldName)) | |
| { | |
| return true; | |
| } | |
| return false; | |
| } | |
| bool ICodedInputStream.ReadDouble(ref double value) | |
| { | |
| return Read(ref value); | |
| } | |
| bool ICodedInputStream.ReadFloat(ref float value) | |
| { | |
| return Read(ref value); | |
| } | |
| bool ICodedInputStream.ReadUInt64(ref ulong value) | |
| { | |
| return Read(ref value); | |
| } | |
| bool ICodedInputStream.ReadInt64(ref long value) | |
| { | |
| return Read(ref value); | |
| } | |
| bool ICodedInputStream.ReadInt32(ref int value) | |
| { | |
| return Read(ref value); | |
| } | |
| bool ICodedInputStream.ReadFixed64(ref ulong value) | |
| { | |
| return Read(ref value); | |
| } | |
| bool ICodedInputStream.ReadFixed32(ref uint value) | |
| { | |
| return Read(ref value); | |
| } | |
| bool ICodedInputStream.ReadBool(ref bool value) | |
| { | |
| return Read(ref value); | |
| } | |
| bool ICodedInputStream.ReadString(ref string value) | |
| { | |
| return Read(ref value); | |
| } | |
| void ICodedInputStream.ReadGroup(int fieldNumber, IBuilderLite builder, ExtensionRegistry extensionRegistry) | |
| { | |
| if (_depth++ > MaxDepth) | |
| { | |
| throw new RecursionLimitExceededException(); | |
| } | |
| ReadGroup(builder, extensionRegistry); | |
| _depth--; | |
| } | |
| void ICodedInputStream.ReadUnknownGroup(int fieldNumber, IBuilderLite builder) | |
| { | |
| throw new NotSupportedException(); | |
| } | |
| void ICodedInputStream.ReadMessage(IBuilderLite builder, ExtensionRegistry extensionRegistry) | |
| { | |
| if (_depth++ > MaxDepth) | |
| { | |
| throw new RecursionLimitExceededException(); | |
| } | |
| ReadMessage(builder, extensionRegistry); | |
| _depth--; | |
| } | |
| bool ICodedInputStream.ReadBytes(ref ByteString value) | |
| { | |
| return Read(ref value); | |
| } | |
| bool ICodedInputStream.ReadUInt32(ref uint value) | |
| { | |
| return Read(ref value); | |
| } | |
| bool ICodedInputStream.ReadEnum(ref IEnumLite value, out object unknown, IEnumLiteMap mapping) | |
| { | |
| value = null; | |
| unknown = null; | |
| if (ReadEnum(ref unknown)) | |
| { | |
| if (unknown is int) | |
| { | |
| value = mapping.FindValueByNumber((int) unknown); | |
| } | |
| else if (unknown is string) | |
| { | |
| value = mapping.FindValueByName((string) unknown); | |
| } | |
| return value != null; | |
| } | |
| return false; | |
| } | |
| bool ICodedInputStream.ReadEnum<T>(ref T value, out object rawValue) | |
| { | |
| rawValue = null; | |
| if (ReadEnum(ref rawValue)) | |
| { | |
| if (!EnumParser<T>.TryConvert(rawValue, ref value)) | |
| { | |
| value = default(T); | |
| return false; | |
| } | |
| return true; | |
| } | |
| return false; | |
| } | |
| bool ICodedInputStream.ReadSFixed32(ref int value) | |
| { | |
| return Read(ref value); | |
| } | |
| bool ICodedInputStream.ReadSFixed64(ref long value) | |
| { | |
| return Read(ref value); | |
| } | |
| bool ICodedInputStream.ReadSInt32(ref int value) | |
| { | |
| return Read(ref value); | |
| } | |
| bool ICodedInputStream.ReadSInt64(ref long value) | |
| { | |
| return Read(ref value); | |
| } | |
| void ICodedInputStream.ReadPrimitiveArray(FieldType fieldType, uint fieldTag, string fieldName, | |
| ICollection<object> list) | |
| { | |
| ReadArray(fieldType, fieldName, list); | |
| } | |
| void ICodedInputStream.ReadEnumArray(uint fieldTag, string fieldName, ICollection<IEnumLite> list, | |
| out ICollection<object> unknown, IEnumLiteMap mapping) | |
| { | |
| unknown = null; | |
| List<object> array = new List<object>(); | |
| if (ReadEnumArray(fieldName, array)) | |
| { | |
| foreach (object rawValue in array) | |
| { | |
| IEnumLite item = null; | |
| if (rawValue is int) | |
| { | |
| item = mapping.FindValueByNumber((int) rawValue); | |
| } | |
| else if (rawValue is string) | |
| { | |
| item = mapping.FindValueByName((string) rawValue); | |
| } | |
| if (item != null) | |
| { | |
| list.Add(item); | |
| } | |
| else | |
| { | |
| if (unknown == null) | |
| { | |
| unknown = new List<object>(); | |
| } | |
| unknown.Add(rawValue); | |
| } | |
| } | |
| } | |
| } | |
| void ICodedInputStream.ReadEnumArray<T>(uint fieldTag, string fieldName, ICollection<T> list, | |
| out ICollection<object> unknown) | |
| { | |
| unknown = null; | |
| List<object> array = new List<object>(); | |
| if (ReadEnumArray(fieldName, array)) | |
| { | |
| foreach (object rawValue in array) | |
| { | |
| T val = default(T); | |
| if (EnumParser<T>.TryConvert(rawValue, ref val)) | |
| { | |
| list.Add(val); | |
| } | |
| else | |
| { | |
| if (unknown == null) | |
| { | |
| unknown = new List<object>(); | |
| } | |
| unknown.Add(rawValue); | |
| } | |
| } | |
| } | |
| } | |
| void ICodedInputStream.ReadMessageArray<T>(uint fieldTag, string fieldName, ICollection<T> list, T messageType, | |
| ExtensionRegistry registry) | |
| { | |
| if (_depth++ > MaxDepth) | |
| { | |
| throw new RecursionLimitExceededException(); | |
| } | |
| ReadMessageArray(fieldName, list, messageType, registry); | |
| _depth--; | |
| } | |
| void ICodedInputStream.ReadGroupArray<T>(uint fieldTag, string fieldName, ICollection<T> list, T messageType, | |
| ExtensionRegistry registry) | |
| { | |
| if (_depth++ > MaxDepth) | |
| { | |
| throw new RecursionLimitExceededException(); | |
| } | |
| ReadGroupArray(fieldName, list, messageType, registry); | |
| _depth--; | |
| } | |
| bool ICodedInputStream.ReadPrimitiveField(FieldType fieldType, ref object value) | |
| { | |
| return ReadField(fieldType, ref value); | |
| } | |
| bool ICodedInputStream.IsAtEnd | |
| { | |
| get | |
| { | |
| string next; | |
| return PeekNext(out next) == false; | |
| } | |
| } | |
| bool ICodedInputStream.SkipField() | |
| { | |
| Skip(); | |
| return true; | |
| } | |
| void ICodedInputStream.ReadStringArray(uint fieldTag, string fieldName, ICollection<string> list) | |
| { | |
| ReadArray(FieldType.String, fieldName, list); | |
| } | |
| void ICodedInputStream.ReadBytesArray(uint fieldTag, string fieldName, ICollection<ByteString> list) | |
| { | |
| ReadArray(FieldType.Bytes, fieldName, list); | |
| } | |
| void ICodedInputStream.ReadBoolArray(uint fieldTag, string fieldName, ICollection<bool> list) | |
| { | |
| ReadArray(FieldType.Bool, fieldName, list); | |
| } | |
| void ICodedInputStream.ReadInt32Array(uint fieldTag, string fieldName, ICollection<int> list) | |
| { | |
| ReadArray(FieldType.Int32, fieldName, list); | |
| } | |
| void ICodedInputStream.ReadSInt32Array(uint fieldTag, string fieldName, ICollection<int> list) | |
| { | |
| ReadArray(FieldType.SInt32, fieldName, list); | |
| } | |
| void ICodedInputStream.ReadUInt32Array(uint fieldTag, string fieldName, ICollection<uint> list) | |
| { | |
| ReadArray(FieldType.UInt32, fieldName, list); | |
| } | |
| void ICodedInputStream.ReadFixed32Array(uint fieldTag, string fieldName, ICollection<uint> list) | |
| { | |
| ReadArray(FieldType.Fixed32, fieldName, list); | |
| } | |
| void ICodedInputStream.ReadSFixed32Array(uint fieldTag, string fieldName, ICollection<int> list) | |
| { | |
| ReadArray(FieldType.SFixed32, fieldName, list); | |
| } | |
| void ICodedInputStream.ReadInt64Array(uint fieldTag, string fieldName, ICollection<long> list) | |
| { | |
| ReadArray(FieldType.Int64, fieldName, list); | |
| } | |
| void ICodedInputStream.ReadSInt64Array(uint fieldTag, string fieldName, ICollection<long> list) | |
| { | |
| ReadArray(FieldType.SInt64, fieldName, list); | |
| } | |
| void ICodedInputStream.ReadUInt64Array(uint fieldTag, string fieldName, ICollection<ulong> list) | |
| { | |
| ReadArray(FieldType.UInt64, fieldName, list); | |
| } | |
| void ICodedInputStream.ReadFixed64Array(uint fieldTag, string fieldName, ICollection<ulong> list) | |
| { | |
| ReadArray(FieldType.Fixed64, fieldName, list); | |
| } | |
| void ICodedInputStream.ReadSFixed64Array(uint fieldTag, string fieldName, ICollection<long> list) | |
| { | |
| ReadArray(FieldType.SFixed64, fieldName, list); | |
| } | |
| void ICodedInputStream.ReadDoubleArray(uint fieldTag, string fieldName, ICollection<double> list) | |
| { | |
| ReadArray(FieldType.Double, fieldName, list); | |
| } | |
| void ICodedInputStream.ReadFloatArray(uint fieldTag, string fieldName, ICollection<float> list) | |
| { | |
| ReadArray(FieldType.Float, fieldName, list); | |
| } | |
| #endregion | |
| } | |
| } |