XmlCompatibilityReader.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / Orcas / QFE / wpf / src / Base / System / Windows / Markup / XmlCompatibilityReader.cs / 1 / XmlCompatibilityReader.cs

                            /****************************************************************************\ 
*
* File: XmlCompatibilityReaderr.cs
*
* Purpose: 
*
* History: 
*    5/11/05:    fmunoz        Created 
*    9/16/05:    oliverfo      Modified
*    9/16/05:    tjhsiang      Modified 
*
* Copyright (C) 2005 by Microsoft Corporation.  All rights reserved.
*
\***************************************************************************/ 

using System; 
using System.Xml; 
using System.Collections.Generic;
using System.Globalization; 
using System.Diagnostics;

#if SYSTEM_XAML
using System.Xaml; 
#endif
 
#if PBTCOMPILER 
using MS.Utility;
namespace MS.Internal.Markup 
#else
using MS.Internal.WindowsBase;
using System.Windows;
 
namespace System.Windows.Markup
#endif 
{ 
#if !PBTCOMPILER
    [FriendAccessAllowed] 
#endif

    // 
    // true if xmlNamespace is recognized 
    // 
    //  
    // the namespace to be checked 
    // 
    //  
    // if the passed in namespace is subsumed, then newXmlNamespace returns the subsuming namespace.
    // 
    internal delegate bool IsXmlNamespaceSupportedCallback(string xmlNamespace, out string newXmlNamespace);
    delegate void HandleElementCallback(int elementDepth, ref bool more); 
    delegate void HandleAttributeCallback(int elementDepth);
#if !PBTCOMPILER 
    [FriendAccessAllowed] 
#endif
    internal sealed class XmlCompatibilityReader: XmlWrappingReader 
    {
        #region Construction
        public XmlCompatibilityReader(XmlReader baseReader):base(baseReader)
        { 
            _compatibilityScope = new CompatibilityScope(null, -1, this);
 
            foreach (string xmlNamespace in _predefinedNamespaces) 
            {
                AddKnownNamespace(xmlNamespace); 
                _namespaceMap[xmlNamespace] = xmlNamespace;
                Reader.NameTable.Add(xmlNamespace);
            }
 
            _elementHandler.Add(AlternateContent, new HandleElementCallback(HandleAlternateContent));
            _elementHandler.Add(Choice, new HandleElementCallback(HandleChoice)); 
            _elementHandler.Add(Fallback, new HandleElementCallback(HandleFallback)); 

            _attributeHandler.Add(Ignorable, new HandleAttributeCallback(HandleIgnorable)); 
            _attributeHandler.Add(MustUnderstand, new HandleAttributeCallback(HandleMustUnderstand));
            _attributeHandler.Add(ProcessContent, new HandleAttributeCallback(HandleProcessContent));
            _attributeHandler.Add(PreserveElements, new HandleAttributeCallback(HandlePreserveElements));
            _attributeHandler.Add(PreserveAttributes, new HandleAttributeCallback(HandlePreserveAttributes)); 
        }
 
        public XmlCompatibilityReader(XmlReader baseReader, 
            IsXmlNamespaceSupportedCallback isXmlNamespaceSupported): this(baseReader)
        { 
            _namespaceCallback = isXmlNamespaceSupported;
        }

        public XmlCompatibilityReader(XmlReader baseReader, 
            IsXmlNamespaceSupportedCallback isXmlNamespaceSupported,
            IEnumerable supportedNamespaces):this(baseReader, isXmlNamespaceSupported) 
        { 
            foreach (string xmlNamespace in supportedNamespaces)
            { 
                AddKnownNamespace(xmlNamespace);
                _namespaceMap[xmlNamespace] = xmlNamespace;
            }
        } 

#if !PBTCOMPILER 
        public XmlCompatibilityReader(XmlReader baseReader, 
            IEnumerable supportedNamespaces):this(baseReader, null, supportedNamespaces)
        { 
        }
#endif
        #endregion Construction
 
        #region Public Methods
        ///  
        /// replaces all future references of namespace URI 'oldNamespace' with 'newNamespace' 
        /// 
        ///  
        /// the namespace to subsume with
        /// 
        /// 
        /// the namespace to be subsumed 
        /// 
        public void DeclareNamespaceCompatibility(string newNamespace, string oldNamespace) 
        { 
            if(newNamespace != oldNamespace)
            { 
                // indicate that newNamespace subsumes another namespace
                AddSubsumingNamespace(newNamespace);

                // If newNamespace is mapped to a namespace, 
                string tempNamespace;
                if (_namespaceMap.TryGetValue(newNamespace, out tempNamespace)) 
                { 
                    // If we have mapped newNamespace already get the newest name.
                    // We don't have to do this recursively because of the code below 
                    // ensures the map always refers to the newest namespace.
                    newNamespace = tempNamespace;
                }
 
                if(IsSubsumingNamespace(oldNamespace))
                { 
                    // if we are mapping what was used as a new namespace to a newer name, 
                    // scan the _newNamespaces dictionary and update the entries. We collect
                    // a list to avoid updating the dictonary during enumeration. 
                    List keysToUpdate = new List();

                    foreach (KeyValuePair pair in _namespaceMap)
                    { 
                        if (pair.Value == oldNamespace)
                        { 
                            keysToUpdate.Add(pair.Key); 
                        }
                    } 

                    foreach (string key in keysToUpdate)
                    {
                        _namespaceMap[key] = newNamespace; 
                    }
                } 
            } 

            _namespaceMap[oldNamespace] = newNamespace; 
        }

        /// 
        /// Reads the next node from the stream. 
        /// 
        ///  
        /// true if the next node was read successfully; false if there are no more nodes to read. 
        /// 
        public override bool Read() 
        {
            bool more = Reader.Read(); //passed as ref arg to ReadStartElement and ReadEndElement
            bool result = false;
 
            while (more)
            { 
                switch (Reader.NodeType) 
                {
                    case XmlNodeType.Element: 
                    {
                        // if the element read should be ignored, read the next element
                        if(!ReadStartElement(ref more))
                        { 
                            continue;
                        } 
                        break; 
                    }
                    case XmlNodeType.EndElement: 
                    {
                        // if the element read should be ignored, read the next element
                        if(!ReadEndElement(ref more))
                        { 
                            continue;
                        } 
                        break; 
                    }
                } 

                // if the element was read successfully and was not ignored, break and return true
                result = true;
                break; 
            }
 
            return result; 
        }
 
        /// 
        /// Used to handle 'start element' tags.  These are actually
        /// just called 'element' tags, the 'start' is just for clarity
        ///  
        /// 
        /// is set to true if there is the document contains more elements, false if the end of the 
        /// document has been reached. 
        /// 
        ///  
        /// true if an element was read that should not be ignored
        /// false if the element read should be ignored or the end of document has been reached
        /// 
        private bool ReadStartElement(ref bool more) 
        {
            // when processing elements, the Reader may advance to another element or attribute, 
            // so we save the values of the current element here 
            int elementDepth = Reader.Depth;
            int depthOffset = _depthOffset; 
            bool isEmpty = Reader.IsEmptyElement;
            string namespaceName = NamespaceURI;
            bool result = false;
 
            if (object.ReferenceEquals(namespaceName, CompatibilityUri))
            { 
                // if the element is a markup-compatibility element, we get the appropriate handler for 
                // the element type, and call the appropriate delegate.  If the element is not recognized
                // we throw an exception. 
                string elementName = Reader.LocalName;
                HandleElementCallback elementCB;
                if(!_elementHandler.TryGetValue(elementName, out elementCB))
                { 
                    Error(SR.Get(SRID.XCRUnknownCompatElement), elementName);
                } 
                elementCB(elementDepth, ref more); 
            }
            // handle non-markup-compatibility elements 
            else
            {
                // check for markup-compatibility attributes and namespaces that should be ignored
                ScanForCompatibility(elementDepth); 

                if (ShouldIgnoreNamespace(namespaceName)) 
                { 
                    if(Scope.ShouldProcessContent(namespaceName, Reader.LocalName))
                    { 
                        // if the current element is unknown and has been marked Ignorable and ProcessContent,
                        // then read the next element, and increase depth offset
                        if(Scope.Depth == elementDepth)
                        { 
                            // if the current element pushed a scope, mark the scope as InProcessContent to
                            // note that for certain logic this scope's parent should be checked 
                            Scope.InProcessContent = true; 
                        }
                        _depthOffset++; 
                        more = Reader.Read();
                    }
                    else
                    { 
                        // if element should be ignored but not processed, check to see if scope must be popped,
                        // then skip to the next element after the end tag of the current element 
                        ScanForEndCompatibility(elementDepth); 
                        Reader.Skip();
                    } 
                }
                else
                {
                    if (Scope.InAlternateContent) 
                    {
                        // if this element is the child of an AlternateContent element, then throw an exception. 
                        Error(SR.Get(SRID.XCRInvalidACChild), Reader.Name); 
                    }
 
                    result = true;
                }
            }
 
            // if the element is empty (e.g. "" and we pushed a scope then get
            // rid of the scope 
            if(isEmpty) 
            {
                ScanForEndCompatibility(elementDepth); 
                _depthOffset = depthOffset;
            }

            return result; 
        }
 
 
        /// 
        /// Used to handle any end element tag 
        /// 
        /// 
        /// is set to true if there is the document contains more elements, false if the end of the
        /// document has been reached. 
        /// 
        ///  
        /// true if an element was read that should not be ignored 
        /// false if the element read should be ignored or the end of document has been reached
        ///  
        private bool ReadEndElement(ref bool more)
        {
            // when reading attributes, the reader's depth increases, so for consistency
            // we store the depth before reading any attributes 
            int elementDepth = Reader.Depth;
            string namespaceName = NamespaceURI; 
            bool result = false;  // return value 

            if (object.ReferenceEquals(namespaceName, CompatibilityUri)) 
            {
                // if the element is a markup-compatibility element, pop a scope, decrement the
                // depth offset and read the next element.
                string elementName = Reader.LocalName; 
                if (object.ReferenceEquals(elementName, AlternateContent))
                { 
                    if (!Scope.ChoiceSeen) 
                    {
                        // if the current element was a , without any Choice 
                        // element children, throw an exception
                        Error(SR.Get(SRID.XCRChoiceNotFound));
                    }
                } 
                _depthOffset--;
                PopScope();  //we know we can pop, so no need to scan 
                more = Reader.Read(); 
            }
            else 
            {
                if (ShouldIgnoreNamespace(namespaceName))
                {
                    // if current element is Ignorable, then to be on it, it must have been marked 
                    // ProcessContent.  Pop a scope if the corresponding start element pushed a scope a
                    // scope, decrement the depth offset and read the next element. 
                    Debug.Assert(Scope.ShouldProcessContent(namespaceName, Reader.LocalName)); 
                    ScanForEndCompatibility(elementDepth);
                    _depthOffset--; 
                    more = Reader.Read();
                }
                else
                { 
                    ScanForEndCompatibility(elementDepth);
                    result = true; 
                } 
            }
 
            return result;
        }

        ///  
        /// Gets the value of the attribute with the specified index.
        ///  
        ///  
        /// The index of the attribute. The index is zero-based. (The first attribute has index 0.)
        ///  
        /// 
        /// The value of the specified attribute. If the attribute is not found, a null reference is returned.
        /// 
        public override string GetAttribute(int i) 
        {
            string result = null; 
 
            if (_ignoredAttributeCount == 0)
            { 
                // if the current element should not ignored any of its attributes, skip extra logic
                result = Reader.GetAttribute(i);
            }
            else 
            {
                SaveReaderPosition(); 
 
                // move to 'i'th attribute, get its value
                MoveToAttribute(i); 
                result = Reader.Value;

                RestoreReaderPosition();
            } 

            return result; 
        } 

        ///  
        /// Gets the value of the attribute with the specified name.
        /// 
        /// 
        /// The qualified name of the attribute. 
        /// 
        ///  
        /// The value of the specified attribute. If the attribute is not found, a null reference is returned. 
        /// 
        public override string GetAttribute(string name) 
        {
            string result = null;

            if (_ignoredAttributeCount == 0) 
            {
                // if the current element should not ignored any attributes, call Reader method 
                result = Reader.GetAttribute(name); 
            }
            else 
            {
                SaveReaderPosition();

                // move to "name" attribute 
                if (MoveToAttribute(name))
                { 
                    result = Reader.Value; 
                    RestoreReaderPosition();
                } 
            }

            return result;
        } 

        ///  
        /// Gets the value of the attribute with the specified local name and namespace URI. 
        /// 
        ///  
        /// The local name of the attribute.
        /// 
        /// 
        /// The namespace URI of the attribute. 
        /// 
        ///  
        /// The value of the specified attribute. If the attribute is not found, a null reference is returned. 
        /// 
        public override string GetAttribute(string localName, string namespaceURI) 
        {
            string result = null;

            if (_ignoredAttributeCount == 0 || !ShouldIgnoreNamespace(namespaceURI) ) 
            {
                // if the current element does not have any attributes that should be ignored or 
                // the namespace provided is not ignorable, call Reader method 
                result = Reader.GetAttribute(localName, namespaceURI);
            } 

            return result;
        }
 
        /// 
        /// Gets the value of the attribute with the specified index. 
        ///  
        /// 
        /// The index of the attribute. The index is zero-based. (The first attribute has index 0.) 
        /// 
        /// 
        /// true if the attribute is found; otherwise, false. If false, the reader's position does not change.
        ///  
        public override void MoveToAttribute(int i)
        { 
            if (_ignoredAttributeCount == 0) 
            {
                // if the current element should not ignored any attributes, call Reader method 
                Reader.MoveToAttribute(i);
            }
            else if (i < 0 || i >= AttributeCount)
            { 
                throw new ArgumentOutOfRangeException("i");
            } 
            else 
            {
                // move Reader to first attribute and iterate until 'i'th element found 
                Reader.MoveToFirstAttribute();

                while (true)
                { 
                    if (!ShouldIgnoreNamespace(NamespaceURI))
                    { 
                        // if attribute should not be ignored, decrement 'i', if i == 0 we've found element 
                        if (i-- == 0)
                        { 
                            break;
                        }
                    }
 
                    Reader.MoveToNextAttribute();
                } 
            } 
        }
 
        /// 
        /// Moves to the attribute with the specified name.
        /// 
        ///  
        /// The qualified name of the attribute.
        ///  
        ///  
        /// true if the attribute is found; otherwise, false. If false, the reader's position does not change.
        ///  
        public override bool MoveToAttribute(string name)
        {
            bool result;
 
            if (_ignoredAttributeCount == 0)
            { 
                // if the current element should not ignored any attributes, call Reader method 
                result = Reader.MoveToAttribute(name);
            } 
            else
            {
                SaveReaderPosition();
 
                result = Reader.MoveToAttribute(name);
                if (result && ShouldIgnoreNamespace(NamespaceURI)) 
                { 
                    // if attribute should be ignored, return false and restore state
                    result = false; 
                    RestoreReaderPosition();
                }
            }
 
            return result;
        } 
 
        /// 
        /// Moves to the attribute with the specified local name and namespace URI. 
        /// 
        /// 
        /// The local name of the attribute.
        ///  
        /// 
        /// The namespace URI of the attribute. 
        ///  
        /// 
        /// true if the attribute is found; otherwise, false. If false, the reader's position does not change. 
        /// 
        public override bool MoveToAttribute(string localName, string namespaceURI)
        {
            bool result; 

            if (_ignoredAttributeCount == 0) 
            { 
                // if the current element should not ignored any attributes, call Reader method
                result = Reader.MoveToAttribute(localName, namespaceURI); 
            }
            else
            {
                SaveReaderPosition(); 

                result = Reader.MoveToAttribute(localName, namespaceURI); 
 
                if (result && ShouldIgnoreNamespace(namespaceURI))
                { 
                    result = false;
                    RestoreReaderPosition();
                }
            } 
            return result;
        } 
 
        /// 
        /// Moves to the first attribute. 
        /// 
        /// 
        /// true if an attribute exists (the reader moves to the first attribute);
        /// otherwise, false (the position of the reader does not change). 
        /// 
        public override bool MoveToFirstAttribute() 
        { 
            bool result = HasAttributes;
 
            if(result)
            {
                MoveToAttribute(0);
            } 

            return result; 
        } 

        ///  
        /// Moves to the next attribute.
        /// 
        /// 
        /// true if there is a next attribute; false if there are no more attributes. 
        /// 
        public override bool MoveToNextAttribute() 
        { 
            bool result;
 
            if (_ignoredAttributeCount == 0)
            {
                // if the current element should not ignored any attributes, call Reader method
                result = Reader.MoveToNextAttribute(); 
            }
            else 
            { 
                SaveReaderPosition();
 
                result = Reader.MoveToNextAttribute();

                if (result)
                { 
                    result = SkipToKnownAttribute();
 
                    if (!result) 
                    {
                        // if no more attributes exist that should not be ignored, return false and restore state 
                        RestoreReaderPosition();
                    }
                }
            } 

            return result; 
        } 

        ///  
        /// Resolves a namespace prefix in the current element's scope.
        /// 
        /// 
        /// The prefix whose namespace URI you want to resolve. To match the default namespace, 
        /// pass an empty string. This string does not have to be atomized.
        ///  
        ///  
        /// The namespace URI to which the prefix maps or a null reference if no matching prefix is found.
        ///  
        public override string LookupNamespace (string prefix)
        {
            string namespaceName = Reader.LookupNamespace(prefix);
 
            if (namespaceName != null)
            { 
                namespaceName = GetMappedNamespace(namespaceName); 
            }
 
            return namespaceName;
        }

        #endregion Public Methods 

        #region Public Properties 
 
        /// 
        /// This override is to ensure that the value 
        /// for the xmlns attribute reflects all the
        /// compatibility (subsuming) rules.
        /// 
        public override string Value 
        {
            get 
            { 
                // Look for xmlns
                if (String.Equals(XmlnsDeclaration, Reader.LocalName, StringComparison.Ordinal)) 
                {
                    return LookupNamespace(String.Empty);
                }
                // Look for xmlns: ... 
                else if (String.Equals(XmlnsDeclaration, Reader.Prefix, StringComparison.Ordinal))
                { 
                    return LookupNamespace(Reader.LocalName); 
                }
 
                return Reader.Value;
            }
        }
 
        /// 
        /// Gets the namespace URI (as defined in the W3C Namespace specification) of the node 
        /// on which the reader is positioned. 
        /// 
        public override string NamespaceURI 
        {
            get
            {
                return GetMappedNamespace(Reader.NamespaceURI); 
            }
        } 
 
        /// 
        /// Gets the depth of the current node in the XML document. 
        /// 
        public override int Depth
        {
            get 
            {
                return Reader.Depth - _depthOffset; 
            } 
        }
 
        /// 
        /// Gets a value indicating whether the current node has any attributes
        /// 
        public override bool HasAttributes 
        {
            get 
            { 
                return AttributeCount != 0;
            } 
        }

        /// 
        /// Gets the number of attributes on the current node. 
        /// 
        public override int AttributeCount 
        { 
            get
            { 
                return Reader.AttributeCount - _ignoredAttributeCount;
            }
        }
 
        /// 
        /// Sets a value indicating whether to normalize white space and attribute values. 
        ///  
        public bool Normalization
        { 
            set
            {
                XmlTextReader xmlTextReader = Reader as XmlTextReader;
 
                // review, what if not the XmlTextReader.
                if (null != xmlTextReader) 
                { 
                    xmlTextReader.Normalization = value;
                } 
            }
        }

#if !PBTCOMPILER 
        /// 
        /// Answer the encoding of the underlying xaml stream 
        ///  
        internal System.Text.Encoding Encoding
        { 
            get
            {
                XmlTextReader textReader = Reader as XmlTextReader;
                if (textReader == null) 
                {
                    return new System.Text.UTF8Encoding(true,true); 
                } 
                else
                { 
                    return textReader.Encoding;
                }
            }
        } 
#endif
        #endregion Public Properties 
 
        #region Private Methods
 
        private void SaveReaderPosition()
        {
            // Save current state so we can go back to the same spot if this fails
            _inAttribute = (Reader.NodeType == XmlNodeType.Attribute); 
            _currentName = Reader.Name;
        } 
 
        private void RestoreReaderPosition()
        { 
            // Restore reader state from SaveReaderPosition
            if (_inAttribute)
            {
                Reader.MoveToAttribute(_currentName); 
            }
            else 
            { 
                Reader.MoveToElement();
            } 
        }

        /// 
        /// Retrieves the correctly mapped namespace from the namespace provided 
        /// 
        ///  
        /// The name of the namespace to retrieve the mapping of 
        /// 
        ///  
        /// The name of the mapped namespace.
        /// 
        private string GetMappedNamespace(string namespaceName)
        { 
            string mappedNamespace;
 
            // if the namespace is not null, get the mapped namespace (which may be itself) 
            if (!_namespaceMap.TryGetValue(namespaceName, out mappedNamespace))
            { 
                // if the namespace has not yet been mapped, map it
                mappedNamespace = MapNewNamespace(namespaceName);
            }
            else if (mappedNamespace == null) 
            {
                // if the mapped namespace is null, then the namespace was not supported, just return 
                // the given namespace 
                mappedNamespace = namespaceName;
            } 

            return mappedNamespace;
        }
 
        /// 
        /// Adds the namespace to the namespace map.  The default is to map the namespace to itself. 
        /// The namespace is mapped to the value returned by the callback, if a callback exists and the 
        /// callback returns a subsuming namespace.
        ///  
        /// 
        /// The name of the namespace to be mapped.
        /// 
        ///  
        /// The name of the mapped namespace.
        ///  
        private string MapNewNamespace(string namespaceName) 
        {
            if (_namespaceCallback != null) 
            {
                string mappedNamespace;

                // the callback returns whether the namespace is supported, and mappedNamespace is the 
                // namespace subsuming the namespace passed in.
                bool isSupported = _namespaceCallback(namespaceName, out mappedNamespace); 
 
                if (isSupported)
                { 
                    AddKnownNamespace(namespaceName);

                    if(String.IsNullOrEmpty(mappedNamespace) || namespaceName == mappedNamespace)
                    { 
                        _namespaceMap[namespaceName] = namespaceName;
                    } 
                    else 
                    {
                        // subsume namespace with mappedNamespace. 
                        string tempNamespace;

                        if (!_namespaceMap.TryGetValue(mappedNamespace, out tempNamespace))
                        { 
                            // mappedNamespace has not been mapped, so map it
                            tempNamespace = MapNewNamespace(mappedNamespace); 
                        } 

                        DeclareNamespaceCompatibility(tempNamespace, namespaceName); 
                        namespaceName = tempNamespace;
                    }
                }
                else 
                {
                    // if the namespace is not supported, we enter null into the namespaceMap as a placeholder 
                    // so that we do not call the callback again on this namespace. 
                    _namespaceMap[namespaceName] = null;
                } 
            }

            return namespaceName;
        } 

        ///  
        /// Used to determine whether a given namespace subsumes another namespace 
        /// 
        ///  
        /// The name of the namespace to be checked.
        /// 
        /// 
        /// true if the namespace subsumes another namespace; false otherwise 
        /// 
        private bool IsSubsumingNamespace(string namespaceName) 
        { 
            return _subsumingNamespaces.ContainsKey(namespaceName);
        } 

        /// 
        /// Used to specify that a namespace subsumes another namespace
        ///  
        /// 
        /// The name of the namespace to be added. 
        ///  
        private void AddSubsumingNamespace(string namespaceName)
        { 
            _subsumingNamespaces[namespaceName] = null;
        }

        ///  
        /// Used to determine whether a given namespace is known/supported
        ///  
        ///  
        /// The name of the namespace to be checked.
        ///  
        /// 
        /// true if the namespace is known/supported; false otherwise
        /// 
        private bool IsNamespaceKnown(string namespaceName) 
        {
            return _knownNamespaces.ContainsKey(namespaceName); 
        } 

        ///  
        /// Used to specify that a namespace is known or supported
        /// 
        /// 
        /// The name of the namespace to be added. 
        /// 
        private void AddKnownNamespace(string namespaceName) 
        { 
            _knownNamespaces[namespaceName] = null;
        } 

        /// 
        /// Used to determine whether a given namespace should be ignored.  A namespace should be ignored if:
        /// EITHER 
        /// a) the namespace is not known/supported and has been marked Ignorable
        /// OR 
        /// b) the namespace is the markup-compatibility namespace 
        /// 
        ///  
        /// The name of the prefix to be checked.
        /// 
        /// 
        /// true if the namespace should be ignored; false otherwise 
        /// 
        private bool ShouldIgnoreNamespace(string namespaceName) 
        { 
            bool result;
            if(IsNamespaceKnown(namespaceName)) 
            {
                result = object.ReferenceEquals(namespaceName, CompatibilityUri);
            }
            else 
            {
                result = Scope.CanIgnore(namespaceName); 
            } 
            return result;
        } 

        /// 
        /// breaks up a space-delineated string into namespace/element pairs
        ///  
        /// 
        /// the string to be parsed 
        ///  
        /// 
        /// The calling element, used in case of an error 
        /// 
        /// 
        /// the list of namespace/element pairs
        ///  
        private IEnumerable ParseContentToNamespaceElementPair(string content, string callerContext)
        { 
            foreach (string pair in content.Trim().Split(' ')) 
            {
                // check each non-null, non-empty space-delineated namespace/element pair 
                if(!String.IsNullOrEmpty(pair))
                {
                    int colonIndex = pair.IndexOf(':');
                    int length = pair.Length; 

                    if(colonIndex <= 0 || colonIndex >= length - 1 || colonIndex != pair.LastIndexOf(':')) 
                    { 
                        // if string does not have a ':', if the last character in the string is a ':'
                        // or if the string contains more than one ':', throw an exception 
                        Error(SR.Get(SRID.XCRInvalidFormat), callerContext);
                    }

                    string prefix = pair.Substring(0, colonIndex); 
                    string elementName = pair.Substring(colonIndex + 1, length - 1 - colonIndex);
                    string namespaceName = LookupNamespace(prefix); 
 
                    if (namespaceName == null)
                    { 
                        // if a prefix does not map to a namespace, throw an exception
                        Error(SR.Get(SRID.XCRUndefinedPrefix), prefix);
                    }
                    else if (elementName != "*" && !IsName(elementName)) 
                    {
                        // if the element's name is not valid XML, throw an exception 
                        Error(SR.Get(SRID.XCRInvalidXMLName), pair); 
                    }
                    else 
                    {
                        yield return new NamespaceElementPair(namespaceName, elementName);
                    }
                } 
            }
        } 
 
        /// 
        /// converts a string of space-delineated prefixes into a list of namespaces 
        /// 
        /// 
        /// the string to be parsed
        ///  
        /// 
        /// the list of namespace/element pairs 
        ///  
        private IEnumerable PrefixesToNamespaces(string prefixes)
        { 
            foreach (string prefix in prefixes.Trim().Split(' '))
            {
                // check each non-null, non-empty space-delineated prefix
                if(!String.IsNullOrEmpty(prefix)) 
                {
                    string namespaceUri = LookupNamespace(prefix); 
 
                    if (namespaceUri == null)
                    { 
                        // if a prefix does not map to a namespace, throw an exception
                        Error(SR.Get(SRID.XCRUndefinedPrefix), prefix);
                    }
                    else 
                    {
                        yield return namespaceUri; 
                    } 
                }
            } 
        }

        /// 
        /// advances the reader to the next known namespace/attribute pair 
        /// 
        ///  
        /// true if a known namespace/attribute pair was found 
        /// 
        private bool SkipToKnownAttribute() 
        {
            bool result = true;
            while (result && ShouldIgnoreNamespace(NamespaceURI))
            { 
                result = Reader.MoveToNextAttribute();
            } 
            return result; 
        }
 
        /// 
        /// Scans the current element for compatibility attributes.  Pushes a new
        /// scope onto the stack under the following conditions:
        /// 1) Ignorable or MustUnderstand attribute read 
        /// 2) current element has not previously declared an Ignorable or
        ///    MustUnderstand attribute 
        /// 
        /// However, if a last condition is not fulfilled, then the scope is popped off
        /// before the function returns 
        /// 3) current element is not empty
        ///
        /// stores in _ignoredAttributeCount the number of attributes on the current element
        /// that should be ignored, for the sake of improving perf in attribute-related 
        /// methods/properties
        ///  
        ///  
        /// the depth of the Reader at the element currently being processed
        ///  
        private void ScanForCompatibility(int elementDepth)
        {
            bool onAttribute = Reader.MoveToFirstAttribute();
 
            _ignoredAttributeCount = 0;
 
            if (onAttribute) 
            {
                _attributePosition = 0; // we count the attribute index in case we see Ignorable 

                do
                {
                    string namespaceName = NamespaceURI; 

                    if(ShouldIgnoreNamespace(namespaceName)) 
                    { 
                        // check each attribute's namespace to see if it should be ignored
                        if (object.ReferenceEquals(namespaceName, CompatibilityUri)) 
                        {
                            // if the attribute is in the markup-compatibility namespace
                            // find and call the appropriate attribute handler callback.
                            string attributeName = Reader.LocalName; 
                            HandleAttributeCallback attributeCB;
                            if(!_attributeHandler.TryGetValue(attributeName, out attributeCB)) 
                            { 
                                Error(SR.Get(SRID.XCRUnknownCompatAttrib), attributeName);
                            } 
                            attributeCB(elementDepth);
                        }

                        _ignoredAttributeCount++; 
                    }
 
                    onAttribute = Reader.MoveToNextAttribute(); 
                    _attributePosition++; // we count the attribute index in case we see Ignorable
                } while (onAttribute); 

                if (Scope.Depth == elementDepth)
                {
                    // if this element pushed a scope, then we need to do a sanity check 
                    Scope.Verify();
                } 
 
                // move the reader back to the element for the client
                Reader.MoveToElement(); 
            }
        }

 
        /// 
        /// pops a scope if the end of a compatibility region. 
        ///  
        /// 
        /// the depth of the Reader at the element currently being processed 
        /// 
        private void ScanForEndCompatibility(int elementDepth)
        {
            if (elementDepth == Scope.Depth) 
            {
                // if the current element's depth equals the depth of the top-level scope, then pop 
                PopScope(); 
            }
        } 

        /// 
        /// pushes a new scope onto the stack with a depth passed as an arg.
        /// PushScope does not push a scope if the top scope on the stack is not a lower depth. 
        /// 
        ///  
        /// the depth of the Reader at the element currently being processed 
        /// 
        private void PushScope(int elementDepth) 
        {
            if(_compatibilityScope.Depth < elementDepth)
            {
                // if the current element has already pushed a scope, then don't push another one 
                _compatibilityScope = new CompatibilityScope(_compatibilityScope, elementDepth, this);
            } 
        } 

        ///  
        /// pops a scope off the top of the stack.
        /// PopScope *always* pops, it does not check the depth before doing so
        /// 
        private void PopScope() 
        {
            _compatibilityScope = _compatibilityScope.Previous; 
        } 

        ///  
        /// handles mc:AlternateContent element
        ///
        /// a good way to think of AlternateContent blocks is as a switch/case
        /// statement.  The AlternateContent tag is like switch, Choice is like 
        /// case, and Fallback is like default.
        ///  
        ///  
        /// the depth of the Reader at the element currently being processed
        ///  
        /// 
        /// returns whether the Reader has more to be read
        /// 
        private void HandleAlternateContent(int elementDepth, ref bool more) 
        {
            if (Scope.InAlternateContent) 
            { 
                // the only valid tags within  ...  are
                // Choice and Fallback 
                Error(SR.Get(SRID.XCRInvalidACChild, Reader.Name));
            }
            if(Reader.IsEmptyElement)
            { 
                // AlternateContent blocks must have a Choice, so they can't be empty
                Error(SR.Get(SRID.XCRChoiceNotFound)); 
            } 

            // check for markup-compatibility attributes, then push an AlternateContent scope 
            ScanForCompatibility(elementDepth);
            PushScope(elementDepth);

            Scope.InAlternateContent = true; 
            _depthOffset++;
            more = Reader.Read(); 
        } 

        ///  
        /// handles mc:Choice element
        ///
        /// a good way to think of AlternateContent blocks is as a switch/case
        /// statement.  The AlternateContent tag is like switch, Choice is like 
        /// case, and Fallback is like default.
        ///  
        ///  
        /// the depth of the Reader at the element currently being processed
        ///  
        /// 
        /// returns whether the Reader has more to be read
        /// 
        private void HandleChoice(int elementDepth, ref bool more) 
        {
            if (!Scope.InAlternateContent) 
            { 
                // Choice must be the child of AlternateContent
                Error(SR.Get(SRID.XCRChoiceOnlyInAC)); 
            }
            if (Scope.FallbackSeen)
            {
                // Choice cannot occur after Fallback 
                Error(SR.Get(SRID.XCRChoiceAfterFallback));
            } 
 
            string requiresValue = Reader.GetAttribute(Requires);
 
            if (requiresValue == null)
            {
                // Choice must have a requires attribute
                Error(SR.Get(SRID.XCRRequiresAttribNotFound)); 
            }
            if (String.IsNullOrEmpty(requiresValue)) 
            { 
                // Requires attribute may not be empty
                Error(SR.Get(SRID.XCRInvalidRequiresAttribute)); 
            }

            CompatibilityScope scope = Scope;
 
            // check for markup-compatibility attributes
            ScanForCompatibility(elementDepth); 
 
            if (AttributeCount != 1)
            { 
                // Choice may not have any attribute that should not be ignored other than Requires
                // get first non-markup-compatibility, non-Requires attribute
                MoveToFirstAttribute();
                if(Reader.LocalName == Requires) 
                {
                    MoveToNextAttribute(); 
                } 
                string attributeName = Reader.LocalName;
                MoveToElement(); 

                Error(SR.Get(SRID.XCRInvalidAttribInElement), attributeName, Choice);
            }
 
            if (scope.ChoiceTaken)
            { 
                // a previous choice was valid, so pop any scope pushed and 
                // skip to next attribute after 
                ScanForEndCompatibility(elementDepth); 
                Reader.Skip();
            }
            else
            { 
                // mark AlternateContent as having seen a choice
                scope.ChoiceSeen = true; 
 
                bool allKnown = true;
                bool somethingSeen = false; 

                foreach (string namespaceUri in PrefixesToNamespaces(requiresValue))
                {
                    somethingSeen = true; 
                    if (!IsNamespaceKnown(namespaceUri))
                    { 
                        // if any attribute in the Requires value is unknown, then do not take this choice 
                        allKnown = false;
                        break; 
                    }
                }

                if (!somethingSeen) 
                {
                    // if the Requires value does not contain a valid prefix/namespace, throw an exception 
                    Error(SR.Get(SRID.XCRInvalidRequiresAttribute)); 
                }
 
                if (allKnown)
                {
                    // if all namespace in the Requires value are known, then this is the Choice taken.
                    // Mark AlternateContent scope as having taken a choice 
                    scope.ChoiceTaken = true;
 
                    // we push a scope here as a place holder, because AlternateContent 
                    // scopes do not allow child elements other than Choice and Fallback
                    PushScope(elementDepth); 
                    _depthOffset++;
                    more = Reader.Read();
                }
                else 
                {
                    // this is not the choice taken, so pop any scope pushed and 
                    // skip to next attribute after  
                    ScanForEndCompatibility(elementDepth);
                    Reader.Skip(); 
                }
            }
        }
 
        /// 
        /// handles mc:Fallback element 
        /// 
        /// a good way to think of AlternateContent blocks is as a switch/case
        /// statement.  The AlternateContent tag is like switch, Choice is like 
        /// case, and Fallback is like default.
        /// 
        /// 
        /// the depth of the Reader at the element currently being processed 
        /// 
        ///  
        /// returns whether the Reader has more to be read 
        /// 
        private void HandleFallback(int elementDepth, ref bool more) 
        {
            if (!Scope.InAlternateContent)
            {
                // Fallback must be the child of AlternateContent 
                Error(SR.Get(SRID.XCRFallbackOnlyInAC));
            } 
            if (!Scope.ChoiceSeen) 
            {
                // AlternateContent block must contain a Choice element 
                Error(SR.Get(SRID.XCRChoiceNotFound));
            }
            if (Scope.FallbackSeen)
            { 
                // AlternateContent block may only contain one Fallback child
                Error(SR.Get(SRID.XCRMultipleFallbackFound)); 
            } 

            // mark scope as having a fallback 
            Scope.FallbackSeen = true;
            bool choiceTaken = Scope.ChoiceTaken;

            // check for markup-compatibility attributes 
            ScanForCompatibility(elementDepth);
 
            if (AttributeCount != 0) 
            {
                // Fallback may not have any attribute that should not be ignored 
                // get first non-markup-compatibility attribute
                MoveToFirstAttribute();
                string attributeName = Reader.LocalName;
                MoveToElement(); 

                Error(SR.Get(SRID.XCRInvalidAttribInElement), attributeName, Fallback); 
            } 

            if (choiceTaken) 
            {
                // a choice was valid, so ignore contents
                ScanForEndCompatibility(elementDepth);
                Reader.Skip(); 
            }
            else 
            { 
                // this is the content that will be used, so push a scope
                if(!Reader.IsEmptyElement) 
                {
                    // we push a scope here as a place holder, because AlternateContent
                    // scopes do not allow child elements other than Choice and Fallback
                    PushScope(elementDepth); 
                    _depthOffset++;
                } 
                more = Reader.Read(); 
            }
        } 

        /// 
        /// handles mc:Ignorable="foo" attribute
        /// 
        /// Ignorable is used to indicate that the namespace the prefix is mapped to can
        /// be ignored, i.e. when the namespace/element or namespace/attribute occurs it 
        /// is not returned by the reader. 
        /// 
        private void HandleIgnorable(int elementDepth) 
        {
            PushScope(elementDepth);

            foreach (string namespaceUri in PrefixesToNamespaces(Reader.Value)) 
            {
                Scope.Ignorable(namespaceUri); 
            } 

            // Just in case one of the namespaces that preceded the Ignorable declaration 
            // was an ignorable namespace, we have to recompute _ignoredAttributeCount :Þ .
            // No need to check if we haven't yet had any non-ignored attributes.
            if (_ignoredAttributeCount < _attributePosition)
            { 
                _ignoredAttributeCount = 0;
                Reader.MoveToFirstAttribute(); 
 
                for (int i = 0; i < _attributePosition; i++)
                { 
                    if (ShouldIgnoreNamespace(Reader.NamespaceURI))
                    {
                        _ignoredAttributeCount++;
                    } 

                    Reader.MoveToNextAttribute(); 
                } 
            }
        } 

        /// 
        /// handles mc:MustUnderstand="foo" attribute
        /// 
        /// MustUnderstand is used to indicate that the namespace the prefix is mapped to
        /// cannot be handled, and if it is not understood an exception is thrown 
        ///  
        private void HandleMustUnderstand(int elementDepth)
        { 
            foreach (string namespaceUri in PrefixesToNamespaces(Reader.Value))
            {
                if (!IsNamespaceKnown(namespaceUri))
                { 
                    Error(SR.Get(SRID.XCRMustUnderstandFailed), namespaceUri);
                } 
            } 
        }
 
        /// 
        /// handles mc:ProcessContent="foo:bar" attribute
        ///
        /// ProcessContent is used to indicate that an ignorable namespace has some 
        /// elements that should be skipped, but contain child elements that should be processed.
        /// 
        /// The wildcard token ("foo:*") indicates that the children of any element in that 
        /// namespace should be processed.
        ///  
        private void HandleProcessContent(int elementDepth)
        {
            PushScope(elementDepth);
 
            foreach (NamespaceElementPair pair in ParseContentToNamespaceElementPair(Reader.Value, _processContent))
            { 
                Scope.ProcessContent(pair.namespaceName, pair.itemName); 
            }
        } 

        /// 
        /// handles mc:PreserveElements="foo:bar" attribute
        /// 
        /// functionality is supported, but not implemented
        ///  
        private void HandlePreserveElements(int elementDepth) 
        {
            PushScope(elementDepth); 

            foreach (NamespaceElementPair pair in ParseContentToNamespaceElementPair(Reader.Value, _preserveElements))
            {
                Scope.PreserveElement(pair.namespaceName, pair.itemName); 
            }
        } 
 
        /// 
        /// handles mc:PreserveAttributes="foo:bar" attribute 
        ///
        /// functionality is supported, but not implemented
        /// 
        private void HandlePreserveAttributes(int elementDepth) 
        {
            PushScope(elementDepth); 
 
            foreach (NamespaceElementPair pair in ParseContentToNamespaceElementPair(Reader.Value, _preserveAttributes))
            { 
                Scope.PreserveAttribute(pair.namespaceName, pair.itemName);
            }
        }
 
        /// 
        /// helper method to generate an exception 
        ///  
        private void Error(string message, params object[] args)
        { 
            IXmlLineInfo info = Reader as IXmlLineInfo;
            throw new XmlException(string.Format(CultureInfo.InvariantCulture, message, args), null, info == null ? 1 : info.LineNumber,
                info == null ? 1 : info.LinePosition);
        } 
        #endregion Private Methods
 
        #region Private Properties 
        private CompatibilityScope Scope
        { 
            get
            {
                return _compatibilityScope;
            } 
        }
 
        private string AlternateContent 
        {
            get 
            {
                if (_alternateContent == null)
                {
                    _alternateContent = Reader.NameTable.Add("AlternateContent"); 
                }
                return _alternateContent; 
            } 
        }
 
        private string Choice
        {
            get
            { 
                if (_choice == null)
                { 
                    _choice = Reader.NameTable.Add("Choice"); 
                }
                return _choice; 
            }
        }

        private string Fallback 
        {
            get 
            { 
                if (_fallback == null)
                { 
                    _fallback = Reader.NameTable.Add("Fallback");
                }
                return _fallback;
            } 
        }
 
        private string Requires 
        {
            get 
            {
                if (_requires == null)
                {
                    _requires = Reader.NameTable.Add("Requires"); 
                }
                return _requires; 
            } 
        }
 
        private string Ignorable
        {
            get
            { 
                if(_ignorable == null)
                { 
                    _ignorable = Reader.NameTable.Add("Ignorable"); 
                }
                return _ignorable; 
            }
        }

        private string MustUnderstand 
        {
            get 
            { 
                if(_mustUnderstand == null)
                { 
                    _mustUnderstand = Reader.NameTable.Add("MustUnderstand");
                }
                return _mustUnderstand;
            } 
        }
 
        private string ProcessContent 
        {
            get 
            {
                if(_processContent == null)
                {
                    _processContent = Reader.NameTable.Add("ProcessContent"); 
                }
                return _processContent; 
            } 
        }
 
        private string PreserveElements
        {
            get
            { 
                if(_preserveElements == null)
                { 
                    _preserveElements = Reader.NameTable.Add("PreserveElements"); 
                }
                return _preserveElements; 
            }
        }

        private string PreserveAttributes 
        {
            get 
            { 
                if(_preserveAttributes == null)
                { 
                    _preserveAttributes = Reader.NameTable.Add("PreserveAttributes");
                }
                return _preserveAttributes;
            } 
        }
 
        private string CompatibilityUri 
        {
            get 
            {
                if (_compatibilityUri == null)
                {
                    _compatibilityUri = Reader.NameTable.Add(MarkupCompatibilityURI); 
                }
                return _compatibilityUri; 
            } 
        }
        #endregion Private Properties 
        #region Nested Classes
        struct NamespaceElementPair
        {
            public string namespaceName; 
            public string itemName;
 
            public NamespaceElementPair(string namespaceName, string itemName) 
            {
                this.namespaceName = namespaceName; 
                this.itemName = itemName;
            }
        }
 
        /// 
        /// CompatibilityScopes are used to handle markup-compatibility elements and attributes. 
        /// Each scope stores the "previous" or parent scope, its depth, and an associated XmlCompatibilityReader. 
        /// At a particular Reader depth, only one scope should be pushed.
        ///  
        private class CompatibilityScope
        {
            CompatibilityScope _previous;
            int _depth; 
            bool _fallbackSeen;
            bool _inAlternateContent; 
            bool _inProcessContent; 
            bool _choiceTaken;
            bool _choiceSeen; 
            XmlCompatibilityReader _reader;
            Dictionary _ignorables;
            Dictionary _processContents;
            Dictionary _preserveElements; 
            Dictionary _preserveAttributes;
 
            public CompatibilityScope(CompatibilityScope previous, int depth, XmlCompatibilityReader reader) 
            {
                _previous = previous; 
                _depth = depth;
                _reader = reader;
            }
 
            public CompatibilityScope Previous
            { 
                get 
                {
                    return _previous; 
                }
            }

            public int Depth 
            {
                get 
                { 
                    return _depth;
                } 
            }

            public bool FallbackSeen
            { 
                get
                { 
                    bool result; 
                    if(_inProcessContent && _previous != null)
                    { 
                        result = _previous.FallbackSeen;
                    }
                    else
                    { 
                        result = _fallbackSeen;
                    } 
                    return result; 
                }
                set 
                {
                    if(_inProcessContent && _previous != null)
                    {
                        _previous.FallbackSeen = value; 
                    }
                    else 
                    { 
                        _fallbackSeen = value;
                    } 
                }
            }

            public bool InAlternateContent 
            {
                get 
                { 
                    bool result;
                    if(_inProcessContent && _previous != null) 
                    {
                        result = _previous.InAlternateContent;
                    }
                    else 
                    {
                        result = _inAlternateContent; 
                    } 
                    return result;
                } 
                set
                {
                    _inAlternateContent = value;
                } 
            }
 
            public bool InProcessContent 
            {
                set 
                {
                    _inProcessContent = value;
                }
            } 

            public bool ChoiceTaken 
            { 
                get
                { 
                    bool result;
                    if(_inProcessContent && _previous != null)
                    {
                        result = _previous.ChoiceTaken; 
                    }
                    else 
                    { 
                        result = _choiceTaken;
                    } 
                    return result;
                }
                set
                { 
                    if(_inProcessContent && _previous != null)
                    { 
                        _previous.ChoiceTaken = value; 
                    }
                    else 
                    {
                        _choiceTaken = value;
                    }
                } 
            }
 
            public bool ChoiceSeen 
            {
                get 
                {
                    bool result;
                    if(_inProcessContent && _previous != null)
                    { 
                        result = _previous.ChoiceSeen;
                    } 
                    else 
                    {
                        result = _choiceSeen; 
                    }
                    return result;
                }
                set 
                {
                    if(_inProcessContent && _previous != null) 
                    { 
                        _previous.ChoiceSeen = value;
                    } 
                    else
                    {
                        _choiceSeen = value;
                    } 
                }
            } 
 
            public bool CanIgnore(string namespaceName)
            { 
                bool result = IsIgnorableAtCurrentScope(namespaceName);

                if (!result && _previous != null)
                { 
                    result = _previous.CanIgnore(namespaceName);
                } 
 
                return result;
            } 

            public bool IsIgnorableAtCurrentScope(string namespaceName)
            {
                return _ignorables != null && _ignorables.ContainsKey(namespaceName); 
            }
 
            public bool ShouldProcessContent(string namespaceName, string elementName) 
            {
                bool result = false; 
                ProcessContentSet set;
                if (_processContents != null && _processContents.TryGetValue(namespaceName, out set))
                {
                    result = set.ShouldProcessContent(elementName); 
                }
                else if (_previous != null) 
                { 
                    result = _previous.ShouldProcessContent(namespaceName, elementName);
                } 

                return result;
            }
 
            public void Ignorable(string namespaceName)
            { 
                if (_ignorables == null) 
                {
                    _ignorables = new Dictionary(); 
                }
                _ignorables[namespaceName] = null; // we don't care about value, just key
            }
 
            public void ProcessContent(string namespaceName, string elementName)
            { 
                if (_processContents == null) 
                {
                    _processContents = new Dictionary(); 
                }
                ProcessContentSet processContentSet;
                if (!_processContents.TryGetValue(namespaceName, out processContentSet))
                { 
                    processContentSet = new ProcessContentSet(namespaceName, _reader);
                    _processContents.Add(namespaceName, processContentSet); 
                } 
                processContentSet.Add(elementName);
            } 

            public void PreserveElement(string namespaceName, string elementName)
            {
                if (_preserveElements == null) 
                {
                    _preserveElements = new Dictionary(); 
                } 
                PreserveItemSet preserveElementSet;
                if (!_preserveElements.TryGetValue(namespaceName, out preserveElementSet)) 
                {
                    preserveElementSet = new PreserveItemSet(namespaceName, _reader);
                    _preserveElements.Add(namespaceName, preserveElementSet);
                } 
                preserveElementSet.Add(elementName);
            } 
 
            public void PreserveAttribute(string namespaceName, string attributeName)
            { 
                if (_preserveAttributes == null)
                {
                    _preserveAttributes = new Dictionary();
                } 
                PreserveItemSet preserveAttributeSet;
                if (!_preserveAttributes.TryGetValue(namespaceName, out preserveAttributeSet)) 
                { 
                    preserveAttributeSet = new PreserveItemSet(namespaceName, _reader);
                    _preserveAttributes.Add(namespaceName, preserveAttributeSet); 
                }
                preserveAttributeSet.Add(attributeName);
            }
 
            /*public bool ShouldPreserveElement(string namespaceName, string elementName)
            { 
                bool result = _preserveItems != null && _preserveItems.ShouldPreserveElement(namespaceName, elementName); 
                if (!result && _previous != null)
                    result = _previous.ShouldPreserveElement(namespaceName, elementName); 
                return result;
            }

            public bool ShouldPreserveAttribute(string namespaceName, string attributeName) 
            {
                bool result = _preserveItems != null && _preserveItems.ShouldPreserveAttribute(namespaceName, attributeName); 
                if (!result && _previous != null) 
                    result = _previous.ShouldPreserveAttribute(namespaceName, attributeName);
                return result; 
            }*/

            public void Verify()
            { 
                // Check process content
                if (_processContents != null) 
                { 
                    foreach (string key in _processContents.Keys)
                    { 
                        if (!IsIgnorableAtCurrentScope(key))
                        {
                            _reader.Error(SR.Get(SRID.XCRNSProcessContentNotIgnorable), key);
                        } 
                    }
                } 
                // Check preserve elements 
                if (_preserveElements != null)
                { 
                    foreach (string key in _preserveElements.Keys)
                    {
                        if (!IsIgnorableAtCurrentScope(key))
                        { 
                            _reader.Error(SR.Get(SRID.XCRNSPreserveNotIgnorable), key);
                        } 
                    } 
                }
                // Check preserve attributes 
                if (_preserveAttributes != null)
                {
                    foreach (string key in _preserveAttributes.Keys)
                    { 
                        if (!IsIgnorableAtCurrentScope(key))
                        { 
                            _reader.Error(SR.Get(SRID.XCRNSPreserveNotIgnorable), key); 
                        }
                    } 
                }
            }
        }
 
        class ProcessContentSet
        { 
            bool _all; 
            string _namespaceName;
            XmlCompatibilityReader _reader; 
            Dictionary _names;

            public ProcessContentSet(string namespaceName, XmlCompatibilityReader reader)
            { 
                _namespaceName = namespaceName;
                _reader = reader; 
            } 

            public bool ShouldProcessContent(string elementName) 
            {
                return _all || (_names != null && _names.ContainsKey(elementName));
            }
 
            public void Add(string elementName)
            { 
                if (ShouldProcessContent(elementName)) 
                {
                    if (elementName == "*") 
                    {
                        _reader.Error(SR.Get(SRID.XCRDuplicateWildcardProcessContent), _namespaceName);
                    }
                    else 
                    {
                        _reader.Error(SR.Get(SRID.XCRDuplicateProcessContent), _namespaceName, elementName); 
                    } 
                }
 
                if (elementName == "*")
                {
                    if (_names != null)
                    { 
                        _reader.Error(SR.Get(SRID.XCRInvalidProcessContent), _namespaceName);
                    } 
                    else 
                    {
                        _all = true; 
                    }
                }
                else
                { 
                    if (_names == null)
                    { 
                        _names = new Dictionary(); 
                    }
 
                    _names[elementName] = null; // we don't care about value, just key
                }
            }
 
        }
 
        class PreserveItemSet 
        {
            bool _all; 
            string _namespaceName;
            XmlCompatibilityReader _reader;
            Dictionary _names;
 
            public PreserveItemSet(string namespaceName, XmlCompatibilityReader reader)
            { 
                _namespaceName = namespaceName; 
                _reader = reader;
            } 

            public bool ShouldPreserveItem(string itemName)
            {
                return _all || (_names != null && _names.ContainsKey(itemName)); 
            }
 
            public void Add(string itemName) 
            {
                if (ShouldPreserveItem(itemName)) 
                {
                    if (itemName == "*")
                    {
                        _reader.Error(SR.Get(SRID.XCRDuplicateWildcardPreserve), _namespaceName); 
                    }
                    else 
                    { 
                        _reader.Error(SR.Get(SRID.XCRDuplicatePreserve), itemName, _namespaceName);
                    } 
                }

                if (itemName == "*")
                { 
                    if (_names != null)
                    { 
                        _reader.Error(SR.Get(SRID.XCRInvalidPreserve), _namespaceName); 
                    }
                    else 
                    {
                        _all = true;
                    }
                } 
                else
                { 
                    if (_names == null) 
                    {
                        _names = new Dictionary(); 
                    }

                    _names.Add(itemName, itemName);
                } 
            }
        } 
        #endregion Nested Classes 

        #region Private Fields 
        private bool _inAttribute; // for Save/Restore ReaderPosition
        private string _currentName; // for Save/Restore ReaderPosition
        private IsXmlNamespaceSupportedCallback _namespaceCallback;
        private Dictionary _knownNamespaces = new Dictionary(); 
        private Dictionary _namespaceMap = new Dictionary();
        private Dictionary _subsumingNamespaces = new Dictionary(); 
        private Dictionary _elementHandler = new Dictionary(); 
        private Dictionary _attributeHandler = new Dictionary();
        private int _depthOffset; // offset for Depth method, to account for elements that should be ignored by client 
        private int _ignoredAttributeCount;
        private int _attributePosition; // used for ScanForCompatibility / HandleIgnorable
        private string _compatibilityUri;
        private string _alternateContent; 
        private string _choice;
        private string _fallback; 
        private string _requires; 
        private string _ignorable;
        private string _mustUnderstand; 
        private string _processContent;
        private string _preserveElements;
        private string _preserveAttributes;
        private CompatibilityScope _compatibilityScope; 

        private const string XmlnsDeclaration = "xmlns"; 
        private const string MarkupCompatibilityURI = "http://schemas.openxmlformats.org/markup-compatibility/2006"; 

        static private string [] _predefinedNamespaces = new string [4] { 
            "http://www.w3.org/2000/xmlns/",
            "http://www.w3.org/XML/1998/namespace",
            "http://www.w3.org/2001/XMLSchema-instance",
            MarkupCompatibilityURI 
        };
        #endregion Private Fields 
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
/****************************************************************************\ 
*
* File: XmlCompatibilityReaderr.cs
*
* Purpose: 
*
* History: 
*    5/11/05:    fmunoz        Created 
*    9/16/05:    oliverfo      Modified
*    9/16/05:    tjhsiang      Modified 
*
* Copyright (C) 2005 by Microsoft Corporation.  All rights reserved.
*
\***************************************************************************/ 

using System; 
using System.Xml; 
using System.Collections.Generic;
using System.Globalization; 
using System.Diagnostics;

#if SYSTEM_XAML
using System.Xaml; 
#endif
 
#if PBTCOMPILER 
using MS.Utility;
namespace MS.Internal.Markup 
#else
using MS.Internal.WindowsBase;
using System.Windows;
 
namespace System.Windows.Markup
#endif 
{ 
#if !PBTCOMPILER
    [FriendAccessAllowed] 
#endif

    // 
    // true if xmlNamespace is recognized 
    // 
    //  
    // the namespace to be checked 
    // 
    //  
    // if the passed in namespace is subsumed, then newXmlNamespace returns the subsuming namespace.
    // 
    internal delegate bool IsXmlNamespaceSupportedCallback(string xmlNamespace, out string newXmlNamespace);
    delegate void HandleElementCallback(int elementDepth, ref bool more); 
    delegate void HandleAttributeCallback(int elementDepth);
#if !PBTCOMPILER 
    [FriendAccessAllowed] 
#endif
    internal sealed class XmlCompatibilityReader: XmlWrappingReader 
    {
        #region Construction
        public XmlCompatibilityReader(XmlReader baseReader):base(baseReader)
        { 
            _compatibilityScope = new CompatibilityScope(null, -1, this);
 
            foreach (string xmlNamespace in _predefinedNamespaces) 
            {
                AddKnownNamespace(xmlNamespace); 
                _namespaceMap[xmlNamespace] = xmlNamespace;
                Reader.NameTable.Add(xmlNamespace);
            }
 
            _elementHandler.Add(AlternateContent, new HandleElementCallback(HandleAlternateContent));
            _elementHandler.Add(Choice, new HandleElementCallback(HandleChoice)); 
            _elementHandler.Add(Fallback, new HandleElementCallback(HandleFallback)); 

            _attributeHandler.Add(Ignorable, new HandleAttributeCallback(HandleIgnorable)); 
            _attributeHandler.Add(MustUnderstand, new HandleAttributeCallback(HandleMustUnderstand));
            _attributeHandler.Add(ProcessContent, new HandleAttributeCallback(HandleProcessContent));
            _attributeHandler.Add(PreserveElements, new HandleAttributeCallback(HandlePreserveElements));
            _attributeHandler.Add(PreserveAttributes, new HandleAttributeCallback(HandlePreserveAttributes)); 
        }
 
        public XmlCompatibilityReader(XmlReader baseReader, 
            IsXmlNamespaceSupportedCallback isXmlNamespaceSupported): this(baseReader)
        { 
            _namespaceCallback = isXmlNamespaceSupported;
        }

        public XmlCompatibilityReader(XmlReader baseReader, 
            IsXmlNamespaceSupportedCallback isXmlNamespaceSupported,
            IEnumerable supportedNamespaces):this(baseReader, isXmlNamespaceSupported) 
        { 
            foreach (string xmlNamespace in supportedNamespaces)
            { 
                AddKnownNamespace(xmlNamespace);
                _namespaceMap[xmlNamespace] = xmlNamespace;
            }
        } 

#if !PBTCOMPILER 
        public XmlCompatibilityReader(XmlReader baseReader, 
            IEnumerable supportedNamespaces):this(baseReader, null, supportedNamespaces)
        { 
        }
#endif
        #endregion Construction
 
        #region Public Methods
        ///  
        /// replaces all future references of namespace URI 'oldNamespace' with 'newNamespace' 
        /// 
        ///  
        /// the namespace to subsume with
        /// 
        /// 
        /// the namespace to be subsumed 
        /// 
        public void DeclareNamespaceCompatibility(string newNamespace, string oldNamespace) 
        { 
            if(newNamespace != oldNamespace)
            { 
                // indicate that newNamespace subsumes another namespace
                AddSubsumingNamespace(newNamespace);

                // If newNamespace is mapped to a namespace, 
                string tempNamespace;
                if (_namespaceMap.TryGetValue(newNamespace, out tempNamespace)) 
                { 
                    // If we have mapped newNamespace already get the newest name.
                    // We don't have to do this recursively because of the code below 
                    // ensures the map always refers to the newest namespace.
                    newNamespace = tempNamespace;
                }
 
                if(IsSubsumingNamespace(oldNamespace))
                { 
                    // if we are mapping what was used as a new namespace to a newer name, 
                    // scan the _newNamespaces dictionary and update the entries. We collect
                    // a list to avoid updating the dictonary during enumeration. 
                    List keysToUpdate = new List();

                    foreach (KeyValuePair pair in _namespaceMap)
                    { 
                        if (pair.Value == oldNamespace)
                        { 
                            keysToUpdate.Add(pair.Key); 
                        }
                    } 

                    foreach (string key in keysToUpdate)
                    {
                        _namespaceMap[key] = newNamespace; 
                    }
                } 
            } 

            _namespaceMap[oldNamespace] = newNamespace; 
        }

        /// 
        /// Reads the next node from the stream. 
        /// 
        ///  
        /// true if the next node was read successfully; false if there are no more nodes to read. 
        /// 
        public override bool Read() 
        {
            bool more = Reader.Read(); //passed as ref arg to ReadStartElement and ReadEndElement
            bool result = false;
 
            while (more)
            { 
                switch (Reader.NodeType) 
                {
                    case XmlNodeType.Element: 
                    {
                        // if the element read should be ignored, read the next element
                        if(!ReadStartElement(ref more))
                        { 
                            continue;
                        } 
                        break; 
                    }
                    case XmlNodeType.EndElement: 
                    {
                        // if the element read should be ignored, read the next element
                        if(!ReadEndElement(ref more))
                        { 
                            continue;
                        } 
                        break; 
                    }
                } 

                // if the element was read successfully and was not ignored, break and return true
                result = true;
                break; 
            }
 
            return result; 
        }
 
        /// 
        /// Used to handle 'start element' tags.  These are actually
        /// just called 'element' tags, the 'start' is just for clarity
        ///  
        /// 
        /// is set to true if there is the document contains more elements, false if the end of the 
        /// document has been reached. 
        /// 
        ///  
        /// true if an element was read that should not be ignored
        /// false if the element read should be ignored or the end of document has been reached
        /// 
        private bool ReadStartElement(ref bool more) 
        {
            // when processing elements, the Reader may advance to another element or attribute, 
            // so we save the values of the current element here 
            int elementDepth = Reader.Depth;
            int depthOffset = _depthOffset; 
            bool isEmpty = Reader.IsEmptyElement;
            string namespaceName = NamespaceURI;
            bool result = false;
 
            if (object.ReferenceEquals(namespaceName, CompatibilityUri))
            { 
                // if the element is a markup-compatibility element, we get the appropriate handler for 
                // the element type, and call the appropriate delegate.  If the element is not recognized
                // we throw an exception. 
                string elementName = Reader.LocalName;
                HandleElementCallback elementCB;
                if(!_elementHandler.TryGetValue(elementName, out elementCB))
                { 
                    Error(SR.Get(SRID.XCRUnknownCompatElement), elementName);
                } 
                elementCB(elementDepth, ref more); 
            }
            // handle non-markup-compatibility elements 
            else
            {
                // check for markup-compatibility attributes and namespaces that should be ignored
                ScanForCompatibility(elementDepth); 

                if (ShouldIgnoreNamespace(namespaceName)) 
                { 
                    if(Scope.ShouldProcessContent(namespaceName, Reader.LocalName))
                    { 
                        // if the current element is unknown and has been marked Ignorable and ProcessContent,
                        // then read the next element, and increase depth offset
                        if(Scope.Depth == elementDepth)
                        { 
                            // if the current element pushed a scope, mark the scope as InProcessContent to
                            // note that for certain logic this scope's parent should be checked 
                            Scope.InProcessContent = true; 
                        }
                        _depthOffset++; 
                        more = Reader.Read();
                    }
                    else
                    { 
                        // if element should be ignored but not processed, check to see if scope must be popped,
                        // then skip to the next element after the end tag of the current element 
                        ScanForEndCompatibility(elementDepth); 
                        Reader.Skip();
                    } 
                }
                else
                {
                    if (Scope.InAlternateContent) 
                    {
                        // if this element is the child of an AlternateContent element, then throw an exception. 
                        Error(SR.Get(SRID.XCRInvalidACChild), Reader.Name); 
                    }
 
                    result = true;
                }
            }
 
            // if the element is empty (e.g. "" and we pushed a scope then get
            // rid of the scope 
            if(isEmpty) 
            {
                ScanForEndCompatibility(elementDepth); 
                _depthOffset = depthOffset;
            }

            return result; 
        }
 
 
        /// 
        /// Used to handle any end element tag 
        /// 
        /// 
        /// is set to true if there is the document contains more elements, false if the end of the
        /// document has been reached. 
        /// 
        ///  
        /// true if an element was read that should not be ignored 
        /// false if the element read should be ignored or the end of document has been reached
        ///  
        private bool ReadEndElement(ref bool more)
        {
            // when reading attributes, the reader's depth increases, so for consistency
            // we store the depth before reading any attributes 
            int elementDepth = Reader.Depth;
            string namespaceName = NamespaceURI; 
            bool result = false;  // return value 

            if (object.ReferenceEquals(namespaceName, CompatibilityUri)) 
            {
                // if the element is a markup-compatibility element, pop a scope, decrement the
                // depth offset and read the next element.
                string elementName = Reader.LocalName; 
                if (object.ReferenceEquals(elementName, AlternateContent))
                { 
                    if (!Scope.ChoiceSeen) 
                    {
                        // if the current element was a , without any Choice 
                        // element children, throw an exception
                        Error(SR.Get(SRID.XCRChoiceNotFound));
                    }
                } 
                _depthOffset--;
                PopScope();  //we know we can pop, so no need to scan 
                more = Reader.Read(); 
            }
            else 
            {
                if (ShouldIgnoreNamespace(namespaceName))
                {
                    // if current element is Ignorable, then to be on it, it must have been marked 
                    // ProcessContent.  Pop a scope if the corresponding start element pushed a scope a
                    // scope, decrement the depth offset and read the next element. 
                    Debug.Assert(Scope.ShouldProcessContent(namespaceName, Reader.LocalName)); 
                    ScanForEndCompatibility(elementDepth);
                    _depthOffset--; 
                    more = Reader.Read();
                }
                else
                { 
                    ScanForEndCompatibility(elementDepth);
                    result = true; 
                } 
            }
 
            return result;
        }

        ///  
        /// Gets the value of the attribute with the specified index.
        ///  
        ///  
        /// The index of the attribute. The index is zero-based. (The first attribute has index 0.)
        ///  
        /// 
        /// The value of the specified attribute. If the attribute is not found, a null reference is returned.
        /// 
        public override string GetAttribute(int i) 
        {
            string result = null; 
 
            if (_ignoredAttributeCount == 0)
            { 
                // if the current element should not ignored any of its attributes, skip extra logic
                result = Reader.GetAttribute(i);
            }
            else 
            {
                SaveReaderPosition(); 
 
                // move to 'i'th attribute, get its value
                MoveToAttribute(i); 
                result = Reader.Value;

                RestoreReaderPosition();
            } 

            return result; 
        } 

        ///  
        /// Gets the value of the attribute with the specified name.
        /// 
        /// 
        /// The qualified name of the attribute. 
        /// 
        ///  
        /// The value of the specified attribute. If the attribute is not found, a null reference is returned. 
        /// 
        public override string GetAttribute(string name) 
        {
            string result = null;

            if (_ignoredAttributeCount == 0) 
            {
                // if the current element should not ignored any attributes, call Reader method 
                result = Reader.GetAttribute(name); 
            }
            else 
            {
                SaveReaderPosition();

                // move to "name" attribute 
                if (MoveToAttribute(name))
                { 
                    result = Reader.Value; 
                    RestoreReaderPosition();
                } 
            }

            return result;
        } 

        ///  
        /// Gets the value of the attribute with the specified local name and namespace URI. 
        /// 
        ///  
        /// The local name of the attribute.
        /// 
        /// 
        /// The namespace URI of the attribute. 
        /// 
        ///  
        /// The value of the specified attribute. If the attribute is not found, a null reference is returned. 
        /// 
        public override string GetAttribute(string localName, string namespaceURI) 
        {
            string result = null;

            if (_ignoredAttributeCount == 0 || !ShouldIgnoreNamespace(namespaceURI) ) 
            {
                // if the current element does not have any attributes that should be ignored or 
                // the namespace provided is not ignorable, call Reader method 
                result = Reader.GetAttribute(localName, namespaceURI);
            } 

            return result;
        }
 
        /// 
        /// Gets the value of the attribute with the specified index. 
        ///  
        /// 
        /// The index of the attribute. The index is zero-based. (The first attribute has index 0.) 
        /// 
        /// 
        /// true if the attribute is found; otherwise, false. If false, the reader's position does not change.
        ///  
        public override void MoveToAttribute(int i)
        { 
            if (_ignoredAttributeCount == 0) 
            {
                // if the current element should not ignored any attributes, call Reader method 
                Reader.MoveToAttribute(i);
            }
            else if (i < 0 || i >= AttributeCount)
            { 
                throw new ArgumentOutOfRangeException("i");
            } 
            else 
            {
                // move Reader to first attribute and iterate until 'i'th element found 
                Reader.MoveToFirstAttribute();

                while (true)
                { 
                    if (!ShouldIgnoreNamespace(NamespaceURI))
                    { 
                        // if attribute should not be ignored, decrement 'i', if i == 0 we've found element 
                        if (i-- == 0)
                        { 
                            break;
                        }
                    }
 
                    Reader.MoveToNextAttribute();
                } 
            } 
        }
 
        /// 
        /// Moves to the attribute with the specified name.
        /// 
        ///  
        /// The qualified name of the attribute.
        ///  
        ///  
        /// true if the attribute is found; otherwise, false. If false, the reader's position does not change.
        ///  
        public override bool MoveToAttribute(string name)
        {
            bool result;
 
            if (_ignoredAttributeCount == 0)
            { 
                // if the current element should not ignored any attributes, call Reader method 
                result = Reader.MoveToAttribute(name);
            } 
            else
            {
                SaveReaderPosition();
 
                result = Reader.MoveToAttribute(name);
                if (result && ShouldIgnoreNamespace(NamespaceURI)) 
                { 
                    // if attribute should be ignored, return false and restore state
                    result = false; 
                    RestoreReaderPosition();
                }
            }
 
            return result;
        } 
 
        /// 
        /// Moves to the attribute with the specified local name and namespace URI. 
        /// 
        /// 
        /// The local name of the attribute.
        ///  
        /// 
        /// The namespace URI of the attribute. 
        ///  
        /// 
        /// true if the attribute is found; otherwise, false. If false, the reader's position does not change. 
        /// 
        public override bool MoveToAttribute(string localName, string namespaceURI)
        {
            bool result; 

            if (_ignoredAttributeCount == 0) 
            { 
                // if the current element should not ignored any attributes, call Reader method
                result = Reader.MoveToAttribute(localName, namespaceURI); 
            }
            else
            {
                SaveReaderPosition(); 

                result = Reader.MoveToAttribute(localName, namespaceURI); 
 
                if (result && ShouldIgnoreNamespace(namespaceURI))
                { 
                    result = false;
                    RestoreReaderPosition();
                }
            } 
            return result;
        } 
 
        /// 
        /// Moves to the first attribute. 
        /// 
        /// 
        /// true if an attribute exists (the reader moves to the first attribute);
        /// otherwise, false (the position of the reader does not change). 
        /// 
        public override bool MoveToFirstAttribute() 
        { 
            bool result = HasAttributes;
 
            if(result)
            {
                MoveToAttribute(0);
            } 

            return result; 
        } 

        ///  
        /// Moves to the next attribute.
        /// 
        /// 
        /// true if there is a next attribute; false if there are no more attributes. 
        /// 
        public override bool MoveToNextAttribute() 
        { 
            bool result;
 
            if (_ignoredAttributeCount == 0)
            {
                // if the current element should not ignored any attributes, call Reader method
                result = Reader.MoveToNextAttribute(); 
            }
            else 
            { 
                SaveReaderPosition();
 
                result = Reader.MoveToNextAttribute();

                if (result)
                { 
                    result = SkipToKnownAttribute();
 
                    if (!result) 
                    {
                        // if no more attributes exist that should not be ignored, return false and restore state 
                        RestoreReaderPosition();
                    }
                }
            } 

            return result; 
        } 

        ///  
        /// Resolves a namespace prefix in the current element's scope.
        /// 
        /// 
        /// The prefix whose namespace URI you want to resolve. To match the default namespace, 
        /// pass an empty string. This string does not have to be atomized.
        ///  
        ///  
        /// The namespace URI to which the prefix maps or a null reference if no matching prefix is found.
        ///  
        public override string LookupNamespace (string prefix)
        {
            string namespaceName = Reader.LookupNamespace(prefix);
 
            if (namespaceName != null)
            { 
                namespaceName = GetMappedNamespace(namespaceName); 
            }
 
            return namespaceName;
        }

        #endregion Public Methods 

        #region Public Properties 
 
        /// 
        /// This override is to ensure that the value 
        /// for the xmlns attribute reflects all the
        /// compatibility (subsuming) rules.
        /// 
        public override string Value 
        {
            get 
            { 
                // Look for xmlns
                if (String.Equals(XmlnsDeclaration, Reader.LocalName, StringComparison.Ordinal)) 
                {
                    return LookupNamespace(String.Empty);
                }
                // Look for xmlns: ... 
                else if (String.Equals(XmlnsDeclaration, Reader.Prefix, StringComparison.Ordinal))
                { 
                    return LookupNamespace(Reader.LocalName); 
                }
 
                return Reader.Value;
            }
        }
 
        /// 
        /// Gets the namespace URI (as defined in the W3C Namespace specification) of the node 
        /// on which the reader is positioned. 
        /// 
        public override string NamespaceURI 
        {
            get
            {
                return GetMappedNamespace(Reader.NamespaceURI); 
            }
        } 
 
        /// 
        /// Gets the depth of the current node in the XML document. 
        /// 
        public override int Depth
        {
            get 
            {
                return Reader.Depth - _depthOffset; 
            } 
        }
 
        /// 
        /// Gets a value indicating whether the current node has any attributes
        /// 
        public override bool HasAttributes 
        {
            get 
            { 
                return AttributeCount != 0;
            } 
        }

        /// 
        /// Gets the number of attributes on the current node. 
        /// 
        public override int AttributeCount 
        { 
            get
            { 
                return Reader.AttributeCount - _ignoredAttributeCount;
            }
        }
 
        /// 
        /// Sets a value indicating whether to normalize white space and attribute values. 
        ///  
        public bool Normalization
        { 
            set
            {
                XmlTextReader xmlTextReader = Reader as XmlTextReader;
 
                // review, what if not the XmlTextReader.
                if (null != xmlTextReader) 
                { 
                    xmlTextReader.Normalization = value;
                } 
            }
        }

#if !PBTCOMPILER 
        /// 
        /// Answer the encoding of the underlying xaml stream 
        ///  
        internal System.Text.Encoding Encoding
        { 
            get
            {
                XmlTextReader textReader = Reader as XmlTextReader;
                if (textReader == null) 
                {
                    return new System.Text.UTF8Encoding(true,true); 
                } 
                else
                { 
                    return textReader.Encoding;
                }
            }
        } 
#endif
        #endregion Public Properties 
 
        #region Private Methods
 
        private void SaveReaderPosition()
        {
            // Save current state so we can go back to the same spot if this fails
            _inAttribute = (Reader.NodeType == XmlNodeType.Attribute); 
            _currentName = Reader.Name;
        } 
 
        private void RestoreReaderPosition()
        { 
            // Restore reader state from SaveReaderPosition
            if (_inAttribute)
            {
                Reader.MoveToAttribute(_currentName); 
            }
            else 
            { 
                Reader.MoveToElement();
            } 
        }

        /// 
        /// Retrieves the correctly mapped namespace from the namespace provided 
        /// 
        ///  
        /// The name of the namespace to retrieve the mapping of 
        /// 
        ///  
        /// The name of the mapped namespace.
        /// 
        private string GetMappedNamespace(string namespaceName)
        { 
            string mappedNamespace;
 
            // if the namespace is not null, get the mapped namespace (which may be itself) 
            if (!_namespaceMap.TryGetValue(namespaceName, out mappedNamespace))
            { 
                // if the namespace has not yet been mapped, map it
                mappedNamespace = MapNewNamespace(namespaceName);
            }
            else if (mappedNamespace == null) 
            {
                // if the mapped namespace is null, then the namespace was not supported, just return 
                // the given namespace 
                mappedNamespace = namespaceName;
            } 

            return mappedNamespace;
        }
 
        /// 
        /// Adds the namespace to the namespace map.  The default is to map the namespace to itself. 
        /// The namespace is mapped to the value returned by the callback, if a callback exists and the 
        /// callback returns a subsuming namespace.
        ///  
        /// 
        /// The name of the namespace to be mapped.
        /// 
        ///  
        /// The name of the mapped namespace.
        ///  
        private string MapNewNamespace(string namespaceName) 
        {
            if (_namespaceCallback != null) 
            {
                string mappedNamespace;

                // the callback returns whether the namespace is supported, and mappedNamespace is the 
                // namespace subsuming the namespace passed in.
                bool isSupported = _namespaceCallback(namespaceName, out mappedNamespace); 
 
                if (isSupported)
                { 
                    AddKnownNamespace(namespaceName);

                    if(String.IsNullOrEmpty(mappedNamespace) || namespaceName == mappedNamespace)
                    { 
                        _namespaceMap[namespaceName] = namespaceName;
                    } 
                    else 
                    {
                        // subsume namespace with mappedNamespace. 
                        string tempNamespace;

                        if (!_namespaceMap.TryGetValue(mappedNamespace, out tempNamespace))
                        { 
                            // mappedNamespace has not been mapped, so map it
                            tempNamespace = MapNewNamespace(mappedNamespace); 
                        } 

                        DeclareNamespaceCompatibility(tempNamespace, namespaceName); 
                        namespaceName = tempNamespace;
                    }
                }
                else 
                {
                    // if the namespace is not supported, we enter null into the namespaceMap as a placeholder 
                    // so that we do not call the callback again on this namespace. 
                    _namespaceMap[namespaceName] = null;
                } 
            }

            return namespaceName;
        } 

        ///  
        /// Used to determine whether a given namespace subsumes another namespace 
        /// 
        ///  
        /// The name of the namespace to be checked.
        /// 
        /// 
        /// true if the namespace subsumes another namespace; false otherwise 
        /// 
        private bool IsSubsumingNamespace(string namespaceName) 
        { 
            return _subsumingNamespaces.ContainsKey(namespaceName);
        } 

        /// 
        /// Used to specify that a namespace subsumes another namespace
        ///  
        /// 
        /// The name of the namespace to be added. 
        ///  
        private void AddSubsumingNamespace(string namespaceName)
        { 
            _subsumingNamespaces[namespaceName] = null;
        }

        ///  
        /// Used to determine whether a given namespace is known/supported
        ///  
        ///  
        /// The name of the namespace to be checked.
        ///  
        /// 
        /// true if the namespace is known/supported; false otherwise
        /// 
        private bool IsNamespaceKnown(string namespaceName) 
        {
            return _knownNamespaces.ContainsKey(namespaceName); 
        } 

        ///  
        /// Used to specify that a namespace is known or supported
        /// 
        /// 
        /// The name of the namespace to be added. 
        /// 
        private void AddKnownNamespace(string namespaceName) 
        { 
            _knownNamespaces[namespaceName] = null;
        } 

        /// 
        /// Used to determine whether a given namespace should be ignored.  A namespace should be ignored if:
        /// EITHER 
        /// a) the namespace is not known/supported and has been marked Ignorable
        /// OR 
        /// b) the namespace is the markup-compatibility namespace 
        /// 
        ///  
        /// The name of the prefix to be checked.
        /// 
        /// 
        /// true if the namespace should be ignored; false otherwise 
        /// 
        private bool ShouldIgnoreNamespace(string namespaceName) 
        { 
            bool result;
            if(IsNamespaceKnown(namespaceName)) 
            {
                result = object.ReferenceEquals(namespaceName, CompatibilityUri);
            }
            else 
            {
                result = Scope.CanIgnore(namespaceName); 
            } 
            return result;
        } 

        /// 
        /// breaks up a space-delineated string into namespace/element pairs
        ///  
        /// 
        /// the string to be parsed 
        ///  
        /// 
        /// The calling element, used in case of an error 
        /// 
        /// 
        /// the list of namespace/element pairs
        ///  
        private IEnumerable ParseContentToNamespaceElementPair(string content, string callerContext)
        { 
            foreach (string pair in content.Trim().Split(' ')) 
            {
                // check each non-null, non-empty space-delineated namespace/element pair 
                if(!String.IsNullOrEmpty(pair))
                {
                    int colonIndex = pair.IndexOf(':');
                    int length = pair.Length; 

                    if(colonIndex <= 0 || colonIndex >= length - 1 || colonIndex != pair.LastIndexOf(':')) 
                    { 
                        // if string does not have a ':', if the last character in the string is a ':'
                        // or if the string contains more than one ':', throw an exception 
                        Error(SR.Get(SRID.XCRInvalidFormat), callerContext);
                    }

                    string prefix = pair.Substring(0, colonIndex); 
                    string elementName = pair.Substring(colonIndex + 1, length - 1 - colonIndex);
                    string namespaceName = LookupNamespace(prefix); 
 
                    if (namespaceName == null)
                    { 
                        // if a prefix does not map to a namespace, throw an exception
                        Error(SR.Get(SRID.XCRUndefinedPrefix), prefix);
                    }
                    else if (elementName != "*" && !IsName(elementName)) 
                    {
                        // if the element's name is not valid XML, throw an exception 
                        Error(SR.Get(SRID.XCRInvalidXMLName), pair); 
                    }
                    else 
                    {
                        yield return new NamespaceElementPair(namespaceName, elementName);
                    }
                } 
            }
        } 
 
        /// 
        /// converts a string of space-delineated prefixes into a list of namespaces 
        /// 
        /// 
        /// the string to be parsed
        ///  
        /// 
        /// the list of namespace/element pairs 
        ///  
        private IEnumerable PrefixesToNamespaces(string prefixes)
        { 
            foreach (string prefix in prefixes.Trim().Split(' '))
            {
                // check each non-null, non-empty space-delineated prefix
                if(!String.IsNullOrEmpty(prefix)) 
                {
                    string namespaceUri = LookupNamespace(prefix); 
 
                    if (namespaceUri == null)
                    { 
                        // if a prefix does not map to a namespace, throw an exception
                        Error(SR.Get(SRID.XCRUndefinedPrefix), prefix);
                    }
                    else 
                    {
                        yield return namespaceUri; 
                    } 
                }
            } 
        }

        /// 
        /// advances the reader to the next known namespace/attribute pair 
        /// 
        ///  
        /// true if a known namespace/attribute pair was found 
        /// 
        private bool SkipToKnownAttribute() 
        {
            bool result = true;
            while (result && ShouldIgnoreNamespace(NamespaceURI))
            { 
                result = Reader.MoveToNextAttribute();
            } 
            return result; 
        }
 
        /// 
        /// Scans the current element for compatibility attributes.  Pushes a new
        /// scope onto the stack under the following conditions:
        /// 1) Ignorable or MustUnderstand attribute read 
        /// 2) current element has not previously declared an Ignorable or
        ///    MustUnderstand attribute 
        /// 
        /// However, if a last condition is not fulfilled, then the scope is popped off
        /// before the function returns 
        /// 3) current element is not empty
        ///
        /// stores in _ignoredAttributeCount the number of attributes on the current element
        /// that should be ignored, for the sake of improving perf in attribute-related 
        /// methods/properties
        ///  
        ///  
        /// the depth of the Reader at the element currently being processed
        ///  
        private void ScanForCompatibility(int elementDepth)
        {
            bool onAttribute = Reader.MoveToFirstAttribute();
 
            _ignoredAttributeCount = 0;
 
            if (onAttribute) 
            {
                _attributePosition = 0; // we count the attribute index in case we see Ignorable 

                do
                {
                    string namespaceName = NamespaceURI; 

                    if(ShouldIgnoreNamespace(namespaceName)) 
                    { 
                        // check each attribute's namespace to see if it should be ignored
                        if (object.ReferenceEquals(namespaceName, CompatibilityUri)) 
                        {
                            // if the attribute is in the markup-compatibility namespace
                            // find and call the appropriate attribute handler callback.
                            string attributeName = Reader.LocalName; 
                            HandleAttributeCallback attributeCB;
                            if(!_attributeHandler.TryGetValue(attributeName, out attributeCB)) 
                            { 
                                Error(SR.Get(SRID.XCRUnknownCompatAttrib), attributeName);
                            } 
                            attributeCB(elementDepth);
                        }

                        _ignoredAttributeCount++; 
                    }
 
                    onAttribute = Reader.MoveToNextAttribute(); 
                    _attributePosition++; // we count the attribute index in case we see Ignorable
                } while (onAttribute); 

                if (Scope.Depth == elementDepth)
                {
                    // if this element pushed a scope, then we need to do a sanity check 
                    Scope.Verify();
                } 
 
                // move the reader back to the element for the client
                Reader.MoveToElement(); 
            }
        }

 
        /// 
        /// pops a scope if the end of a compatibility region. 
        ///  
        /// 
        /// the depth of the Reader at the element currently being processed 
        /// 
        private void ScanForEndCompatibility(int elementDepth)
        {
            if (elementDepth == Scope.Depth) 
            {
                // if the current element's depth equals the depth of the top-level scope, then pop 
                PopScope(); 
            }
        } 

        /// 
        /// pushes a new scope onto the stack with a depth passed as an arg.
        /// PushScope does not push a scope if the top scope on the stack is not a lower depth. 
        /// 
        ///  
        /// the depth of the Reader at the element currently being processed 
        /// 
        private void PushScope(int elementDepth) 
        {
            if(_compatibilityScope.Depth < elementDepth)
            {
                // if the current element has already pushed a scope, then don't push another one 
                _compatibilityScope = new CompatibilityScope(_compatibilityScope, elementDepth, this);
            } 
        } 

        ///  
        /// pops a scope off the top of the stack.
        /// PopScope *always* pops, it does not check the depth before doing so
        /// 
        private void PopScope() 
        {
            _compatibilityScope = _compatibilityScope.Previous; 
        } 

        ///  
        /// handles mc:AlternateContent element
        ///
        /// a good way to think of AlternateContent blocks is as a switch/case
        /// statement.  The AlternateContent tag is like switch, Choice is like 
        /// case, and Fallback is like default.
        ///  
        ///  
        /// the depth of the Reader at the element currently being processed
        ///  
        /// 
        /// returns whether the Reader has more to be read
        /// 
        private void HandleAlternateContent(int elementDepth, ref bool more) 
        {
            if (Scope.InAlternateContent) 
            { 
                // the only valid tags within  ...  are
                // Choice and Fallback 
                Error(SR.Get(SRID.XCRInvalidACChild, Reader.Name));
            }
            if(Reader.IsEmptyElement)
            { 
                // AlternateContent blocks must have a Choice, so they can't be empty
                Error(SR.Get(SRID.XCRChoiceNotFound)); 
            } 

            // check for markup-compatibility attributes, then push an AlternateContent scope 
            ScanForCompatibility(elementDepth);
            PushScope(elementDepth);

            Scope.InAlternateContent = true; 
            _depthOffset++;
            more = Reader.Read(); 
        } 

        ///  
        /// handles mc:Choice element
        ///
        /// a good way to think of AlternateContent blocks is as a switch/case
        /// statement.  The AlternateContent tag is like switch, Choice is like 
        /// case, and Fallback is like default.
        ///  
        ///  
        /// the depth of the Reader at the element currently being processed
        ///  
        /// 
        /// returns whether the Reader has more to be read
        /// 
        private void HandleChoice(int elementDepth, ref bool more) 
        {
            if (!Scope.InAlternateContent) 
            { 
                // Choice must be the child of AlternateContent
                Error(SR.Get(SRID.XCRChoiceOnlyInAC)); 
            }
            if (Scope.FallbackSeen)
            {
                // Choice cannot occur after Fallback 
                Error(SR.Get(SRID.XCRChoiceAfterFallback));
            } 
 
            string requiresValue = Reader.GetAttribute(Requires);
 
            if (requiresValue == null)
            {
                // Choice must have a requires attribute
                Error(SR.Get(SRID.XCRRequiresAttribNotFound)); 
            }
            if (String.IsNullOrEmpty(requiresValue)) 
            { 
                // Requires attribute may not be empty
                Error(SR.Get(SRID.XCRInvalidRequiresAttribute)); 
            }

            CompatibilityScope scope = Scope;
 
            // check for markup-compatibility attributes
            ScanForCompatibility(elementDepth); 
 
            if (AttributeCount != 1)
            { 
                // Choice may not have any attribute that should not be ignored other than Requires
                // get first non-markup-compatibility, non-Requires attribute
                MoveToFirstAttribute();
                if(Reader.LocalName == Requires) 
                {
                    MoveToNextAttribute(); 
                } 
                string attributeName = Reader.LocalName;
                MoveToElement(); 

                Error(SR.Get(SRID.XCRInvalidAttribInElement), attributeName, Choice);
            }
 
            if (scope.ChoiceTaken)
            { 
                // a previous choice was valid, so pop any scope pushed and 
                // skip to next attribute after 
                ScanForEndCompatibility(elementDepth); 
                Reader.Skip();
            }
            else
            { 
                // mark AlternateContent as having seen a choice
                scope.ChoiceSeen = true; 
 
                bool allKnown = true;
                bool somethingSeen = false; 

                foreach (string namespaceUri in PrefixesToNamespaces(requiresValue))
                {
                    somethingSeen = true; 
                    if (!IsNamespaceKnown(namespaceUri))
                    { 
                        // if any attribute in the Requires value is unknown, then do not take this choice 
                        allKnown = false;
                        break; 
                    }
                }

                if (!somethingSeen) 
                {
                    // if the Requires value does not contain a valid prefix/namespace, throw an exception 
                    Error(SR.Get(SRID.XCRInvalidRequiresAttribute)); 
                }
 
                if (allKnown)
                {
                    // if all namespace in the Requires value are known, then this is the Choice taken.
                    // Mark AlternateContent scope as having taken a choice 
                    scope.ChoiceTaken = true;
 
                    // we push a scope here as a place holder, because AlternateContent 
                    // scopes do not allow child elements other than Choice and Fallback
                    PushScope(elementDepth); 
                    _depthOffset++;
                    more = Reader.Read();
                }
                else 
                {
                    // this is not the choice taken, so pop any scope pushed and 
                    // skip to next attribute after  
                    ScanForEndCompatibility(elementDepth);
                    Reader.Skip(); 
                }
            }
        }
 
        /// 
        /// handles mc:Fallback element 
        /// 
        /// a good way to think of AlternateContent blocks is as a switch/case
        /// statement.  The AlternateContent tag is like switch, Choice is like 
        /// case, and Fallback is like default.
        /// 
        /// 
        /// the depth of the Reader at the element currently being processed 
        /// 
        ///  
        /// returns whether the Reader has more to be read 
        /// 
        private void HandleFallback(int elementDepth, ref bool more) 
        {
            if (!Scope.InAlternateContent)
            {
                // Fallback must be the child of AlternateContent 
                Error(SR.Get(SRID.XCRFallbackOnlyInAC));
            } 
            if (!Scope.ChoiceSeen) 
            {
                // AlternateContent block must contain a Choice element 
                Error(SR.Get(SRID.XCRChoiceNotFound));
            }
            if (Scope.FallbackSeen)
            { 
                // AlternateContent block may only contain one Fallback child
                Error(SR.Get(SRID.XCRMultipleFallbackFound)); 
            } 

            // mark scope as having a fallback 
            Scope.FallbackSeen = true;
            bool choiceTaken = Scope.ChoiceTaken;

            // check for markup-compatibility attributes 
            ScanForCompatibility(elementDepth);
 
            if (AttributeCount != 0) 
            {
                // Fallback may not have any attribute that should not be ignored 
                // get first non-markup-compatibility attribute
                MoveToFirstAttribute();
                string attributeName = Reader.LocalName;
                MoveToElement(); 

                Error(SR.Get(SRID.XCRInvalidAttribInElement), attributeName, Fallback); 
            } 

            if (choiceTaken) 
            {
                // a choice was valid, so ignore contents
                ScanForEndCompatibility(elementDepth);
                Reader.Skip(); 
            }
            else 
            { 
                // this is the content that will be used, so push a scope
                if(!Reader.IsEmptyElement) 
                {
                    // we push a scope here as a place holder, because AlternateContent
                    // scopes do not allow child elements other than Choice and Fallback
                    PushScope(elementDepth); 
                    _depthOffset++;
                } 
                more = Reader.Read(); 
            }
        } 

        /// 
        /// handles mc:Ignorable="foo" attribute
        /// 
        /// Ignorable is used to indicate that the namespace the prefix is mapped to can
        /// be ignored, i.e. when the namespace/element or namespace/attribute occurs it 
        /// is not returned by the reader. 
        /// 
        private void HandleIgnorable(int elementDepth) 
        {
            PushScope(elementDepth);

            foreach (string namespaceUri in PrefixesToNamespaces(Reader.Value)) 
            {
                Scope.Ignorable(namespaceUri); 
            } 

            // Just in case one of the namespaces that preceded the Ignorable declaration 
            // was an ignorable namespace, we have to recompute _ignoredAttributeCount :Þ .
            // No need to check if we haven't yet had any non-ignored attributes.
            if (_ignoredAttributeCount < _attributePosition)
            { 
                _ignoredAttributeCount = 0;
                Reader.MoveToFirstAttribute(); 
 
                for (int i = 0; i < _attributePosition; i++)
                { 
                    if (ShouldIgnoreNamespace(Reader.NamespaceURI))
                    {
                        _ignoredAttributeCount++;
                    } 

                    Reader.MoveToNextAttribute(); 
                } 
            }
        } 

        /// 
        /// handles mc:MustUnderstand="foo" attribute
        /// 
        /// MustUnderstand is used to indicate that the namespace the prefix is mapped to
        /// cannot be handled, and if it is not understood an exception is thrown 
        ///  
        private void HandleMustUnderstand(int elementDepth)
        { 
            foreach (string namespaceUri in PrefixesToNamespaces(Reader.Value))
            {
                if (!IsNamespaceKnown(namespaceUri))
                { 
                    Error(SR.Get(SRID.XCRMustUnderstandFailed), namespaceUri);
                } 
            } 
        }
 
        /// 
        /// handles mc:ProcessContent="foo:bar" attribute
        ///
        /// ProcessContent is used to indicate that an ignorable namespace has some 
        /// elements that should be skipped, but contain child elements that should be processed.
        /// 
        /// The wildcard token ("foo:*") indicates that the children of any element in that 
        /// namespace should be processed.
        ///  
        private void HandleProcessContent(int elementDepth)
        {
            PushScope(elementDepth);
 
            foreach (NamespaceElementPair pair in ParseContentToNamespaceElementPair(Reader.Value, _processContent))
            { 
                Scope.ProcessContent(pair.namespaceName, pair.itemName); 
            }
        } 

        /// 
        /// handles mc:PreserveElements="foo:bar" attribute
        /// 
        /// functionality is supported, but not implemented
        ///  
        private void HandlePreserveElements(int elementDepth) 
        {
            PushScope(elementDepth); 

            foreach (NamespaceElementPair pair in ParseContentToNamespaceElementPair(Reader.Value, _preserveElements))
            {
                Scope.PreserveElement(pair.namespaceName, pair.itemName); 
            }
        } 
 
        /// 
        /// handles mc:PreserveAttributes="foo:bar" attribute 
        ///
        /// functionality is supported, but not implemented
        /// 
        private void HandlePreserveAttributes(int elementDepth) 
        {
            PushScope(elementDepth); 
 
            foreach (NamespaceElementPair pair in ParseContentToNamespaceElementPair(Reader.Value, _preserveAttributes))
            { 
                Scope.PreserveAttribute(pair.namespaceName, pair.itemName);
            }
        }
 
        /// 
        /// helper method to generate an exception 
        ///  
        private void Error(string message, params object[] args)
        { 
            IXmlLineInfo info = Reader as IXmlLineInfo;
            throw new XmlException(string.Format(CultureInfo.InvariantCulture, message, args), null, info == null ? 1 : info.LineNumber,
                info == null ? 1 : info.LinePosition);
        } 
        #endregion Private Methods
 
        #region Private Properties 
        private CompatibilityScope Scope
        { 
            get
            {
                return _compatibilityScope;
            } 
        }
 
        private string AlternateContent 
        {
            get 
            {
                if (_alternateContent == null)
                {
                    _alternateContent = Reader.NameTable.Add("AlternateContent"); 
                }
                return _alternateContent; 
            } 
        }
 
        private string Choice
        {
            get
            { 
                if (_choice == null)
                { 
                    _choice = Reader.NameTable.Add("Choice"); 
                }
                return _choice; 
            }
        }

        private string Fallback 
        {
            get 
            { 
                if (_fallback == null)
                { 
                    _fallback = Reader.NameTable.Add("Fallback");
                }
                return _fallback;
            } 
        }
 
        private string Requires 
        {
            get 
            {
                if (_requires == null)
                {
                    _requires = Reader.NameTable.Add("Requires"); 
                }
                return _requires; 
            } 
        }
 
        private string Ignorable
        {
            get
            { 
                if(_ignorable == null)
                { 
                    _ignorable = Reader.NameTable.Add("Ignorable"); 
                }
                return _ignorable; 
            }
        }

        private string MustUnderstand 
        {
            get 
            { 
                if(_mustUnderstand == null)
                { 
                    _mustUnderstand = Reader.NameTable.Add("MustUnderstand");
                }
                return _mustUnderstand;
            } 
        }
 
        private string ProcessContent 
        {
            get 
            {
                if(_processContent == null)
                {
                    _processContent = Reader.NameTable.Add("ProcessContent"); 
                }
                return _processContent; 
            } 
        }
 
        private string PreserveElements
        {
            get
            { 
                if(_preserveElements == null)
                { 
                    _preserveElements = Reader.NameTable.Add("PreserveElements"); 
                }
                return _preserveElements; 
            }
        }

        private string PreserveAttributes 
        {
            get 
            { 
                if(_preserveAttributes == null)
                { 
                    _preserveAttributes = Reader.NameTable.Add("PreserveAttributes");
                }
                return _preserveAttributes;
            } 
        }
 
        private string CompatibilityUri 
        {
            get 
            {
                if (_compatibilityUri == null)
                {
                    _compatibilityUri = Reader.NameTable.Add(MarkupCompatibilityURI); 
                }
                return _compatibilityUri; 
            } 
        }
        #endregion Private Properties 
        #region Nested Classes
        struct NamespaceElementPair
        {
            public string namespaceName; 
            public string itemName;
 
            public NamespaceElementPair(string namespaceName, string itemName) 
            {
                this.namespaceName = namespaceName; 
                this.itemName = itemName;
            }
        }
 
        /// 
        /// CompatibilityScopes are used to handle markup-compatibility elements and attributes. 
        /// Each scope stores the "previous" or parent scope, its depth, and an associated XmlCompatibilityReader. 
        /// At a particular Reader depth, only one scope should be pushed.
        ///  
        private class CompatibilityScope
        {
            CompatibilityScope _previous;
            int _depth; 
            bool _fallbackSeen;
            bool _inAlternateContent; 
            bool _inProcessContent; 
            bool _choiceTaken;
            bool _choiceSeen; 
            XmlCompatibilityReader _reader;
            Dictionary _ignorables;
            Dictionary _processContents;
            Dictionary _preserveElements; 
            Dictionary _preserveAttributes;
 
            public CompatibilityScope(CompatibilityScope previous, int depth, XmlCompatibilityReader reader) 
            {
                _previous = previous; 
                _depth = depth;
                _reader = reader;
            }
 
            public CompatibilityScope Previous
            { 
                get 
                {
                    return _previous; 
                }
            }

            public int Depth 
            {
                get 
                { 
                    return _depth;
                } 
            }

            public bool FallbackSeen
            { 
                get
                { 
                    bool result; 
                    if(_inProcessContent && _previous != null)
                    { 
                        result = _previous.FallbackSeen;
                    }
                    else
                    { 
                        result = _fallbackSeen;
                    } 
                    return result; 
                }
                set 
                {
                    if(_inProcessContent && _previous != null)
                    {
                        _previous.FallbackSeen = value; 
                    }
                    else 
                    { 
                        _fallbackSeen = value;
                    } 
                }
            }

            public bool InAlternateContent 
            {
                get 
                { 
                    bool result;
                    if(_inProcessContent && _previous != null) 
                    {
                        result = _previous.InAlternateContent;
                    }
                    else 
                    {
                        result = _inAlternateContent; 
                    } 
                    return result;
                } 
                set
                {
                    _inAlternateContent = value;
                } 
            }
 
            public bool InProcessContent 
            {
                set 
                {
                    _inProcessContent = value;
                }
            } 

            public bool ChoiceTaken 
            { 
                get
                { 
                    bool result;
                    if(_inProcessContent && _previous != null)
                    {
                        result = _previous.ChoiceTaken; 
                    }
                    else 
                    { 
                        result = _choiceTaken;
                    } 
                    return result;
                }
                set
                { 
                    if(_inProcessContent && _previous != null)
                    { 
                        _previous.ChoiceTaken = value; 
                    }
                    else 
                    {
                        _choiceTaken = value;
                    }
                } 
            }
 
            public bool ChoiceSeen 
            {
                get 
                {
                    bool result;
                    if(_inProcessContent && _previous != null)
                    { 
                        result = _previous.ChoiceSeen;
                    } 
                    else 
                    {
                        result = _choiceSeen; 
                    }
                    return result;
                }
                set 
                {
                    if(_inProcessContent && _previous != null) 
                    { 
                        _previous.ChoiceSeen = value;
                    } 
                    else
                    {
                        _choiceSeen = value;
                    } 
                }
            } 
 
            public bool CanIgnore(string namespaceName)
            { 
                bool result = IsIgnorableAtCurrentScope(namespaceName);

                if (!result && _previous != null)
                { 
                    result = _previous.CanIgnore(namespaceName);
                } 
 
                return result;
            } 

            public bool IsIgnorableAtCurrentScope(string namespaceName)
            {
                return _ignorables != null && _ignorables.ContainsKey(namespaceName); 
            }
 
            public bool ShouldProcessContent(string namespaceName, string elementName) 
            {
                bool result = false; 
                ProcessContentSet set;
                if (_processContents != null && _processContents.TryGetValue(namespaceName, out set))
                {
                    result = set.ShouldProcessContent(elementName); 
                }
                else if (_previous != null) 
                { 
                    result = _previous.ShouldProcessContent(namespaceName, elementName);
                } 

                return result;
            }
 
            public void Ignorable(string namespaceName)
            { 
                if (_ignorables == null) 
                {
                    _ignorables = new Dictionary(); 
                }
                _ignorables[namespaceName] = null; // we don't care about value, just key
            }
 
            public void ProcessContent(string namespaceName, string elementName)
            { 
                if (_processContents == null) 
                {
                    _processContents = new Dictionary(); 
                }
                ProcessContentSet processContentSet;
                if (!_processContents.TryGetValue(namespaceName, out processContentSet))
                { 
                    processContentSet = new ProcessContentSet(namespaceName, _reader);
                    _processContents.Add(namespaceName, processContentSet); 
                } 
                processContentSet.Add(elementName);
            } 

            public void PreserveElement(string namespaceName, string elementName)
            {
                if (_preserveElements == null) 
                {
                    _preserveElements = new Dictionary(); 
                } 
                PreserveItemSet preserveElementSet;
                if (!_preserveElements.TryGetValue(namespaceName, out preserveElementSet)) 
                {
                    preserveElementSet = new PreserveItemSet(namespaceName, _reader);
                    _preserveElements.Add(namespaceName, preserveElementSet);
                } 
                preserveElementSet.Add(elementName);
            } 
 
            public void PreserveAttribute(string namespaceName, string attributeName)
            { 
                if (_preserveAttributes == null)
                {
                    _preserveAttributes = new Dictionary();
                } 
                PreserveItemSet preserveAttributeSet;
                if (!_preserveAttributes.TryGetValue(namespaceName, out preserveAttributeSet)) 
                { 
                    preserveAttributeSet = new PreserveItemSet(namespaceName, _reader);
                    _preserveAttributes.Add(namespaceName, preserveAttributeSet); 
                }
                preserveAttributeSet.Add(attributeName);
            }
 
            /*public bool ShouldPreserveElement(string namespaceName, string elementName)
            { 
                bool result = _preserveItems != null && _preserveItems.ShouldPreserveElement(namespaceName, elementName); 
                if (!result && _previous != null)
                    result = _previous.ShouldPreserveElement(namespaceName, elementName); 
                return result;
            }

            public bool ShouldPreserveAttribute(string namespaceName, string attributeName) 
            {
                bool result = _preserveItems != null && _preserveItems.ShouldPreserveAttribute(namespaceName, attributeName); 
                if (!result && _previous != null) 
                    result = _previous.ShouldPreserveAttribute(namespaceName, attributeName);
                return result; 
            }*/

            public void Verify()
            { 
                // Check process content
                if (_processContents != null) 
                { 
                    foreach (string key in _processContents.Keys)
                    { 
                        if (!IsIgnorableAtCurrentScope(key))
                        {
                            _reader.Error(SR.Get(SRID.XCRNSProcessContentNotIgnorable), key);
                        } 
                    }
                } 
                // Check preserve elements 
                if (_preserveElements != null)
                { 
                    foreach (string key in _preserveElements.Keys)
                    {
                        if (!IsIgnorableAtCurrentScope(key))
                        { 
                            _reader.Error(SR.Get(SRID.XCRNSPreserveNotIgnorable), key);
                        } 
                    } 
                }
                // Check preserve attributes 
                if (_preserveAttributes != null)
                {
                    foreach (string key in _preserveAttributes.Keys)
                    { 
                        if (!IsIgnorableAtCurrentScope(key))
                        { 
                            _reader.Error(SR.Get(SRID.XCRNSPreserveNotIgnorable), key); 
                        }
                    } 
                }
            }
        }
 
        class ProcessContentSet
        { 
            bool _all; 
            string _namespaceName;
            XmlCompatibilityReader _reader; 
            Dictionary _names;

            public ProcessContentSet(string namespaceName, XmlCompatibilityReader reader)
            { 
                _namespaceName = namespaceName;
                _reader = reader; 
            } 

            public bool ShouldProcessContent(string elementName) 
            {
                return _all || (_names != null && _names.ContainsKey(elementName));
            }
 
            public void Add(string elementName)
            { 
                if (ShouldProcessContent(elementName)) 
                {
                    if (elementName == "*") 
                    {
                        _reader.Error(SR.Get(SRID.XCRDuplicateWildcardProcessContent), _namespaceName);
                    }
                    else 
                    {
                        _reader.Error(SR.Get(SRID.XCRDuplicateProcessContent), _namespaceName, elementName); 
                    } 
                }
 
                if (elementName == "*")
                {
                    if (_names != null)
                    { 
                        _reader.Error(SR.Get(SRID.XCRInvalidProcessContent), _namespaceName);
                    } 
                    else 
                    {
                        _all = true; 
                    }
                }
                else
                { 
                    if (_names == null)
                    { 
                        _names = new Dictionary(); 
                    }
 
                    _names[elementName] = null; // we don't care about value, just key
                }
            }
 
        }
 
        class PreserveItemSet 
        {
            bool _all; 
            string _namespaceName;
            XmlCompatibilityReader _reader;
            Dictionary _names;
 
            public PreserveItemSet(string namespaceName, XmlCompatibilityReader reader)
            { 
                _namespaceName = namespaceName; 
                _reader = reader;
            } 

            public bool ShouldPreserveItem(string itemName)
            {
                return _all || (_names != null && _names.ContainsKey(itemName)); 
            }
 
            public void Add(string itemName) 
            {
                if (ShouldPreserveItem(itemName)) 
                {
                    if (itemName == "*")
                    {
                        _reader.Error(SR.Get(SRID.XCRDuplicateWildcardPreserve), _namespaceName); 
                    }
                    else 
                    { 
                        _reader.Error(SR.Get(SRID.XCRDuplicatePreserve), itemName, _namespaceName);
                    } 
                }

                if (itemName == "*")
                { 
                    if (_names != null)
                    { 
                        _reader.Error(SR.Get(SRID.XCRInvalidPreserve), _namespaceName); 
                    }
                    else 
                    {
                        _all = true;
                    }
                } 
                else
                { 
                    if (_names == null) 
                    {
                        _names = new Dictionary(); 
                    }

                    _names.Add(itemName, itemName);
                } 
            }
        } 
        #endregion Nested Classes 

        #region Private Fields 
        private bool _inAttribute; // for Save/Restore ReaderPosition
        private string _currentName; // for Save/Restore ReaderPosition
        private IsXmlNamespaceSupportedCallback _namespaceCallback;
        private Dictionary _knownNamespaces = new Dictionary(); 
        private Dictionary _namespaceMap = new Dictionary();
        private Dictionary _subsumingNamespaces = new Dictionary(); 
        private Dictionary _elementHandler = new Dictionary(); 
        private Dictionary _attributeHandler = new Dictionary();
        private int _depthOffset; // offset for Depth method, to account for elements that should be ignored by client 
        private int _ignoredAttributeCount;
        private int _attributePosition; // used for ScanForCompatibility / HandleIgnorable
        private string _compatibilityUri;
        private string _alternateContent; 
        private string _choice;
        private string _fallback; 
        private string _requires; 
        private string _ignorable;
        private string _mustUnderstand; 
        private string _processContent;
        private string _preserveElements;
        private string _preserveAttributes;
        private CompatibilityScope _compatibilityScope; 

        private const string XmlnsDeclaration = "xmlns"; 
        private const string MarkupCompatibilityURI = "http://schemas.openxmlformats.org/markup-compatibility/2006"; 

        static private string [] _predefinedNamespaces = new string [4] { 
            "http://www.w3.org/2000/xmlns/",
            "http://www.w3.org/XML/1998/namespace",
            "http://www.w3.org/2001/XMLSchema-instance",
            MarkupCompatibilityURI 
        };
        #endregion Private Fields 
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.

                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK