aboutsummaryrefslogblamecommitdiff
path: root/src/ProtocolBuffers/Serialization/AbstractReader.cs
blob: 3aa54e8ffee8f59d71b69cc3bf69967e23602876 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
14













                                                                                                   
                                                                     
                             
 





























































































































































































































































































































                                                                                                                                          
          
                                    

                                                                               
                     
          




                                                                                                      
          
                                    

                                                                                
                     
          





































































































                                                                                                                                                                  
          
                                    

                                                                                
                     
          

                                                                                                                                                  
          
                                    

                                                                               
                     
          






























































                                                                                                             
using System;
using System.Collections.Generic;
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
    {
        const int MaxDepth = CodedInputStream.DefaultRecursionLimit;
        protected int Depth;

        /// <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>
        [CLSCompliant(false)]
        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>
        [CLSCompliant(false)]
        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>
        /// 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 InvalidProtocolBufferException.RecursionLimitExceeded();
            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 InvalidProtocolBufferException.RecursionLimitExceeded(); 
            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 (Enum.IsDefined(typeof(T), rawValue))
                {
                    if (rawValue is int)
                        value = (T)rawValue;
                    else if (rawValue is string)
                        value = (T)Enum.Parse(typeof(T), (string)rawValue, false);
                    else
                    {
                        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)
                {
                    if (rawValue is int)
                        list.Add((T)rawValue);
                    else if (rawValue is string)
                        list.Add((T)Enum.Parse(typeof(T), (string)rawValue, false));
                    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 InvalidProtocolBufferException.RecursionLimitExceeded(); 
            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 InvalidProtocolBufferException.RecursionLimitExceeded();
            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
    }
}