File: FrameworkFork\System.Runtime.Serialization\System\Runtime\Serialization\ExtensionDataReader.cs
Web Access
Project: src\src\dotnet-svcutil\lib\src\dotnet-svcutil-lib.csproj (dotnet-svcutil-lib)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
using Microsoft.Xml;
using System.Collections.Generic;
using System.Security;
 
namespace System.Runtime.Serialization
{
    // NOTE: XmlReader methods that are not needed have been left un-implemented
 
    internal class ExtensionDataReader : XmlReader
    {
        private enum ExtensionDataNodeType
        {
            None,
            Element,
            EndElement,
            Text,
            Xml,
            ReferencedElement,
            NullElement,
        }
 
        private ElementData[] _elements;
        private ElementData _element;
        private ElementData _nextElement;
 
        private ReadState _readState = ReadState.Initial;
        private ExtensionDataNodeType _internalNodeType;
        private XmlNodeType _nodeType;
        private int _depth;
        private string _localName;
        private string _ns;
        private string _prefix;
        private string _value;
        private int _attributeCount;
        private int _attributeIndex;
 
#pragma warning disable 0649
        private XmlNodeReader _xmlNodeReader;
#pragma warning restore 0649
 
        private Queue<IDataNode> _deserializedDataNodes;
        private XmlObjectSerializerReadContext _context;
 
        [SecurityCritical]
        private static Dictionary<string, string> s_nsToPrefixTable;
 
        [SecurityCritical]
        private static Dictionary<string, string> s_prefixToNsTable;
 
        [SecurityCritical]
        static ExtensionDataReader()
        {
            s_nsToPrefixTable = new Dictionary<string, string>();
            s_prefixToNsTable = new Dictionary<string, string>();
            AddPrefix(Globals.XsiPrefix, Globals.SchemaInstanceNamespace);
            AddPrefix(Globals.SerPrefix, Globals.SerializationNamespace);
            AddPrefix(String.Empty, String.Empty);
        }
 
        internal ExtensionDataReader(XmlObjectSerializerReadContext context)
        {
            _attributeIndex = -1;
            _context = context;
        }
 
        internal void SetDeserializedValue(object obj)
        {
            IDataNode deserializedDataNode = (_deserializedDataNodes == null || _deserializedDataNodes.Count == 0) ? null : _deserializedDataNodes.Dequeue();
            if (deserializedDataNode != null && !(obj is IDataNode))
            {
                deserializedDataNode.Value = obj;
                deserializedDataNode.IsFinalValue = true;
            }
        }
 
        internal IDataNode GetCurrentNode()
        {
            IDataNode retVal = _element.dataNode;
            Skip();
            return retVal;
        }
 
        internal void SetDataNode(IDataNode dataNode, string name, string ns)
        {
            SetNextElement(dataNode, name, ns, null);
            _element = _nextElement;
            _nextElement = null;
            SetElement();
        }
 
        internal void Reset()
        {
            _localName = null;
            _ns = null;
            _prefix = null;
            _value = null;
            _attributeCount = 0;
            _attributeIndex = -1;
            _depth = 0;
            _element = null;
            _nextElement = null;
            _elements = null;
            _deserializedDataNodes = null;
        }
 
        private bool IsXmlDataNode { get { return (_internalNodeType == ExtensionDataNodeType.Xml); } }
 
        public override XmlNodeType NodeType { get { return IsXmlDataNode ? _xmlNodeReader.NodeType : _nodeType; } }
        public override string LocalName { get { return IsXmlDataNode ? _xmlNodeReader.LocalName : _localName; } }
        public override string NamespaceURI { get { return IsXmlDataNode ? _xmlNodeReader.NamespaceURI : _ns; } }
        public override string Prefix { get { return IsXmlDataNode ? _xmlNodeReader.Prefix : _prefix; } }
        public override string Value { get { return IsXmlDataNode ? _xmlNodeReader.Value : _value; } }
        public override int Depth { get { return IsXmlDataNode ? _xmlNodeReader.Depth : _depth; } }
        public override int AttributeCount { get { return IsXmlDataNode ? _xmlNodeReader.AttributeCount : _attributeCount; } }
        public override bool EOF { get { return IsXmlDataNode ? _xmlNodeReader.EOF : (_readState == ReadState.EndOfFile); } }
        public override ReadState ReadState { get { return IsXmlDataNode ? _xmlNodeReader.ReadState : _readState; } }
        public override bool IsEmptyElement { get { return IsXmlDataNode ? _xmlNodeReader.IsEmptyElement : false; } }
        public override bool IsDefault { get { return IsXmlDataNode ? _xmlNodeReader.IsDefault : base.IsDefault; } }
        //public override char QuoteChar { get { return IsXmlDataNode ? xmlNodeReader.QuoteChar : base.QuoteChar; } }
        public override XmlSpace XmlSpace { get { return IsXmlDataNode ? _xmlNodeReader.XmlSpace : base.XmlSpace; } }
        public override string XmlLang { get { return IsXmlDataNode ? _xmlNodeReader.XmlLang : base.XmlLang; } }
        public override string this[int i] { get { return IsXmlDataNode ? _xmlNodeReader[i] : GetAttribute(i); } }
        public override string this[string name] { get { return IsXmlDataNode ? _xmlNodeReader[name] : GetAttribute(name); } }
        public override string this[string name, string namespaceURI] { get { return IsXmlDataNode ? _xmlNodeReader[name, namespaceURI] : GetAttribute(name, namespaceURI); } }
 
        public override bool MoveToFirstAttribute()
        {
            if (IsXmlDataNode)
                return _xmlNodeReader.MoveToFirstAttribute();
 
            if (_attributeCount == 0)
                return false;
            MoveToAttribute(0);
            return true;
        }
 
        public override bool MoveToNextAttribute()
        {
            if (IsXmlDataNode)
                return _xmlNodeReader.MoveToNextAttribute();
 
            if (_attributeIndex + 1 >= _attributeCount)
                return false;
            MoveToAttribute(_attributeIndex + 1);
            return true;
        }
 
        public override void MoveToAttribute(int index)
        {
            if (IsXmlDataNode)
                _xmlNodeReader.MoveToAttribute(index);
            else
            {
                if (index < 0 || index >= _attributeCount)
                    throw new XmlException(SRSerialization.InvalidXmlDeserializingExtensionData);
 
                _nodeType = XmlNodeType.Attribute;
                AttributeData attribute = _element.attributes[index];
                _localName = attribute.localName;
                _ns = attribute.ns;
                _prefix = attribute.prefix;
                _value = attribute.value;
                _attributeIndex = index;
            }
        }
 
        public override string GetAttribute(string name, string namespaceURI)
        {
            if (IsXmlDataNode)
                return _xmlNodeReader.GetAttribute(name, namespaceURI);
 
            for (int i = 0; i < _element.attributeCount; i++)
            {
                AttributeData attribute = _element.attributes[i];
                if (attribute.localName == name && attribute.ns == namespaceURI)
                    return attribute.value;
            }
 
            return null;
        }
 
        public override bool MoveToAttribute(string name, string namespaceURI)
        {
            if (IsXmlDataNode)
                return _xmlNodeReader.MoveToAttribute(name, _ns);
 
            for (int i = 0; i < _element.attributeCount; i++)
            {
                AttributeData attribute = _element.attributes[i];
                if (attribute.localName == name && attribute.ns == namespaceURI)
                {
                    MoveToAttribute(i);
                    return true;
                }
            }
 
            return false;
        }
 
        public override bool MoveToElement()
        {
            if (IsXmlDataNode)
                return _xmlNodeReader.MoveToElement();
 
            if (_nodeType != XmlNodeType.Attribute)
                return false;
 
            SetElement();
            return true;
        }
 
        private void SetElement()
        {
            _nodeType = XmlNodeType.Element;
            _localName = _element.localName;
            _ns = _element.ns;
            _prefix = _element.prefix;
            _value = String.Empty;
            _attributeCount = _element.attributeCount;
            _attributeIndex = -1;
        }
 
        [SecuritySafeCritical]
        public override string LookupNamespace(string prefix)
        {
            if (IsXmlDataNode)
                return _xmlNodeReader.LookupNamespace(prefix);
 
            string ns;
            if (!s_prefixToNsTable.TryGetValue(prefix, out ns))
                return null;
            return ns;
        }
 
        public override void Skip()
        {
            if (IsXmlDataNode)
                _xmlNodeReader.Skip();
            else
            {
                if (ReadState != ReadState.Interactive)
                    return;
                MoveToElement();
                if (IsElementNode(_internalNodeType))
                {
                    int depth = 1;
                    while (depth != 0)
                    {
                        if (!Read())
                            throw new XmlException(SRSerialization.InvalidXmlDeserializingExtensionData);
 
                        if (IsElementNode(_internalNodeType))
                            depth++;
                        else if (_internalNodeType == ExtensionDataNodeType.EndElement)
                        {
                            ReadEndElement();
                            depth--;
                        }
                    }
                }
                else
                    Read();
            }
        }
 
        private bool IsElementNode(ExtensionDataNodeType nodeType)
        {
            return (nodeType == ExtensionDataNodeType.Element ||
                nodeType == ExtensionDataNodeType.ReferencedElement ||
                nodeType == ExtensionDataNodeType.NullElement);
        }
 
        protected override void Dispose(bool disposing)
        {
            if (IsXmlDataNode)
                _xmlNodeReader.Dispose();
            else
            {
                Reset();
                _readState = ReadState.Closed;
            }
 
            base.Dispose(disposing);
        }
 
        public override bool Read()
        {
            if (_nodeType == XmlNodeType.Attribute && MoveToNextAttribute())
                return true;
 
            MoveNext(_element.dataNode);
 
            switch (_internalNodeType)
            {
                case ExtensionDataNodeType.Element:
                case ExtensionDataNodeType.ReferencedElement:
                case ExtensionDataNodeType.NullElement:
                    PushElement();
                    SetElement();
                    break;
 
                case ExtensionDataNodeType.Text:
                    _nodeType = XmlNodeType.Text;
                    _prefix = String.Empty;
                    _ns = String.Empty;
                    _localName = String.Empty;
                    _attributeCount = 0;
                    _attributeIndex = -1;
                    break;
 
                case ExtensionDataNodeType.EndElement:
                    _nodeType = XmlNodeType.EndElement;
                    _prefix = String.Empty;
                    _ns = String.Empty;
                    _localName = String.Empty;
                    _value = String.Empty;
                    _attributeCount = 0;
                    _attributeIndex = -1;
                    PopElement();
                    break;
 
                case ExtensionDataNodeType.None:
                    if (_depth != 0)
                        throw new XmlException(SRSerialization.InvalidXmlDeserializingExtensionData);
                    _nodeType = XmlNodeType.None;
                    _prefix = String.Empty;
                    _ns = String.Empty;
                    _localName = String.Empty;
                    _value = String.Empty;
                    _attributeCount = 0;
                    _readState = ReadState.EndOfFile;
                    return false;
 
                case ExtensionDataNodeType.Xml:
                    // do nothing
                    break;
 
                default:
                    Fx.Assert("ExtensionDataReader in invalid state");
                    throw new SerializationException(SRSerialization.InvalidStateInExtensionDataReader);
            }
            _readState = ReadState.Interactive;
            return true;
        }
 
        public override string Name
        {
            get
            {
                if (IsXmlDataNode)
                {
                    return _xmlNodeReader.Name;
                }
                Fx.Assert("ExtensionDataReader Name property should only be called for IXmlSerializable");
                return string.Empty;
            }
        }
 
        public override bool HasValue
        {
            get
            {
                if (IsXmlDataNode)
                {
                    return _xmlNodeReader.HasValue;
                }
                Fx.Assert("ExtensionDataReader HasValue property should only be called for IXmlSerializable");
                return false;
            }
        }
 
        public override string BaseURI
        {
            get
            {
                if (IsXmlDataNode)
                {
                    return _xmlNodeReader.BaseURI;
                }
                Fx.Assert("ExtensionDataReader BaseURI property should only be called for IXmlSerializable");
                return string.Empty;
            }
        }
 
        public override XmlNameTable NameTable
        {
            get
            {
                if (IsXmlDataNode)
                {
                    return _xmlNodeReader.NameTable;
                }
                Fx.Assert("ExtensionDataReader NameTable property should only be called for IXmlSerializable");
                return null;
            }
        }
 
        public override string GetAttribute(string name)
        {
            if (IsXmlDataNode)
            {
                return _xmlNodeReader.GetAttribute(name);
            }
            Fx.Assert("ExtensionDataReader GetAttribute method should only be called for IXmlSerializable");
            return null;
        }
 
        public override string GetAttribute(int i)
        {
            if (IsXmlDataNode)
            {
                return _xmlNodeReader.GetAttribute(i);
            }
            Fx.Assert("ExtensionDataReader GetAttribute method should only be called for IXmlSerializable");
            return null;
        }
 
        public override bool MoveToAttribute(string name)
        {
            if (IsXmlDataNode)
            {
                return _xmlNodeReader.MoveToAttribute(name);
            }
            Fx.Assert("ExtensionDataReader MoveToAttribute method should only be called for IXmlSerializable");
            return false;
        }
 
        public override void ResolveEntity()
        {
            if (IsXmlDataNode)
            {
                _xmlNodeReader.ResolveEntity();
            }
            else
            {
                Fx.Assert("ExtensionDataReader ResolveEntity method should only be called for IXmlSerializable");
            }
        }
 
        public override bool ReadAttributeValue()
        {
            if (IsXmlDataNode)
            {
                return _xmlNodeReader.ReadAttributeValue();
            }
            Fx.Assert("ExtensionDataReader ReadAttributeValue method should only be called for IXmlSerializable");
            return false;
        }
 
        private void MoveNext(IDataNode dataNode)
        {
            throw NotImplemented.ByDesign;
        }
 
        private void SetNextElement(IDataNode node, string name, string ns, string prefix)
        {
            throw NotImplemented.ByDesign;
        }
 
        private void PushElement()
        {
            GrowElementsIfNeeded();
            _elements[_depth++] = _element;
            if (_nextElement == null)
                _element = GetNextElement();
            else
            {
                _element = _nextElement;
                _nextElement = null;
            }
        }
 
        private void PopElement()
        {
            _prefix = _element.prefix;
            _localName = _element.localName;
            _ns = _element.ns;
 
            if (_depth == 0)
                return;
 
            _depth--;
 
            if (_elements != null)
            {
                _element = _elements[_depth];
            }
        }
 
        private void GrowElementsIfNeeded()
        {
            if (_elements == null)
                _elements = new ElementData[8];
            else if (_elements.Length == _depth)
            {
                ElementData[] newElements = new ElementData[_elements.Length * 2];
                Array.Copy(_elements, 0, newElements, 0, _elements.Length);
                _elements = newElements;
            }
        }
 
        private ElementData GetNextElement()
        {
            int nextDepth = _depth + 1;
            return (_elements == null || _elements.Length <= nextDepth || _elements[nextDepth] == null)
                ? new ElementData() : _elements[nextDepth];
        }
 
        [SecuritySafeCritical]
        internal static string GetPrefix(string ns)
        {
            string prefix;
            ns = ns ?? String.Empty;
            if (!s_nsToPrefixTable.TryGetValue(ns, out prefix))
            {
                lock (s_nsToPrefixTable)
                {
                    if (!s_nsToPrefixTable.TryGetValue(ns, out prefix))
                    {
                        prefix = (ns == null || ns.Length == 0) ? String.Empty : "p" + s_nsToPrefixTable.Count;
                        AddPrefix(prefix, ns);
                    }
                }
            }
            return prefix;
        }
 
        [SecuritySafeCritical]
        private static void AddPrefix(string prefix, string ns)
        {
            s_nsToPrefixTable.Add(ns, prefix);
            s_prefixToNsTable.Add(prefix, ns);
        }
    }
 
#if USE_REFEMIT
    public class AttributeData
#else
    internal class AttributeData
#endif
    {
        public string prefix;
        public string ns;
        public string localName;
        public string value;
    }
 
#if USE_REFEMIT
    public class ElementData
#else
    internal class ElementData
#endif
    {
        public string localName;
        public string ns;
        public string prefix;
        public int attributeCount;
        public AttributeData[] attributes;
        public IDataNode dataNode;
        public int childElementIndex;
 
        public void AddAttribute(string prefix, string ns, string name, string value)
        {
            GrowAttributesIfNeeded();
            AttributeData attribute = attributes[attributeCount];
            if (attribute == null)
                attributes[attributeCount] = attribute = new AttributeData();
            attribute.prefix = prefix;
            attribute.ns = ns;
            attribute.localName = name;
            attribute.value = value;
            attributeCount++;
        }
 
        private void GrowAttributesIfNeeded()
        {
            if (attributes == null)
                attributes = new AttributeData[4];
            else if (attributes.Length == attributeCount)
            {
                AttributeData[] newAttributes = new AttributeData[attributes.Length * 2];
                Array.Copy(attributes, 0, newAttributes, 0, attributes.Length);
                attributes = newAttributes;
            }
        }
    }
}