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 { /// /// Provides a base-class that provides some basic functionality for handling type dispatching /// public abstract class AbstractReader : ICodedInputStream { private const int DefaultMaxDepth = 64; private int _depth; /// Constructs a new reader protected AbstractReader() { MaxDepth = DefaultMaxDepth; } /// Gets or sets the maximum recursion depth allowed public int MaxDepth { get; set; } /// /// Merges the contents of stream into the provided message builder /// public TBuilder Merge(TBuilder builder) where TBuilder : IBuilderLite { return Merge(builder, ExtensionRegistry.Empty); } /// /// Merges the contents of stream into the provided message builder /// public abstract TBuilder Merge(TBuilder builder, ExtensionRegistry registry) where TBuilder : IBuilderLite; /// /// Peeks at the next field in the input stream and returns what information is available. /// /// /// 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. /// protected abstract bool PeekNext(out string field); /// /// Causes the reader to skip past this field /// protected abstract void Skip(); /// /// Returns true if it was able to read a Boolean from the input /// protected abstract bool Read(ref bool value); /// /// Returns true if it was able to read a Int32 from the input /// protected abstract bool Read(ref int value); /// /// Returns true if it was able to read a UInt32 from the input /// protected abstract bool Read(ref uint value); /// /// Returns true if it was able to read a Int64 from the input /// protected abstract bool Read(ref long value); /// /// Returns true if it was able to read a UInt64 from the input /// protected abstract bool Read(ref ulong value); /// /// Returns true if it was able to read a Single from the input /// protected abstract bool Read(ref float value); /// /// Returns true if it was able to read a Double from the input /// protected abstract bool Read(ref double value); /// /// Returns true if it was able to read a String from the input /// protected abstract bool Read(ref string value); /// /// Returns true if it was able to read a ByteString from the input /// protected abstract bool Read(ref ByteString value); /// /// 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. /// protected abstract bool ReadEnum(ref object value); /// /// Merges the input stream into the provided IBuilderLite /// protected abstract bool ReadMessage(IBuilderLite builder, ExtensionRegistry registry); /// /// Reads the root-message preamble specific to this formatter /// public abstract void ReadMessageStart(); /// /// Reads the root-message close specific to this formatter /// public abstract void ReadMessageEnd(); /// /// Merges the input stream into the provided IBuilderLite /// public virtual bool ReadGroup(IBuilderLite value, ExtensionRegistry registry) { return ReadMessage(value, registry); } /// /// Cursors through the array elements and stops at the end of the array /// protected virtual IEnumerable ForeachArrayItem(string field) { string next = field; while (true) { yield return next; if (!PeekNext(out next) || next != field) { break; } } } /// /// Reads an array of T messages /// public virtual bool ReadMessageArray(string field, ICollection 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; } /// /// Reads an array of T messages as a proto-buffer group /// public virtual bool ReadGroupArray(string field, ICollection 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; } /// /// Reads an array of System.Enum type T and adds them to the collection /// public virtual bool ReadEnumArray(string field, ICollection items) { bool success = false; foreach (string next in ForeachArrayItem(field)) { object temp = null; if (ReadEnum(ref temp)) { items.Add(temp); success |= true; } } return success; } /// /// Reads an array of T, where T is a primitive type defined by FieldType /// public virtual bool ReadArray(FieldType type, string field, ICollection 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; } /// /// returns true if it was able to read a single primitive value of FieldType into the value reference /// 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(ref T value, out object rawValue) { rawValue = null; if (ReadEnum(ref rawValue)) { if (!EnumParser.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 list) { ReadArray(fieldType, fieldName, list); } void ICodedInputStream.ReadEnumArray(uint fieldTag, string fieldName, ICollection list, out ICollection unknown, IEnumLiteMap mapping) { unknown = null; List array = new List(); 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(); } unknown.Add(rawValue); } } } } void ICodedInputStream.ReadEnumArray(uint fieldTag, string fieldName, ICollection list, out ICollection unknown) { unknown = null; List array = new List(); if (ReadEnumArray(fieldName, array)) { foreach (object rawValue in array) { T val = default(T); if (EnumParser.TryConvert(rawValue, ref val)) { list.Add(val); } else { if (unknown == null) { unknown = new List(); } unknown.Add(rawValue); } } } } void ICodedInputStream.ReadMessageArray(uint fieldTag, string fieldName, ICollection list, T messageType, ExtensionRegistry registry) { if (_depth++ > MaxDepth) { throw new RecursionLimitExceededException(); } ReadMessageArray(fieldName, list, messageType, registry); _depth--; } void ICodedInputStream.ReadGroupArray(uint fieldTag, string fieldName, ICollection 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 list) { ReadArray(FieldType.String, fieldName, list); } void ICodedInputStream.ReadBytesArray(uint fieldTag, string fieldName, ICollection list) { ReadArray(FieldType.Bytes, fieldName, list); } void ICodedInputStream.ReadBoolArray(uint fieldTag, string fieldName, ICollection list) { ReadArray(FieldType.Bool, fieldName, list); } void ICodedInputStream.ReadInt32Array(uint fieldTag, string fieldName, ICollection list) { ReadArray(FieldType.Int32, fieldName, list); } void ICodedInputStream.ReadSInt32Array(uint fieldTag, string fieldName, ICollection list) { ReadArray(FieldType.SInt32, fieldName, list); } void ICodedInputStream.ReadUInt32Array(uint fieldTag, string fieldName, ICollection list) { ReadArray(FieldType.UInt32, fieldName, list); } void ICodedInputStream.ReadFixed32Array(uint fieldTag, string fieldName, ICollection list) { ReadArray(FieldType.Fixed32, fieldName, list); } void ICodedInputStream.ReadSFixed32Array(uint fieldTag, string fieldName, ICollection list) { ReadArray(FieldType.SFixed32, fieldName, list); } void ICodedInputStream.ReadInt64Array(uint fieldTag, string fieldName, ICollection list) { ReadArray(FieldType.Int64, fieldName, list); } void ICodedInputStream.ReadSInt64Array(uint fieldTag, string fieldName, ICollection list) { ReadArray(FieldType.SInt64, fieldName, list); } void ICodedInputStream.ReadUInt64Array(uint fieldTag, string fieldName, ICollection list) { ReadArray(FieldType.UInt64, fieldName, list); } void ICodedInputStream.ReadFixed64Array(uint fieldTag, string fieldName, ICollection list) { ReadArray(FieldType.Fixed64, fieldName, list); } void ICodedInputStream.ReadSFixed64Array(uint fieldTag, string fieldName, ICollection list) { ReadArray(FieldType.SFixed64, fieldName, list); } void ICodedInputStream.ReadDoubleArray(uint fieldTag, string fieldName, ICollection list) { ReadArray(FieldType.Double, fieldName, list); } void ICodedInputStream.ReadFloatArray(uint fieldTag, string fieldName, ICollection list) { ReadArray(FieldType.Float, fieldName, list); } #endregion } }