File: System\Runtime\Serialization\XmlReaderDelegator.cs
Web Access
Project: src\src\libraries\System.Private.DataContractSerialization\src\System.Private.DataContractSerialization.csproj (System.Private.DataContractSerialization)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Runtime.Serialization.DataContracts;
using System.Xml;
using System.Xml.Serialization;
 
namespace System.Runtime.Serialization
{
    internal class XmlReaderDelegator
    {
        protected XmlReader reader;
        protected XmlDictionaryReader? dictionaryReader;
        protected bool isEndOfEmptyElement;
 
        public XmlReaderDelegator(XmlReader reader)
        {
            ArgumentNullException.ThrowIfNull(reader);
 
            this.reader = reader;
            this.dictionaryReader = reader as XmlDictionaryReader;
        }
 
        internal XmlReader UnderlyingReader
        {
            get { return reader; }
        }
 
        internal ExtensionDataReader? UnderlyingExtensionDataReader
        {
            get { return reader as ExtensionDataReader; }
        }
 
        internal int AttributeCount
        {
            get { return isEndOfEmptyElement ? 0 : reader.AttributeCount; }
        }
 
        internal string? GetAttribute(string name)
        {
            return isEndOfEmptyElement ? null : reader.GetAttribute(name);
        }
 
        internal string? GetAttribute(string name, string namespaceUri)
        {
            return isEndOfEmptyElement ? null : reader.GetAttribute(name, namespaceUri);
        }
 
        internal string GetAttribute(int i)
        {
            if (isEndOfEmptyElement)
                throw new ArgumentOutOfRangeException(nameof(i), SR.XmlElementAttributes);
            return reader.GetAttribute(i);
        }
 
        [SuppressMessage("Performance", "CA1822:Mark members as static", Justification = "Conceptually, this property describes this instance. Callers should expect to have an instance on hand to 'ask' about this 'emtpy' circumstance.")]
        internal bool IsEmptyElement
        {
            get { return false; }
        }
 
        internal bool IsNamespaceURI(string ns)
        {
            if (dictionaryReader == null)
                return ns == reader.NamespaceURI;
            else
                return dictionaryReader.IsNamespaceUri(ns);
        }
 
        internal bool IsLocalName(string localName)
        {
            if (dictionaryReader == null)
                return localName == reader.LocalName;
            else
                return dictionaryReader.IsLocalName(localName);
        }
 
        internal bool IsNamespaceUri(XmlDictionaryString ns)
        {
            if (dictionaryReader == null)
                return ns.Value == reader.NamespaceURI;
            else
                return dictionaryReader.IsNamespaceUri(ns);
        }
 
        internal bool IsLocalName(XmlDictionaryString localName)
        {
            if (dictionaryReader == null)
                return localName.Value == reader.LocalName;
            else
                return dictionaryReader.IsLocalName(localName);
        }
 
        internal int IndexOfLocalName(XmlDictionaryString[] localNames, XmlDictionaryString ns)
        {
            if (dictionaryReader != null)
                return dictionaryReader.IndexOfLocalName(localNames, ns);
 
            if (reader.NamespaceURI == ns.Value)
            {
                string localName = this.LocalName;
                for (int i = 0; i < localNames.Length; i++)
                {
                    if (localName == localNames[i].Value)
                    {
                        return i;
                    }
                }
            }
 
            return -1;
        }
 
        internal bool IsStartElement()
        {
            return !isEndOfEmptyElement && reader.IsStartElement();
        }
 
        internal bool IsStartElement(string localname, string ns)
        {
            return !isEndOfEmptyElement && reader.IsStartElement(localname, ns);
        }
 
        internal bool IsStartElement(XmlDictionaryString localname, XmlDictionaryString ns)
        {
            if (dictionaryReader == null)
                return !isEndOfEmptyElement && reader.IsStartElement(localname.Value, ns.Value);
            else
                return !isEndOfEmptyElement && dictionaryReader.IsStartElement(localname, ns);
        }
 
        internal bool MoveToAttribute(string name)
        {
            return isEndOfEmptyElement ? false : reader.MoveToAttribute(name);
        }
 
        internal bool MoveToAttribute(string name, string ns)
        {
            return isEndOfEmptyElement ? false : reader.MoveToAttribute(name, ns);
        }
 
        internal void MoveToAttribute(int i)
        {
            if (isEndOfEmptyElement)
                throw new ArgumentOutOfRangeException(nameof(i), SR.XmlElementAttributes);
            reader.MoveToAttribute(i);
        }
 
        internal bool MoveToElement()
        {
            return isEndOfEmptyElement ? false : reader.MoveToElement();
        }
 
        internal bool MoveToFirstAttribute()
        {
            return isEndOfEmptyElement ? false : reader.MoveToFirstAttribute();
        }
 
        internal bool MoveToNextAttribute()
        {
            return isEndOfEmptyElement ? false : reader.MoveToNextAttribute();
        }
 
        internal XmlNodeType NodeType
        {
            get { return isEndOfEmptyElement ? XmlNodeType.EndElement : reader.NodeType; }
        }
 
        internal bool Read()
        {
            //reader.MoveToFirstAttribute();
            //if (NodeType == XmlNodeType.Attribute)
            reader.MoveToElement();
            if (!reader.IsEmptyElement)
                return reader.Read();
            if (isEndOfEmptyElement)
            {
                isEndOfEmptyElement = false;
                return reader.Read();
            }
            isEndOfEmptyElement = true;
            return true;
        }
 
        internal XmlNodeType MoveToContent()
        {
            if (isEndOfEmptyElement)
                return XmlNodeType.EndElement;
 
            return reader.MoveToContent();
        }
 
        internal bool ReadAttributeValue()
        {
            return isEndOfEmptyElement ? false : reader.ReadAttributeValue();
        }
 
        internal void ReadEndElement()
        {
            if (isEndOfEmptyElement)
                Read();
            else
                reader.ReadEndElement();
        }
 
        private static InvalidDataContractException CreateInvalidPrimitiveTypeException(Type type)
        {
            return new InvalidDataContractException(SR.Format(
                type.IsInterface ? SR.InterfaceTypeCannotBeCreated : SR.InvalidPrimitiveType_Serialization,
                DataContract.GetClrTypeFullName(type)));
        }
 
        public object ReadElementContentAsAnyType(Type valueType)
        {
            Read();
            object o = ReadContentAsAnyType(valueType);
            ReadEndElement();
            return o;
        }
 
        internal object ReadContentAsAnyType(Type valueType)
        {
            switch (Type.GetTypeCode(valueType))
            {
                case TypeCode.Boolean:
                    return ReadContentAsBoolean();
                case TypeCode.Char:
                    return ReadContentAsChar();
                case TypeCode.Byte:
                    return ReadContentAsUnsignedByte();
                case TypeCode.Int16:
                    return ReadContentAsShort();
                case TypeCode.Int32:
                    return ReadContentAsInt();
                case TypeCode.Int64:
                    return ReadContentAsLong();
                case TypeCode.Single:
                    return ReadContentAsSingle();
                case TypeCode.Double:
                    return ReadContentAsDouble();
                case TypeCode.Decimal:
                    return ReadContentAsDecimal();
                case TypeCode.DateTime:
                    return ReadContentAsDateTime();
                case TypeCode.String:
                    return ReadContentAsString();
 
                case TypeCode.SByte:
                    return ReadContentAsSignedByte();
                case TypeCode.UInt16:
                    return ReadContentAsUnsignedShort();
                case TypeCode.UInt32:
                    return ReadContentAsUnsignedInt();
                case TypeCode.UInt64:
                    return ReadContentAsUnsignedLong();
                case TypeCode.Empty:
                case TypeCode.DBNull:
                case TypeCode.Object:
                default:
                    if (valueType == Globals.TypeOfByteArray)
                        return ReadContentAsBase64();
                    else if (valueType == Globals.TypeOfObject)
                        return new object();
                    else if (valueType == Globals.TypeOfTimeSpan)
                        return ReadContentAsTimeSpan();
                    else if (valueType == Globals.TypeOfGuid)
                        return ReadContentAsGuid();
                    else if (valueType == Globals.TypeOfUri)
                        return ReadContentAsUri();
                    else if (valueType == Globals.TypeOfXmlQualifiedName)
                        return ReadContentAsQName();
                    break;
            }
            throw CreateInvalidPrimitiveTypeException(valueType);
        }
 
        internal IDataNode ReadExtensionData(Type valueType)
        {
            switch (Type.GetTypeCode(valueType))
            {
                case TypeCode.Boolean:
                    return new DataNode<bool>(ReadContentAsBoolean());
                case TypeCode.Char:
                    return new DataNode<char>(ReadContentAsChar());
                case TypeCode.Byte:
                    return new DataNode<byte>(ReadContentAsUnsignedByte());
                case TypeCode.Int16:
                    return new DataNode<short>(ReadContentAsShort());
                case TypeCode.Int32:
                    return new DataNode<int>(ReadContentAsInt());
                case TypeCode.Int64:
                    return new DataNode<long>(ReadContentAsLong());
                case TypeCode.Single:
                    return new DataNode<float>(ReadContentAsSingle());
                case TypeCode.Double:
                    return new DataNode<double>(ReadContentAsDouble());
                case TypeCode.Decimal:
                    return new DataNode<decimal>(ReadContentAsDecimal());
                case TypeCode.DateTime:
                    return new DataNode<DateTime>(ReadContentAsDateTime());
                case TypeCode.String:
                    return new DataNode<string>(ReadContentAsString());
                case TypeCode.SByte:
                    return new DataNode<sbyte>(ReadContentAsSignedByte());
                case TypeCode.UInt16:
                    return new DataNode<ushort>(ReadContentAsUnsignedShort());
                case TypeCode.UInt32:
                    return new DataNode<uint>(ReadContentAsUnsignedInt());
                case TypeCode.UInt64:
                    return new DataNode<ulong>(ReadContentAsUnsignedLong());
                case TypeCode.Empty:
                case TypeCode.DBNull:
                case TypeCode.Object:
                default:
                    if (valueType == Globals.TypeOfByteArray)
                        return new DataNode<byte[]>(ReadContentAsBase64());
                    else if (valueType == Globals.TypeOfObject)
                        return new DataNode<object>(new object());
                    else if (valueType == Globals.TypeOfTimeSpan)
                        return new DataNode<TimeSpan>(ReadContentAsTimeSpan());
                    else if (valueType == Globals.TypeOfGuid)
                        return new DataNode<Guid>(ReadContentAsGuid());
                    else if (valueType == Globals.TypeOfUri)
                        return new DataNode<Uri>(ReadContentAsUri());
                    else if (valueType == Globals.TypeOfXmlQualifiedName)
                        return new DataNode<XmlQualifiedName>(ReadContentAsQName());
                    break;
            }
            throw CreateInvalidPrimitiveTypeException(valueType);
        }
 
        [DoesNotReturn]
        private void ThrowConversionException(string value, string type)
        {
            throw new XmlException(XmlObjectSerializer.TryAddLineInfo(this, SR.Format(SR.XmlInvalidConversion, value, type)));
        }
 
        [DoesNotReturn]
        private static void ThrowNotAtElement()
        {
            throw new XmlException(SR.Format(SR.XmlStartElementExpected, "EndElement"));
        }
 
        internal virtual char ReadElementContentAsChar()
        {
            return ToChar(ReadElementContentAsInt());
        }
 
        internal virtual char ReadContentAsChar()
        {
            return ToChar(ReadContentAsInt());
        }
 
        private char ToChar(int value)
        {
            if (value < char.MinValue || value > char.MaxValue)
            {
                ThrowConversionException(value.ToString(NumberFormatInfo.CurrentInfo), "Char");
            }
            return (char)value;
        }
 
        internal string ReadElementContentAsString()
        {
            if (isEndOfEmptyElement)
                ThrowNotAtElement();
 
            return reader.ReadElementContentAsString();
        }
 
        internal string ReadContentAsString()
        {
            return isEndOfEmptyElement ? string.Empty : reader.ReadContentAsString();
        }
 
        internal bool ReadElementContentAsBoolean()
        {
            if (isEndOfEmptyElement)
                ThrowNotAtElement();
 
            return reader.ReadElementContentAsBoolean();
        }
 
        internal bool ReadContentAsBoolean()
        {
            if (isEndOfEmptyElement)
                ThrowConversionException(string.Empty, "Boolean");
 
            return reader.ReadContentAsBoolean();
        }
 
        internal float ReadElementContentAsFloat()
        {
            if (isEndOfEmptyElement)
                ThrowNotAtElement();
 
            return reader.ReadElementContentAsFloat();
        }
 
        internal float ReadContentAsSingle()
        {
            if (isEndOfEmptyElement)
                ThrowConversionException(string.Empty, "Float");
 
            return reader.ReadContentAsFloat();
        }
 
        internal double ReadElementContentAsDouble()
        {
            if (isEndOfEmptyElement)
                ThrowNotAtElement();
 
            return reader.ReadElementContentAsDouble();
        }
 
        internal double ReadContentAsDouble()
        {
            if (isEndOfEmptyElement)
                ThrowConversionException(string.Empty, "Double");
 
            return reader.ReadContentAsDouble();
        }
 
        internal decimal ReadElementContentAsDecimal()
        {
            if (isEndOfEmptyElement)
                ThrowNotAtElement();
 
            return reader.ReadElementContentAsDecimal();
        }
 
        internal decimal ReadContentAsDecimal()
        {
            if (isEndOfEmptyElement)
                ThrowConversionException(string.Empty, "Decimal");
 
            return reader.ReadContentAsDecimal();
        }
 
        internal virtual byte[] ReadElementContentAsBase64()
        {
            if (isEndOfEmptyElement)
                ThrowNotAtElement();
 
            if (dictionaryReader == null)
            {
                return ReadContentAsBase64(reader.ReadElementContentAsString());
            }
            else
            {
                return dictionaryReader.ReadElementContentAsBase64();
            }
        }
 
        public virtual byte[] ReadContentAsBase64()
        {
            if (isEndOfEmptyElement)
                return Array.Empty<byte>();
 
            if (dictionaryReader == null)
            {
                return ReadContentAsBase64(reader.ReadContentAsString());
            }
            else
            {
                return dictionaryReader.ReadContentAsBase64();
            }
        }
 
        [return: NotNullIfNotNull(nameof(str))]
        internal static byte[]? ReadContentAsBase64(string? str)
        {
            if (str == null)
                return null;
            str = str.Trim();
            if (str.Length == 0)
                return Array.Empty<byte>();
 
            try
            {
                return Convert.FromBase64String(str);
            }
            catch (ArgumentException exception)
            {
                throw XmlExceptionHelper.CreateConversionException(str, "byte[]", exception);
            }
            catch (FormatException exception)
            {
                throw XmlExceptionHelper.CreateConversionException(str, "byte[]", exception);
            }
        }
 
        internal virtual DateTime ReadElementContentAsDateTime()
        {
            if (isEndOfEmptyElement)
                ThrowNotAtElement();
 
            return reader.ReadElementContentAsDateTime();
        }
 
        internal virtual DateTime ReadContentAsDateTime()
        {
            if (isEndOfEmptyElement)
                ThrowConversionException(string.Empty, "DateTime");
 
            return reader.ReadContentAsDateTime();
        }
 
        internal int ReadElementContentAsInt()
        {
            if (isEndOfEmptyElement)
                ThrowNotAtElement();
 
            return reader.ReadElementContentAsInt();
        }
 
        internal int ReadContentAsInt()
        {
            if (isEndOfEmptyElement)
                ThrowConversionException(string.Empty, "Int32");
 
            return reader.ReadContentAsInt();
        }
 
        internal long ReadElementContentAsLong()
        {
            if (isEndOfEmptyElement)
                ThrowNotAtElement();
 
            return reader.ReadElementContentAsLong();
        }
 
        internal long ReadContentAsLong()
        {
            if (isEndOfEmptyElement)
                ThrowConversionException(string.Empty, "Int64");
 
            return reader.ReadContentAsLong();
        }
 
        internal short ReadElementContentAsShort()
        {
            return ToShort(ReadElementContentAsInt());
        }
 
        internal short ReadContentAsShort()
        {
            return ToShort(ReadContentAsInt());
        }
 
        private short ToShort(int value)
        {
            if (value < short.MinValue || value > short.MaxValue)
            {
                ThrowConversionException(value.ToString(NumberFormatInfo.CurrentInfo), "Int16");
            }
            return (short)value;
        }
 
        internal byte ReadElementContentAsUnsignedByte()
        {
            return ToByte(ReadElementContentAsInt());
        }
 
        internal byte ReadContentAsUnsignedByte()
        {
            return ToByte(ReadContentAsInt());
        }
 
        private byte ToByte(int value)
        {
            if (value < byte.MinValue || value > byte.MaxValue)
            {
                ThrowConversionException(value.ToString(NumberFormatInfo.CurrentInfo), "Byte");
            }
            return (byte)value;
        }
 
        internal sbyte ReadElementContentAsSignedByte()
        {
            return ToSByte(ReadElementContentAsInt());
        }
 
        internal sbyte ReadContentAsSignedByte()
        {
            return ToSByte(ReadContentAsInt());
        }
 
        private sbyte ToSByte(int value)
        {
            if (value < sbyte.MinValue || value > sbyte.MaxValue)
            {
                ThrowConversionException(value.ToString(NumberFormatInfo.CurrentInfo), "SByte");
            }
            return (sbyte)value;
        }
 
        internal uint ReadElementContentAsUnsignedInt()
        {
            return ToUInt32(ReadElementContentAsLong());
        }
 
        internal uint ReadContentAsUnsignedInt()
        {
            return ToUInt32(ReadContentAsLong());
        }
 
        private uint ToUInt32(long value)
        {
            if (value < uint.MinValue || value > uint.MaxValue)
            {
                ThrowConversionException(value.ToString(NumberFormatInfo.CurrentInfo), "UInt32");
            }
            return (uint)value;
        }
 
        internal virtual ulong ReadElementContentAsUnsignedLong()
        {
            if (isEndOfEmptyElement)
                ThrowNotAtElement();
 
            string str = reader.ReadElementContentAsString();
 
            if (string.IsNullOrEmpty(str))
                ThrowConversionException(string.Empty, "UInt64");
 
            return XmlConverter.ToUInt64(str);
        }
 
        internal virtual ulong ReadContentAsUnsignedLong()
        {
            string str = reader.ReadContentAsString();
 
            if (string.IsNullOrEmpty(str))
                ThrowConversionException(string.Empty, "UInt64");
 
            return XmlConverter.ToUInt64(str);
        }
 
        internal ushort ReadElementContentAsUnsignedShort()
        {
            return ToUInt16(ReadElementContentAsInt());
        }
 
        internal ushort ReadContentAsUnsignedShort()
        {
            return ToUInt16(ReadContentAsInt());
        }
 
        private ushort ToUInt16(int value)
        {
            if (value < ushort.MinValue || value > ushort.MaxValue)
            {
                ThrowConversionException(value.ToString(NumberFormatInfo.CurrentInfo), "UInt16");
            }
            return (ushort)value;
        }
 
        internal TimeSpan ReadElementContentAsTimeSpan()
        {
            if (isEndOfEmptyElement)
                ThrowNotAtElement();
 
            string str = reader.ReadElementContentAsString();
            return XmlConverter.ToTimeSpan(str);
        }
 
        internal TimeSpan ReadContentAsTimeSpan()
        {
            string str = reader.ReadContentAsString();
            return XmlConverter.ToTimeSpan(str);
        }
 
        internal Guid ReadElementContentAsGuid()
        {
            if (isEndOfEmptyElement)
                ThrowNotAtElement();
 
            string str = reader.ReadElementContentAsString();
            try
            {
                return new Guid(str);
            }
            catch (ArgumentException exception)
            {
                throw XmlExceptionHelper.CreateConversionException(str, "Guid", exception);
            }
            catch (FormatException exception)
            {
                throw XmlExceptionHelper.CreateConversionException(str, "Guid", exception);
            }
            catch (OverflowException exception)
            {
                throw XmlExceptionHelper.CreateConversionException(str, "Guid", exception);
            }
        }
 
        internal Guid ReadContentAsGuid()
        {
            string str = reader.ReadContentAsString();
            try
            {
                return Guid.Parse(str);
            }
            catch (ArgumentException exception)
            {
                throw XmlExceptionHelper.CreateConversionException(str, "Guid", exception);
            }
            catch (FormatException exception)
            {
                throw XmlExceptionHelper.CreateConversionException(str, "Guid", exception);
            }
            catch (OverflowException exception)
            {
                throw XmlExceptionHelper.CreateConversionException(str, "Guid", exception);
            }
        }
 
        internal Uri ReadElementContentAsUri()
        {
            if (isEndOfEmptyElement)
                ThrowNotAtElement();
 
            string str = ReadElementContentAsString();
            try
            {
                return new Uri(str, UriKind.RelativeOrAbsolute);
            }
            catch (ArgumentException exception)
            {
                throw XmlExceptionHelper.CreateConversionException(str, "Uri", exception);
            }
            catch (FormatException exception)
            {
                throw XmlExceptionHelper.CreateConversionException(str, "Uri", exception);
            }
        }
 
        internal Uri ReadContentAsUri()
        {
            string str = ReadContentAsString();
            try
            {
                return new Uri(str, UriKind.RelativeOrAbsolute);
            }
            catch (ArgumentException exception)
            {
                throw XmlExceptionHelper.CreateConversionException(str, "Uri", exception);
            }
            catch (FormatException exception)
            {
                throw XmlExceptionHelper.CreateConversionException(str, "Uri", exception);
            }
        }
 
        internal XmlQualifiedName ReadElementContentAsQName()
        {
            Read();
            XmlQualifiedName obj = ReadContentAsQName();
            ReadEndElement();
            return obj;
        }
 
        internal virtual XmlQualifiedName ReadContentAsQName()
        {
            return ParseQualifiedName(ReadContentAsString());
        }
 
        private XmlQualifiedName ParseQualifiedName(string str)
        {
            string name;
            string? ns;
            if (string.IsNullOrEmpty(str))
                name = ns = string.Empty;
            else
                XmlObjectSerializerReadContext.ParseQualifiedName(str, this, out name, out ns, out _);
            return new XmlQualifiedName(name, ns);
        }
 
        private static void CheckExpectedArrayLength(XmlObjectSerializerReadContext context, int arrayLength)
        {
            context.IncrementItemCount(arrayLength);
        }
 
        protected int GetArrayLengthQuota(XmlObjectSerializerReadContext context)
        {
            if (dictionaryReader?.Quotas == null)
                return context.RemainingItemCount;
 
            return Math.Min(context.RemainingItemCount, dictionaryReader.Quotas.MaxArrayLength);
        }
 
        private static void CheckActualArrayLength(int expectedLength, int actualLength, XmlDictionaryString itemName, XmlDictionaryString itemNamespace)
        {
            if (expectedLength != actualLength)
                throw XmlObjectSerializer.CreateSerializationException(SR.Format(SR.ArrayExceededSizeAttribute, expectedLength, itemName.Value, itemNamespace.Value));
        }
 
        internal bool TryReadBooleanArray(XmlObjectSerializerReadContext context,
            XmlDictionaryString itemName, XmlDictionaryString itemNamespace,
            int arrayLength, [NotNullWhen(true)] out bool[]? array)
        {
            if (dictionaryReader == null)
            {
                array = null;
                return false;
            }
 
            if (arrayLength != -1)
            {
                CheckExpectedArrayLength(context, arrayLength);
                array = new bool[arrayLength];
                int read, offset = 0;
                while ((read = dictionaryReader.ReadArray(itemName, itemNamespace, array, offset, arrayLength - offset)) > 0)
                {
                    offset += read;
                }
                CheckActualArrayLength(arrayLength, offset, itemName, itemNamespace);
            }
            else
            {
                array = BooleanArrayHelperWithDictionaryString.Instance.ReadArray(
                    dictionaryReader, itemName, itemNamespace, GetArrayLengthQuota(context));
                context.IncrementItemCount(array.Length);
            }
            return true;
        }
 
        internal virtual bool TryReadDateTimeArray(XmlObjectSerializerReadContext context,
            XmlDictionaryString itemName, XmlDictionaryString itemNamespace,
            int arrayLength, [NotNullWhen(true)] out DateTime[]? array)
        {
            if (dictionaryReader == null)
            {
                array = null;
                return false;
            }
 
            if (arrayLength != -1)
            {
                CheckExpectedArrayLength(context, arrayLength);
                array = new DateTime[arrayLength];
                int read, offset = 0;
                while ((read = dictionaryReader.ReadArray(itemName, itemNamespace, array, offset, arrayLength - offset)) > 0)
                {
                    offset += read;
                }
                CheckActualArrayLength(arrayLength, offset, itemName, itemNamespace);
            }
            else
            {
                array = DateTimeArrayHelperWithDictionaryString.Instance.ReadArray(
                    dictionaryReader, itemName, itemNamespace, GetArrayLengthQuota(context));
                context.IncrementItemCount(array.Length);
            }
            return true;
        }
 
        internal bool TryReadDecimalArray(XmlObjectSerializerReadContext context,
            XmlDictionaryString itemName, XmlDictionaryString itemNamespace,
            int arrayLength, [NotNullWhen(true)] out decimal[]? array)
        {
            if (dictionaryReader == null)
            {
                array = null;
                return false;
            }
 
            if (arrayLength != -1)
            {
                CheckExpectedArrayLength(context, arrayLength);
                array = new decimal[arrayLength];
                int read, offset = 0;
                while ((read = dictionaryReader.ReadArray(itemName, itemNamespace, array, offset, arrayLength - offset)) > 0)
                {
                    offset += read;
                }
                CheckActualArrayLength(arrayLength, offset, itemName, itemNamespace);
            }
            else
            {
                array = DecimalArrayHelperWithDictionaryString.Instance.ReadArray(
                    dictionaryReader, itemName, itemNamespace, GetArrayLengthQuota(context));
                context.IncrementItemCount(array.Length);
            }
            return true;
        }
 
        internal bool TryReadInt32Array(XmlObjectSerializerReadContext context,
            XmlDictionaryString itemName, XmlDictionaryString itemNamespace,
            int arrayLength, [NotNullWhen(true)] out int[]? array)
        {
            if (dictionaryReader == null)
            {
                array = null;
                return false;
            }
 
            if (arrayLength != -1)
            {
                CheckExpectedArrayLength(context, arrayLength);
                array = new int[arrayLength];
                int read, offset = 0;
                while ((read = dictionaryReader.ReadArray(itemName, itemNamespace, array, offset, arrayLength - offset)) > 0)
                {
                    offset += read;
                }
                CheckActualArrayLength(arrayLength, offset, itemName, itemNamespace);
            }
            else
            {
                array = Int32ArrayHelperWithDictionaryString.Instance.ReadArray(
                    dictionaryReader, itemName, itemNamespace, GetArrayLengthQuota(context));
                context.IncrementItemCount(array.Length);
            }
            return true;
        }
 
        internal bool TryReadInt64Array(XmlObjectSerializerReadContext context,
            XmlDictionaryString itemName, XmlDictionaryString itemNamespace,
            int arrayLength, [NotNullWhen(true)] out long[]? array)
        {
            if (dictionaryReader == null)
            {
                array = null;
                return false;
            }
 
            if (arrayLength != -1)
            {
                CheckExpectedArrayLength(context, arrayLength);
                array = new long[arrayLength];
                int read, offset = 0;
                while ((read = dictionaryReader.ReadArray(itemName, itemNamespace, array, offset, arrayLength - offset)) > 0)
                {
                    offset += read;
                }
                CheckActualArrayLength(arrayLength, offset, itemName, itemNamespace);
            }
            else
            {
                array = Int64ArrayHelperWithDictionaryString.Instance.ReadArray(
                    dictionaryReader, itemName, itemNamespace, GetArrayLengthQuota(context));
                context.IncrementItemCount(array.Length);
            }
            return true;
        }
 
        internal bool TryReadSingleArray(XmlObjectSerializerReadContext context,
            XmlDictionaryString itemName, XmlDictionaryString itemNamespace,
            int arrayLength, [NotNullWhen(true)] out float[]? array)
        {
            if (dictionaryReader == null)
            {
                array = null;
                return false;
            }
 
            if (arrayLength != -1)
            {
                CheckExpectedArrayLength(context, arrayLength);
                array = new float[arrayLength];
                int read, offset = 0;
                while ((read = dictionaryReader.ReadArray(itemName, itemNamespace, array, offset, arrayLength - offset)) > 0)
                {
                    offset += read;
                }
                CheckActualArrayLength(arrayLength, offset, itemName, itemNamespace);
            }
            else
            {
                array = SingleArrayHelperWithDictionaryString.Instance.ReadArray(
                    dictionaryReader, itemName, itemNamespace, GetArrayLengthQuota(context));
                context.IncrementItemCount(array.Length);
            }
            return true;
        }
 
        internal bool TryReadDoubleArray(XmlObjectSerializerReadContext context,
            XmlDictionaryString itemName, XmlDictionaryString itemNamespace,
            int arrayLength, [NotNullWhen(true)] out double[]? array)
        {
            if (dictionaryReader == null)
            {
                array = null;
                return false;
            }
 
            if (arrayLength != -1)
            {
                CheckExpectedArrayLength(context, arrayLength);
                array = new double[arrayLength];
                int read, offset = 0;
                while ((read = dictionaryReader.ReadArray(itemName, itemNamespace, array, offset, arrayLength - offset)) > 0)
                {
                    offset += read;
                }
                CheckActualArrayLength(arrayLength, offset, itemName, itemNamespace);
            }
            else
            {
                array = DoubleArrayHelperWithDictionaryString.Instance.ReadArray(
                    dictionaryReader, itemName, itemNamespace, GetArrayLengthQuota(context));
                context.IncrementItemCount(array.Length);
            }
            return true;
        }
 
        internal IDictionary<string, string>? GetNamespacesInScope(XmlNamespaceScope scope)
        {
            return (reader is IXmlNamespaceResolver) ? ((IXmlNamespaceResolver)reader).GetNamespacesInScope(scope) : null;
        }
 
        // IXmlLineInfo members
        internal bool HasLineInfo()
        {
            IXmlLineInfo? iXmlLineInfo = reader as IXmlLineInfo;
            return (iXmlLineInfo == null) ? false : iXmlLineInfo.HasLineInfo();
        }
 
        internal int LineNumber
        {
            get
            {
                IXmlLineInfo? iXmlLineInfo = reader as IXmlLineInfo;
                return (iXmlLineInfo == null) ? 0 : iXmlLineInfo.LineNumber;
            }
        }
 
        internal int LinePosition
        {
            get
            {
                IXmlLineInfo? iXmlLineInfo = reader as IXmlLineInfo;
                return (iXmlLineInfo == null) ? 0 : iXmlLineInfo.LinePosition;
            }
        }
 
        // IXmlTextParser members
        internal bool Normalized
        {
            get
            {
                if (reader is not XmlTextReader xmlTextReader)
                {
                    IXmlTextParser? xmlTextParser = reader as IXmlTextParser;
                    return (xmlTextParser == null) ? false : xmlTextParser.Normalized;
                }
                else
                    return xmlTextReader.Normalization;
            }
            set
            {
                if (reader is not XmlTextReader xmlTextReader)
                {
                    if (reader is IXmlTextParser xmlTextParser)
                        xmlTextParser.Normalized = value;
                }
                else
                    xmlTextReader.Normalization = value;
            }
        }
 
        internal WhitespaceHandling WhitespaceHandling
        {
            get
            {
                if (reader is not XmlTextReader xmlTextReader)
                {
                    IXmlTextParser? xmlTextParser = reader as IXmlTextParser;
                    return (xmlTextParser == null) ? WhitespaceHandling.None : xmlTextParser.WhitespaceHandling;
                }
                else
                    return xmlTextReader.WhitespaceHandling;
            }
            set
            {
                if (reader is not XmlTextReader xmlTextReader)
                {
                    if (reader is IXmlTextParser xmlTextParser)
                        xmlTextParser.WhitespaceHandling = value;
                }
                else
                    xmlTextReader.WhitespaceHandling = value;
            }
        }
 
        // delegating properties and methods
        internal string Name { get { return reader.Name; } }
        internal string LocalName { get { return reader.LocalName; } }
        internal string NamespaceURI { get { return reader.NamespaceURI; } }
        internal string Value { get { return reader.Value; } }
        internal Type ValueType { get { return reader.ValueType; } }
        internal int Depth { get { return reader.Depth; } }
        internal string? LookupNamespace(string prefix) { return reader.LookupNamespace(prefix); }
        internal bool EOF { get { return reader.EOF; } }
 
        internal void Skip()
        {
            reader.Skip();
            isEndOfEmptyElement = false;
        }
    }
}