SeekableMessageNavigator.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ WCF / WCF / 3.5.30729.1 / untmp / Orcas / SP / ndp / cdf / src / WCF / ServiceModel / System / ServiceModel / Dispatcher / SeekableMessageNavigator.cs / 1 / SeekableMessageNavigator.cs

                            //------------------------------------------------------------------------------ 
// Copyright (c) Microsoft Corporation.  All rights reserved.
//-----------------------------------------------------------------------------

namespace System.ServiceModel.Dispatcher 
{
    using System; 
    using System.ServiceModel.Channels; 
    using System.ServiceModel;
    using System.Collections; 
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Text;
    using System.Xml; 
    using System.Xml.XPath;
 
    // Anything marked 

 


    internal class SeekableMessageNavigator : SeekableXPathNavigator, INodeCounter
    { 
        // Use a single template for constructing the common elements.
        static Node[] BlankDom; 
 
        // Constants
        const string XmlP = "xml"; 
        const string XmlnsP = "xmlns";
        const string SoapP = "s";
        const string EnvelopeTag = MessageStrings.Envelope;
        const string HeaderTag = MessageStrings.Header; 
        const string BodyTag = MessageStrings.Body;
 
        // These constants are constructed from each other so new ones can be added without too much hastle. 
        const int NullIndex = 0;
        const int RootIndex = NullIndex + 1; 
        const int EnvelopeIndex = RootIndex + 1;
        const int SoapNSIndex = EnvelopeIndex + 1;
        const int XmlNSIndex = SoapNSIndex + 1;
        const int HeaderIndex = XmlNSIndex + 1; 
        const int FirstHeaderIndex = HeaderIndex + 1;
 
        const int StartSize = 50; // Blank nodes to start with 
        const int GrowFactor = 2; // Multiplier to grow the node array by
        const int StretchMax = 1000; // Use the multiplier until the node array gets this big 
        const int GrowInc = 1000; // Grow by this many nodes when StretchMax is exceeded

        // Shared as dom
        Message message; 
        MessageHeaders headers;
        XmlSpace space; 
        StringBuilder stringBuilder; 

        Node[] nodes; 
        int bodyIndex;
        int nextFreeIndex;

        NameTable nameTable; 
        bool includeBody;
        bool atomize; 
 
        // Shared as counter
        int nodeCount; 
        int nodeCountMax;

        // Instance
        SeekableMessageNavigator dom; 
        SeekableMessageNavigator counter;
        Stack nsStack; 
        int location; 
        int specialParent; // Always null if we're not at a namespace node
 
        static SeekableMessageNavigator()
        {
            BlankDom = new Node[HeaderIndex + 1];
 
            // Root
            BlankDom[RootIndex].type = XPathNodeType.Root; 
            BlankDom[RootIndex].firstChild = EnvelopeIndex; 
            BlankDom[RootIndex].prefix = string.Empty;
            BlankDom[RootIndex].name = string.Empty; 
            BlankDom[RootIndex].val = string.Empty;

            // Envelope
            BlankDom[EnvelopeIndex].type = XPathNodeType.Element; 
            BlankDom[EnvelopeIndex].prefix = SoapP;
            //BlankDom[EnvelopeIndex].ns = soapNS; 
            BlankDom[EnvelopeIndex].name = EnvelopeTag; 
            BlankDom[EnvelopeIndex].parent = RootIndex;
            BlankDom[EnvelopeIndex].firstChild = HeaderIndex; 
            BlankDom[EnvelopeIndex].firstNamespace = SoapNSIndex;

            // SOAP Namespace
            BlankDom[SoapNSIndex].type = XPathNodeType.Namespace; 
            BlankDom[SoapNSIndex].name = SoapP;
            //BlankDom[SoapNSIndex].val = soapNS; 
            BlankDom[SoapNSIndex].nextSibling = XmlNSIndex; 
            BlankDom[SoapNSIndex].parent = EnvelopeIndex;
 
            // xmlns:xml Namespace
            BlankDom[XmlNSIndex].type = XPathNodeType.Namespace;
            BlankDom[XmlNSIndex].name = "xml";
            BlankDom[XmlNSIndex].val = XmlUtil.XmlNs; 
            BlankDom[XmlNSIndex].prevSibling = SoapNSIndex;
            BlankDom[XmlNSIndex].parent = RootIndex; // This one needs to be connected a little different 
 
            // Header
            BlankDom[HeaderIndex].type = XPathNodeType.Element; 
            BlankDom[HeaderIndex].prefix = SoapP;
            //BlankDom[HeaderIndex].ns = soapNS;
            BlankDom[HeaderIndex].name = HeaderTag;
            BlankDom[HeaderIndex].parent = EnvelopeIndex; 
            //BlankDom[HeaderIndex].nextSibling = bodyIndex;
            //BlankDom[HeaderIndex].firstChild = this.bodyIndex != FirstHeaderIndex ? FirstHeaderIndex : NullIndex; 
            BlankDom[HeaderIndex].firstNamespace = SoapNSIndex; 

        } 

        internal SeekableMessageNavigator(SeekableMessageNavigator nav)
        {
            DiagnosticUtility.DebugAssert(nav != null, "Navigator may not be null"); 

            this.counter = nav.counter; 
            this.dom = nav.dom; 
            this.location = nav.location;
            this.specialParent = nav.specialParent; 
            if (this.specialParent != NullIndex)
            {
                this.nsStack = nav.CloneNSStack();
            } 
        }
 
        internal SeekableMessageNavigator(Message msg, int countMax, XmlSpace space, bool includeBody, bool atomize) 
        {
            Init(msg, countMax, space, includeBody, atomize); 
        }

        // The base uri of the element
        // This is usually associated with the URI of the original data's location 
        // WS, [....], look into what readers from messages surface.  If it's always null, we can save
        // some memory 
        public override string BaseURI 
        {
            get 
            {
                LoadOnDemand();
                string s = this.dom.nodes[this.location].baseUri;
                return s == null ? string.Empty : s; 
            }
        } 
 
        // Get/Set an opaque position value.
        // This property will save and restore a navigator's position without cloning 
        // The two integers needed to uniquely identify this navigators location within the DOM are encoded in
        // a long.  The high 32 bits is the parent index, and the low 32 bits is the current node index.
        public override long CurrentPosition
        { 
            get
            { 
                long p = this.specialParent; 
                p <<= 32;
                p += this.location; 
                return p;
            }
            set
            { 
                Position p = this.dom.DecodePosition(value);
 
                // If we are at a namespace, collect the namespaces that have already been seen 
                if (p.parent != NullIndex)
                { 
                    if(this.nsStack == null)
                    {
                        this.nsStack = new Stack();
                    } 
                    else
                    { 
                        this.nsStack.Clear(); 
                    }
 
                    int n = this.dom.nodes[p.parent].firstNamespace;

                    while (n != p.elem)
                    { 
                        // PERF, [....], we might be able to get rid of this check by tweaking the position
                        // validator 
                        if (n == NullIndex) 
                        {
                            throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new QueryProcessingException(QueryProcessingError.InvalidNavigatorPosition, SR.GetString(SR.SeekableMessageNavInvalidPosition))); 
                        }

                        this.nsStack.Push(this.dom.nodes[n].name);
                        n = this.dom.nodes[n].nextSibling; 
                    }
                } 
 
                this.location = p.elem;
                this.specialParent = p.parent; 
            }
        }

        // Returns whether the current node has any defined attributes. 
        public override bool HasAttributes
        { 
            get 
            {
                LoadOnDemand(); 
                return this.dom.nodes[this.location].firstAttribute != NullIndex;
            }
        }
 
        // Returns whether the current node has any children.
        public override bool HasChildren 
        { 
            get
            { 
                LoadOnDemand();
                return this.dom.nodes[this.location].firstChild != NullIndex;
            }
        } 

        // Returns whether the current node was defined as an empty element. 
        // This is not relevant to xpath, so we're saving memory by not recording the true value. 
        // If a reader does ever get wrapped around it, we'll have to fix this.
        public override bool IsEmptyElement 
        {
            get
            {
                //  is an empty element.   is not. 
                return this.dom.nodes[this.location].empty;
            } 
        } 

        // Return the local name of the current node. 
        public override string LocalName
        {
            get
            { 
                string s = this.dom.nodes[this.location].name;
                return s == null ? string.Empty : s; 
            } 
        }
 
        // Returns the message that was used to construct this navigator's DOM
        internal Message Message
        {
            get 
            {
                return this.dom.message; 
            } 
        }
 
        // Returns the qualified name of the current node
        public override string Name
        {
            get 
            {
                return GetName(this.location); 
            } 
        }
 
        // Returns the namespace URI of the current node
        public override string NamespaceURI
        {
            get 
            {
                string s = this.dom.nodes[this.location].ns; 
                return s == null ? string.Empty : s; 
            }
        } 

        // Returns the name table used to atomize strings in this navigator
        // If the DOM is not atomized, this will be null.
        public override XmlNameTable NameTable 
        {
            get 
            { 
                return this.dom.nameTable;
            } 
        }

        // Returns the type of the current node
        public override XPathNodeType NodeType 
        {
            get 
            { 
                return this.dom.nodes[this.location].type;
            } 
        }

        // Returns the prefix of the current node
        public override string Prefix 
        {
            get 
            { 
                LoadOnDemand();
                string s = this.dom.nodes[this.location].prefix; 
                return s == null ? string.Empty : s;
            }
        }
 
        // Returns the text value of the current node
        public override string Value 
        { 
            get
            { 
                return this.dom.GetValue(this.location);
            }
        }
 
        // Returns the value of xml:lang that is currently in scope.
        public override string XmlLang 
        { 
            get
            { 
                LoadOnDemand();
                string s = this.dom.nodes[this.location].xmlLang;
                return s == null ? string.Empty : s;
            } 
        }
 
#if NO 
        // The default value of xml:space for the DOM
        internal XmlSpace DefaultXmlSpace 
        {
            get
            {
                return this.dom.space; 
            }
        } 
 
        internal SeekableMessageNavigator DomNavigator
        { 
            get
            {
                return this.dom;
            } 
        }
#endif 
 
        // Create a clone of the current navigator that shares its DOM and node counter
        public override XPathNavigator Clone() 
        {
            return new SeekableMessageNavigator(this);
        }
 
        // Compare the current position to that of another navigator.
        public override XmlNodeOrder ComparePosition(XPathNavigator nav) 
        { 
            if(nav == null)
            { 
                return XmlNodeOrder.Unknown;
            }

            // We can only compare the positions of navigators of the same type. 
            SeekableMessageNavigator smnav = nav as SeekableMessageNavigator;
            if (smnav != null) 
            { 
                return ComparePosition(smnav);
            } 
            return XmlNodeOrder.Unknown;
        }

        // Compare the current position to that of another navigator. 
        internal XmlNodeOrder ComparePosition(SeekableMessageNavigator nav)
        { 
            if(nav == null) 
            {
                return XmlNodeOrder.Unknown; 
            }

            if (this.dom != nav.dom)
            { 
                return XmlNodeOrder.Unknown;
            } 
 
            return this.dom.ComparePosition(this.specialParent, this.location, nav.specialParent, nav.location);
        } 

        // Compare two position values that are valid for this navigator's DOM
        public override XmlNodeOrder ComparePosition(long pos1, long pos2)
        { 
            Position p1 = this.dom.DecodePosition(pos1);
            Position p2 = this.dom.DecodePosition(pos2); 
            return this.dom.ComparePosition(p1.parent, p1.elem, p2.parent, p2.elem); 
        }
 
        // Compile: We don't need to override this.  Seems like it could have even been static.

        // Evaluate an xpath expression against the current navigator
        public override object Evaluate(string xpath) 
        {
            // We can only evaluate atomized navigators 
            if (!this.dom.atomize) 
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperCritical(new QueryProcessingException(QueryProcessingError.NotAtomized, SR.GetString(SR.SeekableMessageNavNonAtomized, "Evaluate"))); 
            }
            return base.Evaluate(xpath);
        }
 
        // Evaluate an xpath expression against the current navigator
        public override object Evaluate(XPathExpression expr) 
        { 
            // We can only evaluate atomized navigators
            if (!this.dom.atomize) 
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperCritical(new QueryProcessingException(QueryProcessingError.NotAtomized, SR.GetString(SR.SeekableMessageNavNonAtomized, "Evaluate")));
            }
            return base.Evaluate(expr); 
        }
 
        // Evaluate an xpath expression against the current navigator 
        public override object Evaluate(XPathExpression expr, XPathNodeIterator context)
        { 
            // We can only evaluate atomized navigators
            if (!this.dom.atomize)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperCritical(new QueryProcessingException(QueryProcessingError.NotAtomized, SR.GetString(SR.SeekableMessageNavNonAtomized, "Evaluate"))); 
            }
            return base.Evaluate(expr, context); 
        } 

        // Get the value of an attribute with a particular name and namespace 
        public override string GetAttribute(string name, string ns)
        {
            if(name == null)
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("name");
            } 
 
            if(ns == null)
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("ns");
            }

            // We must be at an element node 
            if (this.NodeType != XPathNodeType.Element)
            { 
                return string.Empty; 
            }
 
            int a;
            string ret = string.Empty;
            Increase();
            LoadOnDemand(); 

            // Walk through the attributes looking for the one we want. 
            a = this.dom.nodes[this.location].firstAttribute; 
            while (a != NullIndex)
            { 
                if (String.CompareOrdinal(this.dom.nodes[a].name, name) == 0 && String.CompareOrdinal(this.dom.nodes[a].ns, ns) == 0)
                {
                    ret = this.dom.nodes[a].val;
                    break; 
                }
 
                Increase(); 
                a = this.dom.nodes[a].nextSibling;
            } 

            return ret;
        }
 
        // Returns the local name of the node defined by the given navigator position
        public override string GetLocalName(long pos) 
        { 
            string s = this.dom.nodes[this.dom.DecodePosition(pos).elem].name;
            return s == null ? string.Empty : s; 
        }

        // Returns the qualified name of the node defined by the given navigator position
        public override string GetName(long pos) 
        {
            return GetName(this.dom.DecodePosition(pos).elem); 
        } 

        // Returns the namespace uri of the node defined by the given navigator position 
        public override string GetNamespace(long pos)
        {
            string s = this.dom.nodes[this.dom.DecodePosition(pos).elem].ns;
            return s == null ? string.Empty : s; 
        }
 
        // Returns the namespace uri that is bound to the given prefix in the current scope, or the empty 
        // string if the prefix is not defined
        public override string GetNamespace(string name) 
        {
            if(name == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("name"); 
            }
 
            if (this.NodeType != XPathNodeType.Element) 
            {
                return string.Empty; 
            }

            int ns;
            Increase(); 
            LoadOnDemand();
            ns = this.dom.nodes[this.location].firstNamespace; 
            string ret = string.Empty; 

            while (ns != NullIndex) 
            {
                Increase();

                if (String.CompareOrdinal(this.dom.nodes[ns].name, name) == 0) 
                {
                    ret = this.dom.nodes[ns].val; 
                    break; 
                }
 
                ns = this.dom.nodes[ns].nextSibling;
            }

            return ret; 
        }
 
        // Returns the node type of the node defined by the given navigator position 
        public override XPathNodeType GetNodeType(long pos)
        { 
            return this.dom.nodes[this.dom.DecodePosition(pos).elem].type;
        }

        // Returns the string value of the node defined by the given navigator position 
        public override string GetValue(long pos)
        { 
            string s = this.dom.GetValue(this.dom.DecodePosition(pos).elem); 
            return s == null ? string.Empty : s;
        } 

        // Test whether the given navigator is positioned on a descendant of this navigator
        public override bool IsDescendant(XPathNavigator nav)
        { 
            if(nav == null)
            { 
                return false; 
            }
 
            // Navigator positions can only be compared if they are of the same type
            SeekableMessageNavigator smnav = nav as SeekableMessageNavigator;
            if (smnav != null)
            { 
                return IsDescendant(smnav);
            } 
            return false; 
        }
 
        // Test whether the given navigator is positioned on a descendant of this navigator
        internal bool IsDescendant(SeekableMessageNavigator nav)
        {
            if(nav == null) 
            {
                return false; 
            } 

            if (this.dom != nav.dom) 
            {
                return false;
            }
 
            // Namespaces and attributes are not considered descendants
            XPathNodeType type = this.dom.nodes[nav.location].type; 
            if (type == XPathNodeType.Namespace || type == XPathNodeType.Attribute) 
            {
                return false; 
            }

            // Namespaces and attributes are not parents
            type = this.dom.nodes[this.location].type; 
            if (type == XPathNodeType.Namespace || type == XPathNodeType.Attribute)
            { 
                return false; 
            }
 
            // Climb up the tree looking for the current navigator's position
            int n = nav.location;
            while (n != NullIndex)
            { 
                Increase();
                n = this.dom.nodes[n].parent; 
 
                if (n == this.location)
                { 
                    return true;
                }
            }
            return false; 
        }
 
        // Tests whether the given navigator is positioned on the same node as this navigator 
        public override bool IsSamePosition(XPathNavigator nav)
        { 
            if(nav == null)
            {
                return false;
            } 

            // Navigator positions can only be compared if they are of the same type 
            SeekableMessageNavigator smnav = nav as SeekableMessageNavigator; 
            if (smnav != null)
            { 
                return IsSamePosition(smnav);
            }
            return false;
        } 

        // Tests whether the given navigator is positioned on the same node as this navigator 
        internal bool IsSamePosition(SeekableMessageNavigator nav) 
        {
            if(nav == null) 
            {
                return false;
            }
 
            return this.dom == nav.dom && this.location == nav.location && this.specialParent == nav.specialParent;
        } 
 
        // Test if the given xpath matches this navigator
        public override bool Matches(string xpath) 
        {
            // We can only match atomized navigators
            if (!this.dom.atomize)
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperCritical(new QueryProcessingException(QueryProcessingError.NotAtomized, SR.GetString(SR.SeekableMessageNavNonAtomized, "Matches")));
            } 
            return base.Matches(xpath); 
        }
 
        // Test if the given xpath matches this navigator
        public override bool Matches(XPathExpression expr)
        {
            // We can only match atomized navigators 
            if (!this.dom.atomize)
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperCritical(new QueryProcessingException(QueryProcessingError.NotAtomized, SR.GetString(SR.SeekableMessageNavNonAtomized, "Matches"))); 
            }
            return base.Matches(expr); 
        }

        // Move this navigator to the same position as the given one
        public override bool MoveTo(XPathNavigator nav) 
        {
            if(nav == null) 
            { 
                return false;
            } 

            // Can only move to the position of a navigator of the same type
            SeekableMessageNavigator smnav = nav as SeekableMessageNavigator;
            if (smnav != null) 
            {
                return MoveTo(smnav); 
            } 
            return false;
        } 

        // Move this navigator to the same position as the given one
        internal bool MoveTo(SeekableMessageNavigator nav)
        { 
            if(nav == null)
            { 
                return false; 
            }
 
            this.dom = nav.dom;
            this.counter = nav.counter;
            this.location = nav.location;
            this.specialParent = nav.specialParent; 
            if (this.specialParent != NullIndex)
            { 
                this.nsStack = nav.CloneNSStack(); 
            }
 
            return true;
        }

        // Move this navigator to an attribute with the given name and namespace 
        public override bool MoveToAttribute(string localName, string namespaceURI)
        { 
            if(localName == null) 
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("localName"); 
            }

            if(namespaceURI == null)
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("namespaceURI");
            } 
 
            LoadOnDemand();
 
            // We must be positioned on an element
            if (this.dom.nodes[this.location].type != XPathNodeType.Element)
            {
                return false; 
            }
 
            // Move through the attributes looking for one that matches 
            Increase();
            int n = this.dom.nodes[this.location].firstAttribute; 
            while (n != NullIndex)
            {
                if (String.CompareOrdinal(this.dom.nodes[n].name, localName) == 0 &&
                    String.CompareOrdinal(this.dom.nodes[n].ns, namespaceURI) == 0) 
                {
                    // If we find it, we're done 
                    this.location = n; 
                    return true;
                } 
                else
                {
                    // Try the next one
                    Increase(); 
                    n = this.dom.nodes[n].nextSibling;
                } 
            } 

            // Didn't find it 
            return false;
        }

        // Move the navigator to the first sibling of the current node 
        public override bool MoveToFirst()
        { 
            // Not valid for attributes and namespaces 
            XPathNodeType t = this.dom.nodes[this.location].type;
            if (t != XPathNodeType.Attribute && t != XPathNodeType.Namespace) 
            {
                // Get the parent of the current node
                Increase();
                int p = this.dom.nodes[this.location].parent; 

                // If the parent was null, we're at the root (which has no siblings) 
                if (p != NullIndex) 
                {
                    // Move to the first child of our node's parent (ie, first sibling) 
                    // Cool, huh? :-)
                    Increase();
                    this.location = this.dom.nodes[p].firstChild;
                } 

                // The move is still considered successful if we were already there. 
                return true; 
            }
            return false; 
        }

        // Move the navigator to the first attribute of it's current element
        public override bool MoveToFirstAttribute() 
        {
            // Only valid for element nodes 
            if (this.dom.nodes[this.location].type != XPathNodeType.Element) 
            {
                return false; 
            }

            // Get the first attribute
            LoadOnDemand(); 
            int n = this.dom.nodes[this.location].firstAttribute;
 
            // The move was only successful if there is at least one attribute 
            if (n != NullIndex)
            { 
                Increase();
                this.location = n;
                return true;
            } 

            return false; 
        } 

        // Move the navigator to the first child of the current node. 
        public override bool MoveToFirstChild()
        {
            // PERF, [....], do we need this check?  The null check may be enough
            // Only valid for the root or an element node 
            if (this.location == RootIndex || this.dom.nodes[this.location].type == XPathNodeType.Element)
            { 
                // Get the first child 
                LoadOnDemand();
                int n = this.dom.nodes[this.location].firstChild; 

                // Only successful if there was at least one child
                if (n != NullIndex)
                { 
                    Increase();
                    this.location = n; 
                    return true; 
                }
            } 
            return false;
        }

        // Move the navigator to the first namespace that fits the scope 
        public override bool MoveToFirstNamespace(XPathNamespaceScope scope)
        { 
            // Only valid on element nodes 
            if (this.dom.nodes[this.location].type != XPathNodeType.Element)
            { 
                return false;
            }

            // Start with a clean namespace stack 
            if (this.nsStack == null)
            { 
                this.nsStack = new Stack(); 
            }
            else 
            {
                this.nsStack.Clear();
            }
 
            // Find the namespace
            LoadOnDemand(); 
            int n = FindNamespace(this.location, this.dom.nodes[this.location].firstNamespace, scope); 

            // If one was found, move there 
            if (n != NullIndex)
            {
                // Record the parent
                this.specialParent = this.location; 
                Increase();
                this.location = n; 
                return true; 
            }
            return false; 
        }

        // Move the navigator to the node with the given unique ID
        public override bool MoveToId(string id) 
        {
            // SOAP prohibits the inclusion of a DTD, so unique IDs cannot be defined. 
            throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new QueryProcessingException(QueryProcessingError.NotSupported, SR.GetString(SR.SeekableMessageNavIDNotSupported))); 
        }
 
        // Move the navigator to the namespace manager the given prefix
        public override bool MoveToNamespace(string name)
        {
            if(name == null) 
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("name"); 
            } 

            // Only valid from an element node 
            if (this.dom.nodes[this.location].type != XPathNodeType.Element)
            {
                return false;
            } 

            // Start with a clean namespace stack 
            if (this.nsStack == null) 
            {
                this.nsStack = new Stack(); 
            }
            else
            {
                this.nsStack.Clear(); 
            }
 
            Increase(); 
            LoadOnDemand();
 
            // Look through the namespaces for the specified prefix
            int n = this.dom.nodes[this.location].firstNamespace;
            string nodeName;
            string nodeVal; 
            int nsCount = 0;
            while (n != NullIndex) 
            { 
                // Skip any already defined prefixes
                nodeName = this.dom.nodes[n].name; 
                if (!this.nsStack.Contains(nodeName))
                {
                    this.nsStack.Push(nodeName);
                    ++nsCount; 
                    nodeVal = this.dom.nodes[n].val;
                    if ((nodeName.Length > 0 || nodeVal.Length > 0) && String.CompareOrdinal(nodeName, name) == 0) 
                    { 
                        this.specialParent = this.location;
                        this.location = n; 
                        return true;
                    }
                }
 
                // Try the next one
                Increase(); 
                n = this.dom.nodes[n].nextSibling; 
            }
 
            // PERF, [....], can we just clear?
            // We didn't find it, so restore the namespace stack
            for (int i = 0; i < nsCount; ++i)
            { 
                this.nsStack.Pop();
            } 
 
            return false;
        } 

        // Move the navigator to the next sibling
        public override bool MoveToNext()
        { 
            // Not valid for attribute/namespace nodes.  They have different 'next' functions.
            XPathNodeType type = this.dom.nodes[this.location].type; 
            if (type == XPathNodeType.Attribute || type == XPathNodeType.Namespace) 
            {
                return false; 
            }

            // Successful if there is a next sibling.
            int n = this.dom.nodes[this.location].nextSibling; 
            if (n != NullIndex)
            { 
                Increase(); 
                this.location = n;
                return true; 
            }

            return false;
        } 

        // Move the navigator to the next attribute node 
        public override bool MoveToNextAttribute() 
        {
            // Only valid on an attribute node 
            if (this.dom.nodes[this.location].type != XPathNodeType.Attribute)
            {
                return false;
            } 

            // Successful if there is a next sibling 
            int n = this.dom.nodes[this.location].nextSibling; 
            if (n != NullIndex)
            { 
                Increase();
                this.location = n;
                return true;
            } 

            return false; 
        } 

        // Move the navigator to the next namespace node in the specified scope 
        public override bool MoveToNextNamespace(XPathNamespaceScope scope)
        {
            // Only valid from a namespace node
            if (this.dom.nodes[this.location].type != XPathNodeType.Namespace) 
            {
                return false; 
            } 

            // Successful if the a namespace was found in the given scope 
            int n = FindNamespace(this.specialParent, this.dom.nodes[this.location].nextSibling, scope);
            if (n != NullIndex)
            {
                // Move to the namespace 
                Increase();
                this.location = n; 
                return true; 
            }
            return false; 
        }

        // Move the navigator to the parent of the current node
        public override bool MoveToParent() 
        {
            // The root node doesn't have a parent 
            if (this.location == RootIndex) 
            {
                return false; 
            }

            // Use the special parent if it's not null
            Increase(); 
            if (this.specialParent != NullIndex)
            { 
                Increase(); 
                this.location = this.specialParent;
                this.specialParent = NullIndex; 
            }
            else
            {
                this.location = this.dom.nodes[this.location].parent; 
            }
 
            return true; 
        }
 
        // Move the navigator to the previous sibling of the current node
        public override bool MoveToPrevious()
        {
            // Not valid for attribute/namespace nodes 
            int n = NullIndex;
            XPathNodeType t = this.dom.nodes[this.location].type; 
            if (t != XPathNodeType.Attribute && t != XPathNodeType.Namespace) 
            {
                n = this.dom.nodes[this.location].prevSibling; 
            }

            // Successful if there was a previous sibling
            if (n != NullIndex) 
            {
                Increase(); 
                this.location = n; 
                return true;
            } 
            return false;
        }

        // Move the navigator to the root node 
        public override void MoveToRoot()
        { 
            Increase(); 
            this.location = RootIndex;
            this.specialParent = NullIndex; 
        }

        // Select nodes from the navigator using the given xpath
        public override XPathNodeIterator Select(string xpath) 
        {
            // Cannot select from an unatomized navigator 
            if (!this.dom.atomize) 
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperCritical(new QueryProcessingException(QueryProcessingError.NotAtomized, SR.GetString(SR.SeekableMessageNavNonAtomized, "Select"))); 
            }
            return base.Select(xpath);
        }
 
        // Select nodes from the navigator using the given xpath
        public override XPathNodeIterator Select(XPathExpression xpath) 
        { 
            // Cannot select from an unatomized navigator
            if (!this.dom.atomize) 
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperCritical(new QueryProcessingException(QueryProcessingError.NotAtomized, SR.GetString(SR.SeekableMessageNavNonAtomized, "Select")));
            }
            return base.Select(xpath); 
        }
 
        // Select ancestor nodes from the navigator of a given type 
        public override XPathNodeIterator SelectAncestors(XPathNodeType type, bool matchSelf)
        { 
            // Cannot select from an unatomized navigator
            if (!this.dom.atomize)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperCritical(new QueryProcessingException(QueryProcessingError.NotAtomized, SR.GetString(SR.SeekableMessageNavNonAtomized, "SelectAncestors"))); 
            }
            return base.SelectAncestors(type, matchSelf); 
        } 

        // Select ancestor nodes from the navigator with a particular name and namespace 
        public override XPathNodeIterator SelectAncestors(string name, string namespaceURI, bool matchSelf)
        {
            // Cannot select from an unatomized navigator
            if (!this.dom.atomize) 
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperCritical(new QueryProcessingException(QueryProcessingError.NotAtomized, SR.GetString(SR.SeekableMessageNavNonAtomized, "SelectAncestors"))); 
            } 
            return base.SelectAncestors(name, namespaceURI, matchSelf);
        } 

        // Select child nodes of a certain type from the navigator
        public override XPathNodeIterator SelectChildren(XPathNodeType type)
        { 
            // Cannot select from an unatomized navigator
            if (!this.dom.atomize) 
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperCritical(new QueryProcessingException(QueryProcessingError.NotAtomized, SR.GetString(SR.SeekableMessageNavNonAtomized, "SelectChildren")));
            } 
            return base.SelectChildren(type);
        }

        // Select child nodes from the navigator with a certain name and namespace 
        public override XPathNodeIterator SelectChildren(string name, string namespaceURI)
        { 
            // Cannot select from an unatomized navigator 
            if (!this.dom.atomize)
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperCritical(new QueryProcessingException(QueryProcessingError.NotAtomized, SR.GetString(SR.SeekableMessageNavNonAtomized, "SelectChildren")));
            }
            return base.SelectChildren(name, namespaceURI);
        } 

        // Select descendant nodes of a certain type from the navigator 
        public override XPathNodeIterator SelectDescendants(XPathNodeType type, bool matchSelf) 
        {
            // Cannot select from an unatomized navigator 
            if (!this.dom.atomize)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperCritical(new QueryProcessingException(QueryProcessingError.NotAtomized, SR.GetString(SR.SeekableMessageNavNonAtomized, "SelectDescendants")));
            } 
            return base.SelectDescendants(type, matchSelf);
        } 
 
        // Selectg descendant nodes from the navigator with a certain name and namespace
        public override XPathNodeIterator SelectDescendants(string name, string namespaceURI, bool matchSelf) 
        {
            // Cannot select from an unatomized navigator
            if (!this.dom.atomize)
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperCritical(new QueryProcessingException(QueryProcessingError.NotAtomized, SR.GetString(SR.SeekableMessageNavNonAtomized, "SelectDescendants")));
            } 
            return base.SelectDescendants(name, namespaceURI, matchSelf); 
        }
 
        // ToString: Don't need to override this

        // Atomize the required strings if atomization was not enabled for this DOM
        // Calling this function permanently enables atomization for the DOM 
        internal void Atomize()
        { 
            if (!this.dom.atomize) 
            {
                this.dom.atomize = true; 
                this.dom.nameTable = new NameTable();
                this.dom.nameTable.Add(string.Empty);
                this.dom.Atomize(RootIndex, this.nextFreeIndex);
            } 
        }
 
        // Set a new count for this navigator 
        // Set it to use itself for the counter so all clones of it will share the new counter
        internal void ForkNodeCount(int count) 
        {
            DiagnosticUtility.DebugAssert(count > 0, "Maximum node count must be greater than zero");

            this.nodeCount = count; 
            this.nodeCountMax = count;
            this.counter = this; 
        } 

        // THREAD: Synchronize this function if multiple threads can try to re-initialize an instance at the same time.  Also, if you reinitialize the navigator that holds information referenced by clones, the clones will be affected as well. 
        internal void Init(Message msg, int countMax, XmlSpace space, bool includeBody, bool atomize)
        {
            DiagnosticUtility.DebugAssert(countMax > 0, "Maximum node count must be greater than zero");
            this.counter = this; 
            this.nodeCount = countMax;
            this.nodeCountMax = countMax; 
 
            DiagnosticUtility.DebugAssert(msg != null, "Message may not be null");
            this.dom = this; 
            this.location = RootIndex;
            this.specialParent = NullIndex;
            this.includeBody = includeBody;
            this.message = msg; 
            this.headers = msg.Headers;
            this.space = space; 
            this.atomize = false; // Will get fixed at the end of this function 

            int minSize = msg.Headers.Count + FirstHeaderIndex + 1; 

            if (this.nodes == null || this.nodes.Length < minSize)
            {
                this.nodes = new Node[minSize + StartSize]; 
            }
            else 
            { 
                Array.Clear(this.nodes, 1, this.nextFreeIndex - 1);
            } 

            this.bodyIndex = minSize - 1;
            this.nextFreeIndex = minSize;
 
            // Use the static blank DOM to create the first few nodes
            Array.Copy(BlankDom, this.nodes, HeaderIndex + 1); 
 
            string soapNS = msg.Version.Envelope.Namespace;
            this.nodes[EnvelopeIndex].ns = soapNS; 
            this.nodes[SoapNSIndex].val = soapNS;
            this.nodes[HeaderIndex].ns = soapNS;

            this.nodes[HeaderIndex].nextSibling = bodyIndex; 
            this.nodes[HeaderIndex].firstChild = this.bodyIndex != FirstHeaderIndex ? FirstHeaderIndex : NullIndex;
 
            // Headers 
            if(msg.Headers.Count > 0)
            { 
                for (int i = FirstHeaderIndex, h = 0; h < msg.Headers.Count; ++i, ++h)
                {
                    this.nodes[i].type = XPathNodeType.Element;
                    this.nodes[i].parent = HeaderIndex; 
                    this.nodes[i].nextSibling = i + 1;
                    this.nodes[i].prevSibling = i - 1; 
 
                    // Extract the header block stub data
                    MessageHeaderInfo header = msg.Headers[h]; 
                    this.nodes[i].ns = header.Namespace;
                    this.nodes[i].name = header.Name;
                    this.nodes[i].firstChild = -1;
                } 
                this.nodes[FirstHeaderIndex].prevSibling = NullIndex;
                this.nodes[this.bodyIndex-1].nextSibling = NullIndex; 
            } 

            // Body 
            this.nodes[bodyIndex].type = XPathNodeType.Element;
            this.nodes[bodyIndex].prefix = SoapP;
            this.nodes[bodyIndex].ns = soapNS;
            this.nodes[bodyIndex].name = BodyTag; 
            this.nodes[bodyIndex].parent = EnvelopeIndex;
            this.nodes[bodyIndex].prevSibling = HeaderIndex; 
            this.nodes[bodyIndex].firstNamespace = SoapNSIndex; 
            this.nodes[bodyIndex].firstChild = -1; // Need to load
 
            // Atomize
            if (atomize)
            {
                Atomize(); 
            }
        } 
 
        // Add an attribute node
        // Must be called on the DOM object 
        void AddAttribute(int node, int attr)
        {
            // Since order just needs to be consistant, we can just push it on the front of the list
            this.nodes[attr].parent = node; 
            this.nodes[attr].nextSibling = this.nodes[node].firstAttribute;
            this.nodes[node].firstAttribute = attr; 
        } 

        // Append a node to another's set of children 
        // Must be called on the DOM object
        void AddChild(int parent, int child)
        {
            // What we do depends on whether there are alredy children 
            if (this.nodes[parent].firstChild == NullIndex)
            { 
                // Make the node the only child 
                this.nodes[parent].firstChild = child;
                this.nodes[child].parent = parent; 
            }
            else
            {
                // Make the new child the last sibling of the first child 
                AddSibling(this.nodes[parent].firstChild, child);
            } 
        } 

        // Add a namespace node 
        // Must be called on the DOM object
        void AddNamespace(int node, int ns)
        {
            // Since order just needs to be consistant, we can just push it on the front of the list 
            this.nodes[ns].parent = node;
            this.nodes[ns].nextSibling = this.nodes[node].firstNamespace; 
            this.nodes[node].firstNamespace = ns; 
        }
 
        // Make a node the last sibling of another node
        // Must be called on the DOM object
        void AddSibling(int node1, int node2)
        { 
            // Get the current last sibling
            int i = LastSibling(node1); 
 
            // Link the node in after the last sibling
            this.nodes[i].nextSibling = node2; 
            this.nodes[node2].prevSibling = i;
            this.nodes[node2].parent = this.nodes[i].parent;
        }
 
        // Atomize the necessary strings within a range of nodes.
        // Must be called on the DOM object 
        void Atomize(int first, int bound) 
        {
            string s; 
            for (; first < bound; ++first)
            {
                s = this.nodes[first].prefix;
                if (s != null) 
                {
                    this.nodes[first].prefix = this.nameTable.Add(s); 
                } 

                s = this.nodes[first].name; 
                if (s != null)
                {
                    this.nodes[first].name = this.nameTable.Add(s);
                } 

                s = this.nodes[first].ns; 
                if (s != null) 
                {
                    this.nodes[first].ns = this.nameTable.Add(s); 
                }
            }
        }
#if NO 
        // Verify that a given position is valid for the document, and throw if it is not.
        // The node referenced must already have been constructed 
        // Must be called on the DOM object 
        void CheckValidPosition(int elem, int parent)
        { 
            if (!IsValidPosition(elem, parent))
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new QueryProcessingException(QueryProcessingError.InvalidNavigatorPosition, SR.GetString(SR.SeekableMessageNavInvalidPosition)));
            } 
        }
#endif 
        // Create a copy of the current namespace stack 
        Stack CloneNSStack()
        { 
            Stack newStack = new Stack();

            foreach (string s in this.nsStack)
            { 
                newStack.Push(s);
            } 
 
            return newStack;
        } 

        // Compare the locations of two nodes in the DOM
        // This function assumes the nodes are both in the body or in the same header block
        XmlNodeOrder CompareLocation(int loc1, int loc2) 
        {
            if (loc1 == loc2) 
            { 
                return XmlNodeOrder.Same;
            } 
            else if (loc1 < loc2)
            {
                return XmlNodeOrder.Before;
            } 
            else
            { 
                return XmlNodeOrder.After; 
            }
        } 

        // Performs the actual position comparison.
        XmlNodeOrder ComparePosition(int p1, int loc1, int p2, int loc2)
        { 
            // Both namespaces of the same node
            if (p1 == p2 && p1 != NullIndex) 
            { 
                return CompareLocation(loc1, loc2);
            } 

            // Get the element of navigator 1
            int thisNode;
            if (p1 == NullIndex) 
            {
                if (this.nodes[loc1].type == XPathNodeType.Attribute) 
                { 
                    thisNode = this.nodes[loc1].parent;
                } 
                else
                {
                    thisNode = loc1;
                } 
            }
            else 
            { 
                thisNode = p1;
            } 

            // Get the element of navigator 2
            int thatNode;
            if (p2 == NullIndex) 
            {
                if (this.nodes[loc2].type == XPathNodeType.Attribute) 
                { 
                    thatNode = this.nodes[loc2].parent;
                } 
                else
                {
                    thatNode = loc2;
                } 
            }
            else 
            { 
                thatNode = p2;
            } 

            // If the elements are the same
            if (thisNode == thatNode)
            { 
                XPathNodeType type1 = this.nodes[loc1].type;
                XPathNodeType type2 = this.nodes[loc2].type; 
 
                // We already know they are not both namespaces.
 
                if (type1 == XPathNodeType.Namespace)
                {
                    if (type2 == XPathNodeType.Attribute)
                    { 
                        // Namespaces come before attributes
                        return XmlNodeOrder.Before; 
                    } 
                    else
                    { 
                        // loc2 is the element itself
                        return XmlNodeOrder.After;
                    }
                } 

                if (type2 == XPathNodeType.Namespace) 
                { 
                    if (type1 == XPathNodeType.Attribute)
                    { 
                        // Namespaces come before attributes
                        return XmlNodeOrder.After;
                    }
                    else 
                    {
                        // loc1 is the element itself 
                        return XmlNodeOrder.Before; 
                    }
                } 

            }

            // Need to find out which upper level element is the parent of each node 
            // Upper level elements are in document order
 
            int thisP = thisNode; 
            while (thisP > this.bodyIndex)
            { 
                thisP = this.nodes[thisP].parent;
            }

            int thatP = thatNode; 
            while (thatP > this.bodyIndex)
            { 
                thatP = this.nodes[thatP].parent; 
            }
 
            if (thisP == thatP)
            {
                return CompareLocation(loc1, loc2);
            } 
            else
            { 
                return CompareLocation(thisP, thatP); 
            }
        } 

        // Decompose the 'long' position into it's element and parent components
        // Must be called on the DOM node
        Position DecodePosition(long pos) 
        {
            Position p = new Position((int) pos, (int) (pos >> 32)); 
 
            // Make sure both nodes are valid
            if (p.elem > NullIndex && p.elem < this.nextFreeIndex) 
            {
                if (p.parent == NullIndex)
                {
                    return p; 
                }
 
                // If the parent is not null, make sure it is a valid parent and that the element is a namespace node 
                if (p.parent > NullIndex && p.parent < this.nextFreeIndex && this.nodes[p.parent].type == XPathNodeType.Element && this.nodes[p.elem].type == XPathNodeType.Namespace)
                { 
                    // Check that 'parent' is a descendant-or-self of elem->parent
                    int n = this.nodes[p.elem].parent;
                    int par = p.parent;
 
                    do
                    { 
                        if (par == n) 
                        {
                            return p; 
                        }

                        par = this.nodes[par].parent;
 
                    } while (par != NullIndex);
                } 
            } 

            throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new QueryProcessingException(QueryProcessingError.InvalidNavigatorPosition, SR.GetString(SR.SeekableMessageNavInvalidPosition))); 
        }

        // Get the index of the next namespace that matches the scope
        // This function populates the namespace stack too 
        // PERF, [....], see if we can have this function set the current location too
        int FindNamespace(int parent, int ns, XPathNamespaceScope scope) 
        { 
            bool done = false;
            int nsCount = 0; 

            // ns is the first one we try
            while (ns != NullIndex && !done)
            { 
                Increase();
 
                string nodeName, nodeVal; 

                // Skip any prefixes that are already defined 
                nodeName = this.dom.nodes[ns].name;
                if (this.nsStack.Contains(nodeName))
                {
                    ns = this.dom.nodes[ns].nextSibling; 
                    continue;
                } 
                this.nsStack.Push(nodeName); 
                ++nsCount;
 
                // Skip the node undefining the default namespace
                nodeVal = this.dom.nodes[ns].val;
                if (nodeName.Length == 0 && nodeVal.Length == 0)
                { 
                    continue;
                } 
 
                // See if the current namespace is in our scope
                switch (scope) 
                {
                    case XPathNamespaceScope.All:
                        done = true;
                        break; 

                    case XPathNamespaceScope.ExcludeXml: 
                        // If it's 'xml', keep looking 
                        if (String.CompareOrdinal(nodeName, XmlP) == 0)
                        { 
                            Increase();
                            ns = this.dom.nodes[ns].nextSibling;
                        }
                        else 
                        {
                            done = true; 
                        } 
                        break;
 
                    case XPathNamespaceScope.Local:
                        // If the node's parent is not the element we're searching from, we've exhausted
                        // the locally defined namespaces
                        if (this.dom.nodes[ns].parent != parent) 
                        {
                            ns = NullIndex; 
                        } 
                        else
                        { 
                            done = true;
                        }

                        break; 
                }
            } 
 
            // If we didn't find one, restore the namespace stack
            if (ns == NullIndex) 
            {
                for (int i = 0; i < nsCount; ++i)
                {
                    this.nsStack.Pop(); 
                }
            } 
 
            return ns;
        } 

        // Returns the qualified name of the given node
        string GetName(int elem)
        { 
            string p, n;
            LoadOnDemand(elem); 
            p = this.dom.nodes[elem].prefix; 
            n = this.dom.nodes[elem].name;
 
            if (p != null && p.Length > 0)
            {
                return p + ":" + n;
            } 
            return n;
        } 
 
        // Returns the string value of given node
        // If the value is null, it attempts to acquire it 
        // Must only be called on the DOM object
        string GetValue(int elem)
        {
            string val = this.nodes[elem].val; 
            if (val == null)
            { 
                if (this.stringBuilder == null) 
                {
                    this.stringBuilder = new StringBuilder(); 
                }
                else
                {
                    this.stringBuilder.Length = 0; 
                }
 
                GetValueDriver(elem); 

                string s = this.stringBuilder.ToString(); 
                this.nodes[elem].val = s;
                return s;
            }
            else 
            {
                return val; 
            } 
        }
 
        // Recursive function that collects up the string value of element nodes
        // Must only be called on the DOM object
        void GetValueDriver(int elem)
        { 
            string val;
            this.dom.LoadOnDemand(elem); 
            switch (this.nodes[elem].type) 
            {
                // The string value of Element/Root nodes is the concatination of the values of their children 
                case XPathNodeType.Element:
                case XPathNodeType.Root:
                    val = this.nodes[elem].val;
                    if (val == null) 
                    {
                        int n = this.nodes[elem].firstChild; 
                        while (n != NullIndex) 
                        {
                            Increase(); 
                            GetValueDriver(n);
                            n = this.nodes[n].nextSibling;
                        }
                    } 
                    else
                    { 
                        this.stringBuilder.Append(val); 
                    }
                    break; 

                // String value cannot be 'computed' for other node types.
                default:
                    this.stringBuilder.Append(this.nodes[elem].val); 
                    break;
            } 
        } 
#if NO
        // Checks if a node index is defined in the current DOM 
        // Must be called on the DOM object
        bool IsValidNode(int n, bool allowNull)
        {
            if (allowNull) 
            {
                return n >= NullIndex && n < this.dom.nextFreeIndex; 
            } 
            else
            { 
                return n > NullIndex && n < this.dom.nextFreeIndex;
            }
        }
 
        // Verify that a given position is valid for the document.
        // The node referenced must already have been constructed 
        // Must be called on the DOM object 
        bool IsValidPosition(int elem, int parent)
        { 
            // Make sure both nodes are valid
            if ( elem > NullIndex && elem < this.nextFreeIndex)
            {
                if (parent == NullIndex) 
                {
                    return true; 
                } 

                // If the parent is not null, make sure it is a valid parent 
                if (parent > NullIndex && parent < this.nextFreeIndex)
                {
                    // The parent must be an element node
                    if (this.nodes[parent].type != XPathNodeType.Element) 
                    {
                        return false; 
                    } 

                    // If the parent is not null, the element must be a namespace node 
                    if (this.nodes[elem].type != XPathNodeType.Namespace)
                    {
                        return false;
                    } 

                    // Check that 'parent' is a descendant-or-self of elem->parent 
                    int n = this.nodes[elem].parent; 

                    while (parent != n) 
                    {
                        parent = this.nodes[parent].parent;

                        if (parent == NullIndex) 
                        {
                            return false; 
                        } 
                    }
 
                    return true;
                }
            }
 
            return false;
        } 
#endif 
        // Find the last child of a node
        // Must be called on the DOM object 
        int LastChild(int n)
        {
            // See if there are any children
            n = this.nodes[n].firstChild; 
            if (n == NullIndex)
            { 
                return NullIndex; 
            }
 
            // Find the last sibling of the first child
            return LastSibling(n);
        }
 
        // Find the last sibling of a node
        // Must be called on the DOM object 
        int LastSibling(int n) 
        {
            // Walk down the list unitl we get to the end. 
            while (this.nodes[n].nextSibling != NullIndex)
            {
                n = this.nodes[n].nextSibling;
            } 
            return n;
        } 
 
        // Load the children of the body element
        // Must be called on the DOM object 
        void LoadBody()
        {
            if (!this.message.IsEmpty)
            { 
                // Get the body reader
                XmlReader reader = this.message.GetReaderAtBodyContents(); 
                if (reader.ReadState == ReadState.Initial) 
                {
                    reader.Read(); 
                }

                // Record where we start so we can atomize later
                int lower = this.nextFreeIndex; 

                // Load the children of the body element 
                ReadChildNodes(reader, this.bodyIndex, SoapNSIndex); 

                // Record where we finished 
                int upper = this.nextFreeIndex;

                // Atomize if necessary
                if (this.atomize) 
                {
                    Atomize(lower, upper); 
                } 
            }
        } 

        // Load the given header node
        // Must be called on the DOM object
        void LoadHeader(int self) 
        {
            // Get the header reader 
            XmlReader reader = this.headers.GetReaderAtHeader(self - FirstHeaderIndex); 
            if (reader.ReadState == ReadState.Initial)
            { 
                reader.Read();
            }

            // Record where we started so we can atomize later 
            int lower = this.nextFreeIndex;
 
            // Finish populating the header element 
            this.nodes[self].firstNamespace = SoapNSIndex;
            this.nodes[self].prefix = this.atomize ? this.nameTable.Add(reader.Prefix) : reader.Prefix; 
            this.nodes[self].baseUri = reader.BaseURI;
            this.nodes[self].xmlLang = reader.XmlLang;

            // We are ignoring any siblings the reader may try to surface. 
            // NullIndex will be returned when then next element is the closing tag
            if (!reader.IsEmptyElement) 
            { 
                ReadAttributes(self, reader);
                reader.Read(); 
                ReadChildNodes(reader, self, this.nodes[self].firstNamespace);
            }
            else
            { 
                ReadAttributes(self, reader);
            } 
 
            // Record where we finished
            int upper = this.nextFreeIndex; 

            // Atomize if necessary
            if (this.atomize)
            { 
                Atomize(lower, upper);
            } 
        } 

        // Make sure the current node is fully loaded into the DOM 
        // This function does not need to be called from the DOM object
        void LoadOnDemand()
        {
            this.dom.LoadOnDemand(this.location); 
        }
 
        // Make sure the given node is fully loaded into the DOM 
        // Must be called on the DOM object
        // THREAD: Synchronize this function to prevent multiple concurrent loads of the same element. 
        //         They will cause errors in the DOM structure.
        void LoadOnDemand(int elem)
        {
            // Bail if we're not at a loadable item 
            if (elem > this.bodyIndex || elem < FirstHeaderIndex)
            { 
                return; 
            }
 
            // Check for the 'unloaded' marker
            if (this.nodes[elem].firstChild == -1)
            {
                // Clear the 'unloaded' marker 
                this.nodes[elem].firstChild = 0;
 
                // Load as appropriate 
                if (elem == this.bodyIndex)
                { 
                    if (this.includeBody)
                    {
                        LoadBody();
                    } 
                    else
                    { 
                        // Throw an exception if we try to navigate into the body. 
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NavigatorInvalidBodyAccessException(SR.GetString(SR.SeekableMessageNavBodyForbidden)));
                    } 
                }
                else
                {
                    LoadHeader(elem); 
                }
            } 
            else if (elem == this.bodyIndex && !this.includeBody) 
            {
                // Throw an exception if we try to navigate into the body. 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NavigatorInvalidBodyAccessException(SR.GetString(SR.SeekableMessageNavBodyForbidden)));
            }
        }
 
        // Get the index of a new unused node
        // Perform an necessary resizing 
        // Must be called on the DOM object 
        // THREAD: Synchronize this function.  If LoadOnDemand is synchronized, it may be possible to avoid synchronizing this one.
        int NewNode() 
        {
            // Resize if necessary
            if (this.nextFreeIndex == this.nodes.Length)
            { 
                // Compute the new size for the node array
                int size; 
                if (this.nodes.Length <= StretchMax) 
                {
                    size = this.nodes.Length * GrowFactor; 
                }
                else
                {
                    size = this.nodes.Length + GrowInc; 
                }
 
                // Resize the node array 
                Node[] tmp = new Node[size];
                this.nodes.CopyTo(tmp, 0); 
                this.nodes = tmp;
            }

            // Return the index of the next free node 
            return this.nextFreeIndex++;
        } 
 
        // Read in the attributes/namespaces and attach them to their element
        // Must be called on the DOM object 
        void ReadAttributes(int elem, XmlReader reader)
        {
            int a, n;
            while (reader.MoveToNextAttribute()) 
            {
                if (QueryDataModel.IsAttribute(reader.NamespaceURI)) 
                { 
                    a = NewNode();
                    this.nodes[a].type = XPathNodeType.Attribute; 
                    this.nodes[a].prefix = reader.Prefix;
                    this.nodes[a].name = reader.LocalName;
                    this.nodes[a].ns = reader.NamespaceURI;
                    this.nodes[a].val = reader.Value; 
                    this.nodes[a].baseUri = reader.BaseURI;
                    this.nodes[a].xmlLang = reader.XmlLang; 
                    AddAttribute(elem, a); 
                }
                else 
                {
                    string name = reader.Prefix.Length == 0 ? string.Empty : reader.LocalName;

                    // It is illegal to override the 'xml' and 'xmlns' prefixes 
                    if (String.CompareOrdinal(name, XmlP) == 0 || String.CompareOrdinal(name, XmlnsP) == 0)
                    { 
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new QueryProcessingException(QueryProcessingError.InvalidNamespacePrefix, SR.GetString(SR.SeekableMessageNavOverrideForbidden, reader.Name))); 
                    }
 
                    n = NewNode();
                    this.nodes[n].type = XPathNodeType.Namespace;
                    this.nodes[n].name = name;
                    this.nodes[n].val = reader.Value; 
                    this.nodes[n].baseUri = reader.BaseURI;
                    this.nodes[n].xmlLang = reader.XmlLang; 
                    AddNamespace(elem, n); 
                }
            } 
        }

        // Load elements from a reader
        // Must be called on the DOM object 
        int ReadChildNodes(XmlReader reader, int parent, int parentNS)
        { 
            DiagnosticUtility.DebugAssert(reader != null, "Reader cannot be null"); 

            // Loop over all nodes being surfaced 
            int n = NullIndex;
            do
            {
                // PERF, [....], reorder cases so more common ones are earlier 
                switch (reader.NodeType)
                { 
                    case XmlNodeType.Element: 
                        n = NewNode();
                        this.nodes[n].type = XPathNodeType.Element; 
                        this.nodes[n].prefix = reader.Prefix;
                        this.nodes[n].name = reader.LocalName;
                        this.nodes[n].ns = reader.NamespaceURI;
                        this.nodes[n].firstNamespace = parentNS; 
                        this.nodes[n].baseUri = reader.BaseURI;
                        this.nodes[n].xmlLang = reader.XmlLang; 
 
                        // Empty elements don't surface closing tags so they need to be handled differently
                        if (!reader.IsEmptyElement) 
                        {
                            ReadAttributes(n, reader);
                            reader.Read();
                            ReadChildNodes(reader, n, this.nodes[n].firstNamespace); 
                        }
                        else 
                        { 
                            ReadAttributes(n, reader);
                            this.nodes[n].empty = true; 
                        }

                        AddChild(parent, n);
                        break; 

                    case XmlNodeType.Comment: 
                        n = NewNode(); 
                        this.nodes[n].type = XPathNodeType.Comment;
                        this.nodes[n].val = reader.Value; 
                        this.nodes[n].baseUri = reader.BaseURI;
                        this.nodes[n].xmlLang = reader.XmlLang;
                        AddChild(parent, n);
                        break; 

                    case XmlNodeType.ProcessingInstruction: 
                        n = NewNode(); 
                        this.nodes[n].type = XPathNodeType.ProcessingInstruction;
                        this.nodes[n].name = reader.LocalName; 
                        this.nodes[n].val = reader.Value;
                        this.nodes[n].baseUri = reader.BaseURI;
                        this.nodes[n].xmlLang = reader.XmlLang;
                        AddChild(parent, n); 
                        break;
 
                    case XmlNodeType.SignificantWhitespace: 
                        if (reader.XmlSpace == XmlSpace.Preserve)
                        { 
                            // If we're preserving whitespace, try to append it to a text node instead
                            // of creating a new node
                            n = LastChild(parent);
                            if (n != NullIndex && (this.nodes[n].type == XPathNodeType.Text || 
                                this.nodes[n].type == XPathNodeType.Whitespace ||
                                this.nodes[n].type == XPathNodeType.SignificantWhitespace)) 
                            { 
                                this.nodes[n].val = this.nodes[n].val + reader.Value;
                            } 
                            else
                            {
                                n = NewNode();
                                this.nodes[n].type = XPathNodeType.SignificantWhitespace; 
                                this.nodes[n].val = reader.Value;
                                this.nodes[n].baseUri = reader.BaseURI; 
                                this.nodes[n].xmlLang = reader.XmlLang; 
                                AddChild(parent, n);
                            } 
                        }
                        else
                        {
                            goto case XmlNodeType.Whitespace; 
                        }
                        break; 
 
                    case XmlNodeType.Whitespace:
                        if (this.space == XmlSpace.Preserve) 
                        {
                            // If we're preserving whitespace, try to append it to a text node instead
                            // of creating a new node
                            n = LastChild(parent); 
                            if (n != NullIndex && (this.nodes[n].type == XPathNodeType.Text ||
                                this.nodes[n].type == XPathNodeType.Whitespace || 
                                this.nodes[n].type == XPathNodeType.SignificantWhitespace)) 
                            {
                                this.nodes[n].val = this.nodes[n].val + reader.Value; 
                            }
                            else
                            {
                                n = NewNode(); 
                                this.nodes[n].type = XPathNodeType.Whitespace;
                                this.nodes[n].val = reader.Value; 
                                this.nodes[n].baseUri = reader.BaseURI; 
                                this.nodes[n].xmlLang = reader.XmlLang;
                                AddChild(parent, n); 
                            }
                        }
                        break;
 
                    case XmlNodeType.CDATA:
                    case XmlNodeType.Text: 
                        // Try to append it to a text node instead of creating a new node 
                        n = LastChild(parent);
                        if (n == NullIndex || (this.nodes[n].type != XPathNodeType.Text && 
                            this.nodes[n].type != XPathNodeType.Whitespace &&
                            this.nodes[n].type != XPathNodeType.SignificantWhitespace))
                        {
                            n = NewNode(); 
 					
					 
					 
					
                            this.nodes[n].baseUri = reader.BaseURI; 
                            this.nodes[n].xmlLang = reader.XmlLang;
                            AddChild(parent, n);
                        }
                        this.nodes[n].type = XPathNodeType.Text; 
                        this.nodes[n].val = reader.Value;
                        break; 
 
                    case XmlNodeType.EntityReference:
                        reader.ResolveEntity(); 
                        reader.Read();
                        ReadChildNodes(reader, parent, parentNS);
 					
					 
 					
 					 
                        break; 

                    case XmlNodeType.EndEntity: 
                    case XmlNodeType.EndElement:
                    case XmlNodeType.None:
                        return n;
 
                    case XmlNodeType.DocumentType:
                        break; 
 
                    case XmlNodeType.XmlDeclaration:
                    default: 
                        break;
                }
            } while (reader.Read());
 
            return n;
        } 
 
        int INodeCounter.CounterMarker
        { 
            get
            {
                return this.counter.nodeCount;
            } 
            set
            { 
                this.counter.nodeCount = value; 
            }
        } 

        int INodeCounter.MaxCounter
        {
            set 
            {
                this.counter.nodeCountMax = value; 
            } 
        }
 
        int INodeCounter.ElapsedCount(int marker)
        {
            return marker - this.counter.nodeCount;
        } 

        void Increase() 
        { 
            DiagnosticUtility.DebugAssert(this.counter != null, "Counter reference is null");
            if (this.counter.nodeCount > 0) 
            {
                --this.counter.nodeCount;
            }
            else 
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XPathNavigatorException(SR.GetString(SR.FilterNodeQuotaExceeded, this.counter.nodeCountMax))); 
            } 
        }
 
        // PERF, [....], find a better way to implement and have internal
        void INodeCounter.Increase()
        {
            Increase(); 
        }
 
        void INodeCounter.IncreaseBy(int count) 
        {
            this.counter.nodeCount -= (count - 1); 
            Increase();
        }

        struct Node 
        {
            // Connectivity 
            internal int parent; 
            internal int firstAttribute;
            internal int firstChild; 
            internal int firstNamespace;
            internal int nextSibling;
            internal int prevSibling;
 
            // Data
            internal string baseUri; 
            internal bool empty; 
            internal string name;
            internal string ns; 
            internal string prefix;
            internal string val;
            internal string xmlLang;
 
            // Type
            internal XPathNodeType type; 
        } 

        struct Position 
        {
            internal int elem;
            internal int parent;
 
            internal Position(int e, int p)
            { 
                this.elem = e; 
                this.parent = p;
            } 
        }
    }
}

// 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