XmlQueryRuntime.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / whidbey / NetFXspW7 / ndp / fx / src / XmlUtils / System / Xml / Xsl / Runtime / XmlQueryRuntime.cs / 1 / XmlQueryRuntime.cs

                            //------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// [....] 
//-----------------------------------------------------------------------------
using System; 
using System.IO; 
using System.Xml;
using System.Xml.XPath; 
using System.Xml.Schema;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics; 
using System.Text;
using System.Globalization; 
using System.Reflection; 
using System.Reflection.Emit;
using System.Xml.Xsl.Qil; 
using System.Xml.Xsl.IlGen;
using System.ComponentModel;
using MS.Internal.Xml.XPath;
 
namespace System.Xml.Xsl.Runtime {
    using Res = System.Xml.Utils.Res; 
 
    /// 
    /// XmlQueryRuntime is passed as the first parameter to all generated query methods. 
    ///
    /// XmlQueryRuntime contains runtime support for generated ILGen queries:
    ///   1. Stack of output writers (stack handles nested document construction)
    ///   2. Manages list of all xml types that are used within the query 
    ///   3. Manages list of all atomized names that are used within the query
    ///  
    [EditorBrowsable(EditorBrowsableState.Never)] 
    public sealed class XmlQueryRuntime {
        // Early-Bound Library Objects 
        private XmlQueryContext ctxt;
        private XsltLibrary xsltLib;
        private EarlyBoundInfo[] earlyInfo;
        private object[] earlyObjects; 

        // Global variables and parameters 
        private string[] globalNames; 
        private object[] globalValues;
 
        // Names, prefix mappings, and name filters
        private XmlNameTable nameTableQuery;
        private string[] atomizedNames;             // Names after atomization
        private XmlNavigatorFilter[] filters;       // Name filters (contain atomized names) 
        private StringPair[][] prefixMappingsList;  // Lists of prefix mappings (used to resolve computed names)
 
        // Xml types 
        private XmlQueryType[] types;
 
        // Collations
        private XmlCollation[] collations;

        // Document ordering 
        private DocumentOrderComparer docOrderCmp;
 
        // Indexes 
        private ArrayList[] indexes;
 
        // Output construction
        private XmlQueryOutput output;
        private Stack stkOutput;
 

        //----------------------------------------------- 
        // Constructors 
        //-----------------------------------------------
 
        /// 
        /// This constructor is internal so that external users cannot construct it (and therefore we do not have to test it separately).
        /// 
        internal XmlQueryRuntime(XmlQueryStaticData data, object defaultDataSource, XmlResolver dataSources, XsltArgumentList argList, XmlSequenceWriter seqWrt) { 
            Debug.Assert(data != null);
            string[] names = data.Names; 
            Int32Pair[] filters = data.Filters; 
            WhitespaceRuleLookup wsRules;
            int i; 

            // Early-Bound Library Objects
            wsRules = (data.WhitespaceRules != null && data.WhitespaceRules.Count != 0) ? new WhitespaceRuleLookup(data.WhitespaceRules) : null;
            this.ctxt = new XmlQueryContext(this, defaultDataSource, dataSources, argList, wsRules); 
            this.xsltLib = null;
            this.earlyInfo = data.EarlyBound; 
            this.earlyObjects = (this.earlyInfo != null) ? new object[earlyInfo.Length] : null; 

            // Global variables and parameters 
            this.globalNames = data.GlobalNames;
            this.globalValues = (this.globalNames != null) ? new object[this.globalNames.Length] : null;

            // Names 
            this.nameTableQuery = this.ctxt.QueryNameTable;
            this.atomizedNames = null; 
 
            if (names != null) {
                // Atomize all names in "nameTableQuery".  Use names from the default data source's 
                // name table when possible.
                XmlNameTable nameTableDefault = ctxt.DefaultNameTable;
                this.atomizedNames = new string[names.Length];
 
                if (nameTableDefault != this.nameTableQuery && nameTableDefault != null) {
                    // Ensure that atomized names from the default data source are added to the 
                    // name table used in this query 
                    for (i = 0; i < names.Length; i++) {
                        string name = nameTableDefault.Get(names[i]); 
                        this.atomizedNames[i] = this.nameTableQuery.Add(name ?? names[i]);
                    }
                }
                else { 
                    // Enter names into nametable used in this query
                    for (i = 0; i < names.Length; i++) 
                        this.atomizedNames[i] = this.nameTableQuery.Add(names[i]); 
                }
            } 

            // Name filters
            this.filters = null;
            if (filters != null) { 
                // Construct name filters.  Each pair of integers in the filters[] array specifies the
                // (localName, namespaceUri) of the NameFilter to be created. 
                this.filters = new XmlNavigatorFilter[filters.Length]; 

                for (i = 0; i < filters.Length; i++) 
                    this.filters[i] = XmlNavNameFilter.Create(this.atomizedNames[filters[i].Left], this.atomizedNames[filters[i].Right]);
            }

            // Prefix maping lists 
            this.prefixMappingsList = data.PrefixMappingsList;
 
            // Xml types 
            this.types = data.Types;
 
            // Xml collations
            this.collations = data.Collations;

            // Document ordering 
            this.docOrderCmp = new DocumentOrderComparer();
 
            // Indexes 
            this.indexes = null;
 
            // Output construction
            this.stkOutput = new Stack(16);
            this.output = new XmlQueryOutput(this, seqWrt);
        } 

 
        //----------------------------------------------- 
        // Debugger Utility Methods
        //----------------------------------------------- 

        /// 
        /// Return array containing the names of all the global variables and parameters used in this query, in this format:
        ///     {namespace}prefix:local-name 
        /// 
        public string[] DebugGetGlobalNames() { 
            return this.globalNames; 
        }
 
        /// 
        /// Get the value of a global value having the specified name.  Always return the global value as a list of XPathItem.
        /// Return null if there is no global value having the specified name.
        ///  
        public IList DebugGetGlobalValue(string name) {
            for (int idx = 0; idx < this.globalNames.Length; idx++) { 
                if (this.globalNames[idx] == name) { 
                    Debug.Assert(IsGlobalComputed(idx), "Cannot get the value of a global value until it has been computed.");
                    Debug.Assert(this.globalValues[idx] is IList, "Only debugger should call this method, and all global values should have type item* in debugging scenarios."); 
                    return (IList) this.globalValues[idx];
                }
            }
            return null; 
        }
 
        ///  
        /// Set the value of a global value having the specified name.  If there is no such value, this method is a no-op.
        ///  
        public void DebugSetGlobalValue(string name, object value) {
            for (int idx = 0; idx < this.globalNames.Length; idx++) {
                if (this.globalNames[idx] == name) {
                    Debug.Assert(IsGlobalComputed(idx), "Cannot get the value of a global value until it has been computed."); 
                    Debug.Assert(this.globalValues[idx] is IList, "Only debugger should call this method, and all global values should have type item* in debugging scenarios.");
 
                    // Always convert "value" to a list of XPathItem using the item* converter 
                    this.globalValues[idx] = (IList) XmlAnyListConverter.ItemList.ChangeType(value, typeof(XPathItem[]), null);
                    break; 
                }
            }
        }
 
        /// 
        /// Convert sequence to it's appropriate XSLT type and return to caller. 
        ///  
        public object DebugGetXsltValue(IList seq) {
            if (seq != null && seq.Count == 1) { 
                XPathItem item = seq[0] as XPathItem;
                if (item != null && !item.IsNode) {
                    return item.TypedValue;
                } 
                else if (item is RtfNavigator) {
                    return ((RtfNavigator) item).ToNavigator(); 
                } 
            }
 
            return seq;
        }

 
        //-----------------------------------------------
        // Early-Bound Library Objects 
        //----------------------------------------------- 

        internal const BindingFlags EarlyBoundFlags     = BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static; 
        internal const BindingFlags LateBoundFlags      = BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static;

        /// 
        /// Return the object that manages external user context information such as data sources, parameters, extension objects, etc. 
        /// 
        public XmlQueryContext ExternalContext { 
            get { return this.ctxt; } 
        }
 
        /// 
        /// Return the object that manages the state needed to implement various Xslt functions.
        /// 
        public XsltLibrary XsltFunctions { 
            get {
                if (this.xsltLib == null) { 
                    this.xsltLib = new XsltLibrary(this); 
                }
 
                return this.xsltLib;
            }
        }
 
        /// 
        /// Get the early-bound extension object identified by "index".  If it does not yet exist, create an instance using the 
        /// corresponding ConstructorInfo. 
        /// 
        public object GetEarlyBoundObject(int index) { 
            object obj;
            Debug.Assert(this.earlyObjects != null && index < this.earlyObjects.Length, "Early bound object does not exist");

            obj = this.earlyObjects[index]; 
            if (obj == null) {
                // Early-bound object does not yet exist, so create it now 
                obj = this.earlyInfo[index].CreateObject(); 
                this.earlyObjects[index] = obj;
            } 

            return obj;
        }
 
        /// 
        /// Return true if the early bound object identified by "namespaceUri" contains a method that matches "name". 
        ///  
        public bool EarlyBoundFunctionExists(string name, string namespaceUri) {
            if (this.earlyInfo == null) 
                return false;

            for (int idx = 0; idx < this.earlyInfo.Length; idx++) {
                if (namespaceUri == this.earlyInfo[idx].NamespaceUri) 
                    return new XmlExtensionFunction(name, namespaceUri, -1, this.earlyInfo[idx].EarlyBoundType, EarlyBoundFlags).CanBind();
            } 
 
            return false;
        } 


        //-----------------------------------------------
        // Global variables and parameters 
        //-----------------------------------------------
 
        ///  
        /// Return true if the global value specified by idxValue was previously computed.
        ///  
        public bool IsGlobalComputed(int index) {
            return this.globalValues[index] != null;
        }
 
        /// 
        /// Return the value that is bound to the global variable or parameter specified by idxValue. 
        /// If the value has not yet been computed, then compute it now and store it in this.globalValues. 
        /// 
        public object GetGlobalValue(int index) { 
            Debug.Assert(IsGlobalComputed(index), "Cannot get the value of a global value until it has been computed.");
            return this.globalValues[index];
        }
 
        /// 
        /// Return the value that is bound to the global variable or parameter specified by idxValue. 
        /// If the value has not yet been computed, then compute it now and store it in this.globalValues. 
        /// 
        public void SetGlobalValue(int index, object value) { 
            Debug.Assert(!IsGlobalComputed(index), "Global value should only be set once.");
            this.globalValues[index] = value;
        }
 

        //----------------------------------------------- 
        // Names, prefix mappings, and name filters 
        //-----------------------------------------------
 
        /// 
        /// Return the name table used to atomize all names used by the query.
        /// 
        public XmlNameTable NameTable { 
            get { return this.nameTableQuery; }
        } 
 
        /// 
        /// Get the atomized name at the specified index in the array of names. 
        /// 
        public string GetAtomizedName(int index) {
            Debug.Assert(this.atomizedNames != null);
            return this.atomizedNames[index]; 
        }
 
        ///  
        /// Get the name filter at the specified index in the array of filters.
        ///  
        public XmlNavigatorFilter GetNameFilter(int index) {
            Debug.Assert(this.filters != null);
            return this.filters[index];
        } 

        ///  
        /// XPathNodeType.All: Filters all nodes 
        /// XPathNodeType.Attribute: Filters attributes
        /// XPathNodeType.Namespace: Not allowed 
        /// XPathNodeType.XXX: Filters all nodes *except* those having XPathNodeType.XXX
        /// 
        public XmlNavigatorFilter GetTypeFilter(XPathNodeType nodeType) {
            if (nodeType == XPathNodeType.All) 
                return XmlNavNeverFilter.Create();
 
            if (nodeType == XPathNodeType.Attribute) 
                return XmlNavAttrFilter.Create();
 
            return XmlNavTypeFilter.Create(nodeType);
        }

        ///  
        /// Parse the specified tag name (foo:bar) and resolve the resulting prefix.  If the prefix cannot be resolved,
        /// then throw an error.  Return an XmlQualifiedName. 
        ///  
        public XmlQualifiedName ParseTagName(string tagName, int indexPrefixMappings) {
            string prefix, localName, ns; 

            // Parse the tagName as a prefix, localName pair and resolve the prefix
            ParseTagName(tagName, indexPrefixMappings, out prefix, out localName, out ns);
            return new XmlQualifiedName(localName, ns); 
        }
 
        ///  
        /// Parse the specified tag name (foo:bar).  Return an XmlQualifiedName consisting of the parsed local name
        /// and the specified namespace. 
        /// 
        public XmlQualifiedName ParseTagName(string tagName, string ns) {
            string prefix, localName;
 
            // Parse the tagName as a prefix, localName pair
            ValidateNames.ParseQNameThrow(tagName, out prefix, out localName); 
            return new XmlQualifiedName(localName, ns); 
        }
 
        /// 
        /// Parse the specified tag name (foo:bar) and resolve the resulting prefix.  If the prefix cannot be resolved,
        /// then throw an error.  Return the prefix, localName, and namespace URI.
        ///  
        internal void ParseTagName(string tagName, int idxPrefixMappings, out string prefix, out string localName, out string ns) {
            Debug.Assert(this.prefixMappingsList != null); 
 
            // Parse the tagName as a prefix, localName pair
            ValidateNames.ParseQNameThrow(tagName, out prefix, out localName); 

            // Map the prefix to a namespace URI
            ns = null;
            foreach (StringPair pair in this.prefixMappingsList[idxPrefixMappings]) { 
                if (prefix == pair.Left) {
                    ns = pair.Right; 
                    break; 
                }
            } 

            // Throw exception if prefix could not be resolved
            if (ns == null) {
                // Check for mappings that are always in-scope 
                if (prefix.Length == 0)
                    ns = ""; 
                else if (prefix.Equals("xml")) 
                    ns = XmlReservedNs.NsXml;
                else if (prefix.Equals("xmlns")) 
                    ns = XmlReservedNs.NsXmlNs;
                else
                    throw new XslTransformException(Res.Xslt_InvalidPrefix, prefix);
            } 
        }
 
        ///  
        /// Return true if the nav1's LocalName and NamespaceURI properties equal nav2's corresponding properties.
        ///  
        public bool IsQNameEqual(XPathNavigator n1, XPathNavigator n2) {
            if ((object) n1.NameTable == (object) n2.NameTable) {
                // Use atomized comparison
                return (object) n1.LocalName == (object) n2.LocalName && (object) n1.NamespaceURI == (object) n2.NamespaceURI; 
            }
 
            return (n1.LocalName == n2.LocalName) && (n1.NamespaceURI == n2.NamespaceURI); 
        }
 
        /// 
        /// Return true if the specified navigator's LocalName and NamespaceURI properties equal the argument names.
        /// 
        public bool IsQNameEqual(XPathNavigator navigator, int indexLocalName, int indexNamespaceUri) { 
            if ((object) navigator.NameTable == (object) this.nameTableQuery) {
                // Use atomized comparison 
                return ((object) GetAtomizedName(indexLocalName) == (object) navigator.LocalName && 
                        (object) GetAtomizedName(indexNamespaceUri) == (object) navigator.NamespaceURI);
            } 

            // Use string comparison
            return (GetAtomizedName(indexLocalName) == navigator.LocalName) && (GetAtomizedName(indexNamespaceUri) == navigator.NamespaceURI);
        } 

 
        //----------------------------------------------- 
        // Xml types
        //----------------------------------------------- 

        /// 
        /// Get the array of xml types that are used within this query.
        ///  
        internal XmlQueryType[] XmlTypes {
            get { return this.types; } 
        } 

        ///  
        /// Get the Xml query type at the specified index in the array of types.
        /// 
        internal XmlQueryType GetXmlType(int idxType) {
            Debug.Assert(this.types != null); 
            return this.types[idxType];
        } 
 
        /// 
        /// Forward call to ChangeTypeXsltArgument(XmlQueryType, object, Type). 
        /// 
        public object ChangeTypeXsltArgument(int indexType, object value, Type destinationType) {
            return ChangeTypeXsltArgument(GetXmlType(indexType), value, destinationType);
        } 

        ///  
        /// Convert from the Clr type of "value" to Clr type "destinationType" using V1 Xslt rules. 
        /// These rules include converting any Rtf values to Nodes.
        ///  
        internal object ChangeTypeXsltArgument(XmlQueryType xmlType, object value, Type destinationType) {
            Debug.Assert(XmlILTypeHelper.GetStorageType(xmlType).IsAssignableFrom(value.GetType()),
                         "Values passed to ChangeTypeXsltArgument should be in ILGen's default Clr representation.");
            Debug.Assert(destinationType == XsltConvert.ObjectType || !destinationType.IsAssignableFrom(value.GetType()), 
                         "No need to call ChangeTypeXsltArgument since value is already assignable to destinationType " + destinationType);
 
            switch (xmlType.TypeCode) { 
                case XmlTypeCode.String:
                    if (destinationType == XsltConvert.DateTimeType) 
                        value = XsltConvert.ToDateTime((string) value);
                    break;

                case XmlTypeCode.Double: 
                    if (destinationType != XsltConvert.DoubleType)
                        value = Convert.ChangeType(value, destinationType, CultureInfo.InvariantCulture); 
                    break; 

                case XmlTypeCode.Node: 
                    Debug.Assert(xmlType != XmlQueryTypeFactory.Node && xmlType != XmlQueryTypeFactory.NodeS,
                                 "Rtf values should have been eliminated by caller.");

                    if (destinationType == XsltConvert.XPathNodeIteratorType) { 
                        value = new XPathArrayIterator((IList) value);
                    } 
                    else if (destinationType == XsltConvert.XPathNavigatorArrayType) { 
                        // Copy sequence to XPathNavigator[]
                        IList seq = (IList) value; 
                        XPathNavigator[] navArray = new XPathNavigator[seq.Count];

                        for (int i = 0; i < seq.Count; i++)
                            navArray[i] = seq[i]; 

                        value = navArray; 
                    } 
                    break;
 
                case XmlTypeCode.Item: {
                    // Only typeof(object) is supported as a destination type
                    if (destinationType != XsltConvert.ObjectType)
                        throw new XslTransformException(Res.Xslt_UnsupportedClrType, destinationType.Name); 

                    // Convert to default, backwards-compatible representation 
                    //   1. NodeSet: System.Xml.XPath.XPathNodeIterator 
                    //   2. Rtf: System.Xml.XPath.XPathNavigator
                    //   3. Other:   Default V1 representation 
                    IList seq = (IList) value;
                    if (seq.Count == 1) {
                        XPathItem item = seq[0];
 
                        if (item.IsNode) {
                            // Node or Rtf 
                            RtfNavigator rtf = item as RtfNavigator; 
                            if (rtf != null)
                                value = rtf.ToNavigator(); 
                            else
                                value = new XPathArrayIterator((IList) value);
                        }
                        else { 
                            // Atomic value
                            value = item.TypedValue; 
                        } 
                    }
                    else { 
                        // Nodeset
                        value = new XPathArrayIterator((IList) value);
                    }
                    break; 
                }
            } 
 
            Debug.Assert(destinationType.IsAssignableFrom(value.GetType()), "ChangeType from type " + value.GetType().Name + " to type " + destinationType.Name + " failed");
            return value; 
        }

        /// 
        /// Forward call to ChangeTypeXsltResult(XmlQueryType, object) 
        /// 
        public object ChangeTypeXsltResult(int indexType, object value) { 
            return ChangeTypeXsltResult(GetXmlType(indexType), value); 
        }
 
        /// 
        /// Convert from the Clr type of "value" to the default Clr type that ILGen uses to represent the xml type, using
        /// the conversion rules of the xml type.
        ///  
        internal object ChangeTypeXsltResult(XmlQueryType xmlType, object value) {
            if (value == null) 
                throw new XslTransformException(Res.Xslt_ItemNull, string.Empty); 

            switch (xmlType.TypeCode) { 
                case XmlTypeCode.String:
                    if (value.GetType() == XsltConvert.DateTimeType)
                        value = XsltConvert.ToString((DateTime) value);
                    break; 

                case XmlTypeCode.Double: 
                    if (value.GetType() != XsltConvert.DoubleType) 
                        value = ((IConvertible) value).ToDouble(null);
 
                    break;

                case XmlTypeCode.Node:
                    if (!xmlType.IsSingleton) { 
                        XPathArrayIterator iter = value as XPathArrayIterator;
 
                        // Special-case XPathArrayIterator in order to avoid copies 
                        if (iter != null && iter.AsList is XmlQueryNodeSequence) {
                            value = iter.AsList as XmlQueryNodeSequence; 
                        }
                        else {
                            // Iterate over list and ensure it only contains nodes
                            XmlQueryNodeSequence seq = new XmlQueryNodeSequence(); 
                            IList list = value as IList;
 
                            if (list != null) { 
                                for (int i = 0; i < list.Count; i++)
                                    seq.Add(EnsureNavigator(list[i])); 
                            }
                            else {
                                foreach (object o in (IEnumerable) value)
                                    seq.Add(EnsureNavigator(o)); 
                            }
 
                            value = seq; 
                        }
 
                        // Always sort node-set by document order
                        value = ((XmlQueryNodeSequence) value).DocOrderDistinct(this.docOrderCmp);
                    }
                    break; 

                case XmlTypeCode.Item: { 
                    Type sourceType = value.GetType(); 
                    IXPathNavigable navigable;
 
                    // If static type is item, then infer type based on dynamic value
                    switch (XsltConvert.InferXsltType(sourceType).TypeCode) {
                        case XmlTypeCode.Boolean:
                            value = new XmlQueryItemSequence(new XmlAtomicValue(XmlSchemaType.GetBuiltInSimpleType(XmlTypeCode.Boolean), value)); 
                            break;
 
                        case XmlTypeCode.Double: 
                            value = new XmlQueryItemSequence(new XmlAtomicValue(XmlSchemaType.GetBuiltInSimpleType(XmlTypeCode.Double), ((IConvertible) value).ToDouble(null)));
                            break; 

                        case XmlTypeCode.String:
                            if (sourceType == XsltConvert.DateTimeType)
                                value = new XmlQueryItemSequence(new XmlAtomicValue(XmlSchemaType.GetBuiltInSimpleType(XmlTypeCode.String), XsltConvert.ToString((DateTime) value))); 
                            else
                                value = new XmlQueryItemSequence(new XmlAtomicValue(XmlSchemaType.GetBuiltInSimpleType(XmlTypeCode.String), value)); 
                            break; 

                        case XmlTypeCode.Node: 
                            // Support XPathNavigator[]
                            value = ChangeTypeXsltResult(XmlQueryTypeFactory.NodeS, value);
                            break;
 
                        case XmlTypeCode.Item:
                            // Support XPathNodeIterator 
                            if (value is XPathNodeIterator) { 
                                value = ChangeTypeXsltResult(XmlQueryTypeFactory.NodeS, value);
                                break; 
                            }

                            // Support IXPathNavigable and XPathNavigator
                            navigable = value as IXPathNavigable; 
                            if (navigable != null) {
                                if (value is XPathNavigator) 
                                    value = new XmlQueryNodeSequence((XPathNavigator) value); 
                                else
                                    value = new XmlQueryNodeSequence(navigable.CreateNavigator()); 
                                break;
                            }

                            throw new XslTransformException(Res.Xslt_UnsupportedClrType, sourceType.Name); 
                    }
                    break; 
                } 
            }
 
            Debug.Assert(XmlILTypeHelper.GetStorageType(xmlType).IsAssignableFrom(value.GetType()), "Xml type " + xmlType + " is not represented in ILGen as " + value.GetType().Name);
            return value;
        }
 
        /// 
        /// Ensure that "value" is a navigator and not null. 
        ///  
        private static XPathNavigator EnsureNavigator(object value) {
            XPathNavigator nav = value as XPathNavigator; 

            if (nav == null)
                throw new XslTransformException(Res.Xslt_ItemNull, string.Empty);
 
            return nav;
        } 
 
        /// 
        /// Return true if the type of every item in "seq" matches the xml type identified by "idxType". 
        /// 
        public bool MatchesXmlType(IList seq, int indexType) {
            XmlQueryType typBase = GetXmlType(indexType);
            XmlQueryCardinality card; 

            switch (seq.Count) { 
                case 0: card = XmlQueryCardinality.Zero; break; 
                case 1: card = XmlQueryCardinality.One; break;
                default: card = XmlQueryCardinality.More; break; 
            }

            if (!(card <= typBase.Cardinality))
                return false; 

            typBase = typBase.Prime; 
            for (int i = 0; i < seq.Count; i++) { 
                if (!CreateXmlType(seq[0]).IsSubtypeOf(typBase))
                    return false; 
            }

            return true;
        } 

        ///  
        /// Return true if the type of "item" matches the xml type identified by "idxType". 
        /// 
        public bool MatchesXmlType(XPathItem item, int indexType) { 
            return CreateXmlType(item).IsSubtypeOf(GetXmlType(indexType));
        }

        ///  
        /// Return true if the type of "seq" is a subtype of a singleton type identified by "code".
        ///  
        public bool MatchesXmlType(IList seq, XmlTypeCode code) { 
            if (seq.Count != 1)
                return false; 

            return MatchesXmlType(seq[0], code);
        }
 
        /// 
        /// Return true if the type of "item" is a subtype of the type identified by "code". 
        ///  
        public bool MatchesXmlType(XPathItem item, XmlTypeCode code) {
            // All atomic type codes appear after AnyAtomicType 
            if (code > XmlTypeCode.AnyAtomicType)
                    return !item.IsNode && item.XmlType.TypeCode == code;

            // Handle node code and AnyAtomicType 
            switch (code) {
                case XmlTypeCode.AnyAtomicType: return !item.IsNode; 
                case XmlTypeCode.Node: return item.IsNode; 
                case XmlTypeCode.Item: return true;
                default: 
                    if (!item.IsNode)
                        return false;

                    switch (((XPathNavigator) item).NodeType) { 
                        case XPathNodeType.Root: return code == XmlTypeCode.Document;
                        case XPathNodeType.Element: return code == XmlTypeCode.Element; 
                        case XPathNodeType.Attribute: return code == XmlTypeCode.Attribute; 
                        case XPathNodeType.Namespace: return code == XmlTypeCode.Namespace;
                        case XPathNodeType.Text: return code == XmlTypeCode.Text; 
                        case XPathNodeType.SignificantWhitespace: return code == XmlTypeCode.Text;
                        case XPathNodeType.Whitespace: return code == XmlTypeCode.Text;
                        case XPathNodeType.ProcessingInstruction: return code == XmlTypeCode.ProcessingInstruction;
                        case XPathNodeType.Comment: return code == XmlTypeCode.Comment; 
                    }
                    break; 
            } 

            Debug.Fail("XmlTypeCode " + code + " was not fully handled."); 
            return false;
        }

        ///  
        /// Create an XmlQueryType that represents the type of "item".
        ///  
        private XmlQueryType CreateXmlType(XPathItem item) { 
            if (item.IsNode) {
                // Rtf 
                RtfNavigator rtf = item as RtfNavigator;
                if (rtf != null)
                    return XmlQueryTypeFactory.Node;
 
                // Node
                XPathNavigator nav = (XPathNavigator) item; 
                switch (nav.NodeType) { 
                    case XPathNodeType.Root:
                    case XPathNodeType.Element: 
                        if (nav.XmlType == null)
                            return XmlQueryTypeFactory.Type(nav.NodeType, XmlQualifiedNameTest.New(nav.LocalName, nav.NamespaceURI), XmlSchemaComplexType.UntypedAnyType, false);

                        return XmlQueryTypeFactory.Type(nav.NodeType, XmlQualifiedNameTest.New(nav.LocalName, nav.NamespaceURI), nav.XmlType, nav.SchemaInfo.SchemaElement.IsNillable); 

                    case XPathNodeType.Attribute: 
                        if (nav.XmlType == null) 
                            return XmlQueryTypeFactory.Type(nav.NodeType, XmlQualifiedNameTest.New(nav.LocalName, nav.NamespaceURI), DatatypeImplementation.UntypedAtomicType, false);
 
                        return XmlQueryTypeFactory.Type(nav.NodeType, XmlQualifiedNameTest.New(nav.LocalName, nav.NamespaceURI), nav.XmlType, false);
                }

                return XmlQueryTypeFactory.Type(nav.NodeType, XmlQualifiedNameTest.Wildcard, XmlSchemaComplexType.AnyType, false); 
            }
 
            // Atomic value 
            return XmlQueryTypeFactory.Type((XmlSchemaSimpleType)item.XmlType, true);
        } 


        //-----------------------------------------------
        // Xml collations 
        //-----------------------------------------------
 
        ///  
        /// Get a collation that was statically created.
        ///  
        public XmlCollation GetCollation(int index) {
            Debug.Assert(this.collations != null);
            return this.collations[index];
        } 

        ///  
        /// Create a collation from a string. 
        /// 
        public XmlCollation CreateCollation(string collation) { 
            return XmlCollation.Create(collation);
        }

 
        //-----------------------------------------------
        // Document Ordering and Identity 
        //----------------------------------------------- 

        ///  
        /// Compare the relative positions of two navigators.  Return -1 if navThis is before navThat, 1 if after, and
        /// 0 if they are positioned to the same node.
        /// 
        public int ComparePosition(XPathNavigator navigatorThis, XPathNavigator navigatorThat) { 
            return this.docOrderCmp.Compare(navigatorThis, navigatorThat);
        } 
 
        /// 
        /// Get a comparer which guarantees a stable ordering among nodes, even those from different documents. 
        /// 
        public IList DocOrderDistinct(IList seq) {
            if (seq.Count <= 1)
                return seq; 

            XmlQueryNodeSequence nodeSeq = (XmlQueryNodeSequence) seq; 
            if (nodeSeq == null) 
                nodeSeq = new XmlQueryNodeSequence(seq);
 
            return nodeSeq.DocOrderDistinct(this.docOrderCmp);
        }

        ///  
        /// Generate a unique string identifier for the specified node.  Do this by asking the navigator for an identifier
        /// that is unique within the document, and then prepend a document index. 
        ///  
        public string GenerateId(XPathNavigator navigator) {
            return string.Concat("ID", this.docOrderCmp.GetDocumentIndex(navigator).ToString(CultureInfo.InvariantCulture), navigator.UniqueId); 
        }


        //----------------------------------------------- 
        // Indexes
        //----------------------------------------------- 
 
        /// 
        /// If an index having the specified Id has already been created over the "context" document, then return it 
        /// in "index" and return true.  Otherwise, create a new, empty index and return false.
        /// 
        public bool FindIndex(XPathNavigator context, int indexId, out XmlILIndex index) {
            XPathNavigator navRoot; 
            ArrayList docIndexes;
            Debug.Assert(context != null); 
 
            // Get root of document
            navRoot = context.Clone(); 
            navRoot.MoveToRoot();

            // Search pre-existing indexes in order to determine whether the specified index has already been created
            if (this.indexes != null && indexId < this.indexes.Length) { 
                docIndexes = (ArrayList) this.indexes[indexId];
                if (docIndexes != null) { 
                    // Search for an index defined over the specified document 
                    for (int i = 0; i < docIndexes.Count; i += 2) {
                        // If we find a matching document, then return the index saved in the next slot 
                        if (((XPathNavigator) docIndexes[i]).IsSamePosition(navRoot)) {
                            index = (XmlILIndex) docIndexes[i + 1];
                            return true;
                        } 
                    }
                } 
            } 

            // Return a new, empty index 
            index = new XmlILIndex();
            return false;
        }
 
        /// 
        /// Add a newly built index over the specified "context" document to the existing collection of indexes. 
        ///  
        public void AddNewIndex(XPathNavigator context, int indexId, XmlILIndex index) {
            XPathNavigator navRoot; 
            ArrayList docIndexes;
            Debug.Assert(context != null);

            // Get root of document 
            navRoot = context.Clone();
            navRoot.MoveToRoot(); 
 
            // Ensure that a slot exists for the new index
            if (this.indexes == null) { 
                this.indexes = new ArrayList[indexId + 4];
            }
            else if (indexId >= this.indexes.Length) {
                // Resize array 
                ArrayList[] indexesNew = new ArrayList[indexId + 4];
                Array.Copy(this.indexes, 0, indexesNew, 0, this.indexes.Length); 
                this.indexes = indexesNew; 
            }
 
            docIndexes = (ArrayList) this.indexes[indexId];
            if (docIndexes == null) {
                docIndexes = new ArrayList();
                this.indexes[indexId] = docIndexes; 
            }
 
            docIndexes.Add(navRoot); 
            docIndexes.Add(index);
        } 


        //-----------------------------------------------
        // Output construction 
        //-----------------------------------------------
 
        ///  
        /// Get output writer object.
        ///  
        public XmlQueryOutput Output {
            get { return this.output; }
        }
 
        /// 
        /// Start construction of a nested sequence of items. Return a new XmlQueryOutput that will be 
        /// used to construct this new sequence. 
        /// 
        public void StartSequenceConstruction(out XmlQueryOutput output) { 
            // Push current writer
            this.stkOutput.Push(this.output);

            // Create new writers 
            output = this.output = new XmlQueryOutput(this, new XmlCachedSequenceWriter());
        } 
 
        /// 
        /// End construction of a nested sequence of items and return the items as an IList 
        /// internal class.  Return previous XmlQueryOutput.
        /// 
        public IList EndSequenceConstruction(out XmlQueryOutput output) {
            IList seq = ((XmlCachedSequenceWriter) this.output.SequenceWriter).ResultSequence; 

            // Restore previous XmlQueryOutput 
            output = this.output = this.stkOutput.Pop(); 

            return seq; 
        }

        /// 
        /// Start construction of an Rtf. Return a new XmlQueryOutput object that will be used to construct this Rtf. 
        /// 
        public void StartRtfConstruction(string baseUri, out XmlQueryOutput output) { 
            // Push current writer 
            this.stkOutput.Push(this.output);
 
            // Create new XmlQueryOutput over an Rtf writer
            output = this.output = new XmlQueryOutput(this, new XmlEventCache(baseUri, true));
        }
 
        /// 
        /// End construction of an Rtf and return it as an RtfNavigator.  Return previous XmlQueryOutput object. 
        ///  
        public XPathNavigator EndRtfConstruction(out XmlQueryOutput output) {
            XmlEventCache events; 

            events = (XmlEventCache) this.output.Writer;

            // Restore previous XmlQueryOutput 
            output = this.output = this.stkOutput.Pop();
 
            // Return Rtf as an RtfNavigator 
            events.EndEvents();
            return new RtfTreeNavigator(events, this.nameTableQuery); 
        }

        /// 
        /// Construct a new RtfTextNavigator from the specified "text".  This is much more efficient than calling 
        /// StartNodeConstruction(), StartRtf(), WriteString(), EndRtf(), and EndNodeConstruction().
        ///  
        public XPathNavigator TextRtfConstruction(string text, string baseUri) { 
            return new RtfTextNavigator(text, baseUri);
        } 


        //-----------------------------------------------
        // Miscellaneous 
        //-----------------------------------------------
 
        ///  
        /// Report query execution information to event handler.
        ///  
        public void SendMessage(string message) {
            this.ctxt.OnXsltMessageEncountered(message);
        }
 
        /// 
        /// Throw an Xml exception having the specified message text. 
        ///  
        public void ThrowException(string text) {
            throw new XslTransformException(text); 
        }

        /// 
        /// Position navThis to the same location as navThat. 
        /// 
        internal static XPathNavigator SyncToNavigator(XPathNavigator navigatorThis, XPathNavigator navigatorThat) { 
            if (navigatorThis == null || !navigatorThis.MoveTo(navigatorThat)) 
                return navigatorThat.Clone();
 
            return navigatorThis;
        }

        ///  
        /// Function is called in Debug mode on each time context node change.
        ///  
        public static int OnCurrentNodeChanged(XPathNavigator currentNode) { 
            IXmlLineInfo lineInfo = currentNode as IXmlLineInfo;
 
            // In case of a namespace node, check whether it is inherited or locally defined
            if (lineInfo != null && ! (currentNode.NodeType == XPathNodeType.Namespace && IsInheritedNamespace(currentNode))) {
                OnCurrentNodeChanged2(currentNode.BaseURI, lineInfo.LineNumber, lineInfo.LinePosition);
            } 
            return 0;
        } 
 
 	// 'true' if current Namespace "inherited" from it's parent. Not defined localy.
        private static bool IsInheritedNamespace(XPathNavigator node) { 
            Debug.Assert(node.NodeType == XPathNodeType.Namespace);
            XPathNavigator nav = node.Clone();
            if (nav.MoveToParent()) {
                if (nav.MoveToFirstNamespace(XPathNamespaceScope.Local)) { 
                    do {
                        if ((object)nav.LocalName == (object)node.LocalName) { 
                            return false; 
                        }
                    } while (nav.MoveToNextNamespace(XPathNamespaceScope.Local)); 
                }
            }
            return true;
        } 

 
        private static void OnCurrentNodeChanged2(string baseUri, int lineNumber, int linePosition) {} 
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// [....] 
//-----------------------------------------------------------------------------
using System; 
using System.IO; 
using System.Xml;
using System.Xml.XPath; 
using System.Xml.Schema;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics; 
using System.Text;
using System.Globalization; 
using System.Reflection; 
using System.Reflection.Emit;
using System.Xml.Xsl.Qil; 
using System.Xml.Xsl.IlGen;
using System.ComponentModel;
using MS.Internal.Xml.XPath;
 
namespace System.Xml.Xsl.Runtime {
    using Res = System.Xml.Utils.Res; 
 
    /// 
    /// XmlQueryRuntime is passed as the first parameter to all generated query methods. 
    ///
    /// XmlQueryRuntime contains runtime support for generated ILGen queries:
    ///   1. Stack of output writers (stack handles nested document construction)
    ///   2. Manages list of all xml types that are used within the query 
    ///   3. Manages list of all atomized names that are used within the query
    ///  
    [EditorBrowsable(EditorBrowsableState.Never)] 
    public sealed class XmlQueryRuntime {
        // Early-Bound Library Objects 
        private XmlQueryContext ctxt;
        private XsltLibrary xsltLib;
        private EarlyBoundInfo[] earlyInfo;
        private object[] earlyObjects; 

        // Global variables and parameters 
        private string[] globalNames; 
        private object[] globalValues;
 
        // Names, prefix mappings, and name filters
        private XmlNameTable nameTableQuery;
        private string[] atomizedNames;             // Names after atomization
        private XmlNavigatorFilter[] filters;       // Name filters (contain atomized names) 
        private StringPair[][] prefixMappingsList;  // Lists of prefix mappings (used to resolve computed names)
 
        // Xml types 
        private XmlQueryType[] types;
 
        // Collations
        private XmlCollation[] collations;

        // Document ordering 
        private DocumentOrderComparer docOrderCmp;
 
        // Indexes 
        private ArrayList[] indexes;
 
        // Output construction
        private XmlQueryOutput output;
        private Stack stkOutput;
 

        //----------------------------------------------- 
        // Constructors 
        //-----------------------------------------------
 
        /// 
        /// This constructor is internal so that external users cannot construct it (and therefore we do not have to test it separately).
        /// 
        internal XmlQueryRuntime(XmlQueryStaticData data, object defaultDataSource, XmlResolver dataSources, XsltArgumentList argList, XmlSequenceWriter seqWrt) { 
            Debug.Assert(data != null);
            string[] names = data.Names; 
            Int32Pair[] filters = data.Filters; 
            WhitespaceRuleLookup wsRules;
            int i; 

            // Early-Bound Library Objects
            wsRules = (data.WhitespaceRules != null && data.WhitespaceRules.Count != 0) ? new WhitespaceRuleLookup(data.WhitespaceRules) : null;
            this.ctxt = new XmlQueryContext(this, defaultDataSource, dataSources, argList, wsRules); 
            this.xsltLib = null;
            this.earlyInfo = data.EarlyBound; 
            this.earlyObjects = (this.earlyInfo != null) ? new object[earlyInfo.Length] : null; 

            // Global variables and parameters 
            this.globalNames = data.GlobalNames;
            this.globalValues = (this.globalNames != null) ? new object[this.globalNames.Length] : null;

            // Names 
            this.nameTableQuery = this.ctxt.QueryNameTable;
            this.atomizedNames = null; 
 
            if (names != null) {
                // Atomize all names in "nameTableQuery".  Use names from the default data source's 
                // name table when possible.
                XmlNameTable nameTableDefault = ctxt.DefaultNameTable;
                this.atomizedNames = new string[names.Length];
 
                if (nameTableDefault != this.nameTableQuery && nameTableDefault != null) {
                    // Ensure that atomized names from the default data source are added to the 
                    // name table used in this query 
                    for (i = 0; i < names.Length; i++) {
                        string name = nameTableDefault.Get(names[i]); 
                        this.atomizedNames[i] = this.nameTableQuery.Add(name ?? names[i]);
                    }
                }
                else { 
                    // Enter names into nametable used in this query
                    for (i = 0; i < names.Length; i++) 
                        this.atomizedNames[i] = this.nameTableQuery.Add(names[i]); 
                }
            } 

            // Name filters
            this.filters = null;
            if (filters != null) { 
                // Construct name filters.  Each pair of integers in the filters[] array specifies the
                // (localName, namespaceUri) of the NameFilter to be created. 
                this.filters = new XmlNavigatorFilter[filters.Length]; 

                for (i = 0; i < filters.Length; i++) 
                    this.filters[i] = XmlNavNameFilter.Create(this.atomizedNames[filters[i].Left], this.atomizedNames[filters[i].Right]);
            }

            // Prefix maping lists 
            this.prefixMappingsList = data.PrefixMappingsList;
 
            // Xml types 
            this.types = data.Types;
 
            // Xml collations
            this.collations = data.Collations;

            // Document ordering 
            this.docOrderCmp = new DocumentOrderComparer();
 
            // Indexes 
            this.indexes = null;
 
            // Output construction
            this.stkOutput = new Stack(16);
            this.output = new XmlQueryOutput(this, seqWrt);
        } 

 
        //----------------------------------------------- 
        // Debugger Utility Methods
        //----------------------------------------------- 

        /// 
        /// Return array containing the names of all the global variables and parameters used in this query, in this format:
        ///     {namespace}prefix:local-name 
        /// 
        public string[] DebugGetGlobalNames() { 
            return this.globalNames; 
        }
 
        /// 
        /// Get the value of a global value having the specified name.  Always return the global value as a list of XPathItem.
        /// Return null if there is no global value having the specified name.
        ///  
        public IList DebugGetGlobalValue(string name) {
            for (int idx = 0; idx < this.globalNames.Length; idx++) { 
                if (this.globalNames[idx] == name) { 
                    Debug.Assert(IsGlobalComputed(idx), "Cannot get the value of a global value until it has been computed.");
                    Debug.Assert(this.globalValues[idx] is IList, "Only debugger should call this method, and all global values should have type item* in debugging scenarios."); 
                    return (IList) this.globalValues[idx];
                }
            }
            return null; 
        }
 
        ///  
        /// Set the value of a global value having the specified name.  If there is no such value, this method is a no-op.
        ///  
        public void DebugSetGlobalValue(string name, object value) {
            for (int idx = 0; idx < this.globalNames.Length; idx++) {
                if (this.globalNames[idx] == name) {
                    Debug.Assert(IsGlobalComputed(idx), "Cannot get the value of a global value until it has been computed."); 
                    Debug.Assert(this.globalValues[idx] is IList, "Only debugger should call this method, and all global values should have type item* in debugging scenarios.");
 
                    // Always convert "value" to a list of XPathItem using the item* converter 
                    this.globalValues[idx] = (IList) XmlAnyListConverter.ItemList.ChangeType(value, typeof(XPathItem[]), null);
                    break; 
                }
            }
        }
 
        /// 
        /// Convert sequence to it's appropriate XSLT type and return to caller. 
        ///  
        public object DebugGetXsltValue(IList seq) {
            if (seq != null && seq.Count == 1) { 
                XPathItem item = seq[0] as XPathItem;
                if (item != null && !item.IsNode) {
                    return item.TypedValue;
                } 
                else if (item is RtfNavigator) {
                    return ((RtfNavigator) item).ToNavigator(); 
                } 
            }
 
            return seq;
        }

 
        //-----------------------------------------------
        // Early-Bound Library Objects 
        //----------------------------------------------- 

        internal const BindingFlags EarlyBoundFlags     = BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static; 
        internal const BindingFlags LateBoundFlags      = BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static;

        /// 
        /// Return the object that manages external user context information such as data sources, parameters, extension objects, etc. 
        /// 
        public XmlQueryContext ExternalContext { 
            get { return this.ctxt; } 
        }
 
        /// 
        /// Return the object that manages the state needed to implement various Xslt functions.
        /// 
        public XsltLibrary XsltFunctions { 
            get {
                if (this.xsltLib == null) { 
                    this.xsltLib = new XsltLibrary(this); 
                }
 
                return this.xsltLib;
            }
        }
 
        /// 
        /// Get the early-bound extension object identified by "index".  If it does not yet exist, create an instance using the 
        /// corresponding ConstructorInfo. 
        /// 
        public object GetEarlyBoundObject(int index) { 
            object obj;
            Debug.Assert(this.earlyObjects != null && index < this.earlyObjects.Length, "Early bound object does not exist");

            obj = this.earlyObjects[index]; 
            if (obj == null) {
                // Early-bound object does not yet exist, so create it now 
                obj = this.earlyInfo[index].CreateObject(); 
                this.earlyObjects[index] = obj;
            } 

            return obj;
        }
 
        /// 
        /// Return true if the early bound object identified by "namespaceUri" contains a method that matches "name". 
        ///  
        public bool EarlyBoundFunctionExists(string name, string namespaceUri) {
            if (this.earlyInfo == null) 
                return false;

            for (int idx = 0; idx < this.earlyInfo.Length; idx++) {
                if (namespaceUri == this.earlyInfo[idx].NamespaceUri) 
                    return new XmlExtensionFunction(name, namespaceUri, -1, this.earlyInfo[idx].EarlyBoundType, EarlyBoundFlags).CanBind();
            } 
 
            return false;
        } 


        //-----------------------------------------------
        // Global variables and parameters 
        //-----------------------------------------------
 
        ///  
        /// Return true if the global value specified by idxValue was previously computed.
        ///  
        public bool IsGlobalComputed(int index) {
            return this.globalValues[index] != null;
        }
 
        /// 
        /// Return the value that is bound to the global variable or parameter specified by idxValue. 
        /// If the value has not yet been computed, then compute it now and store it in this.globalValues. 
        /// 
        public object GetGlobalValue(int index) { 
            Debug.Assert(IsGlobalComputed(index), "Cannot get the value of a global value until it has been computed.");
            return this.globalValues[index];
        }
 
        /// 
        /// Return the value that is bound to the global variable or parameter specified by idxValue. 
        /// If the value has not yet been computed, then compute it now and store it in this.globalValues. 
        /// 
        public void SetGlobalValue(int index, object value) { 
            Debug.Assert(!IsGlobalComputed(index), "Global value should only be set once.");
            this.globalValues[index] = value;
        }
 

        //----------------------------------------------- 
        // Names, prefix mappings, and name filters 
        //-----------------------------------------------
 
        /// 
        /// Return the name table used to atomize all names used by the query.
        /// 
        public XmlNameTable NameTable { 
            get { return this.nameTableQuery; }
        } 
 
        /// 
        /// Get the atomized name at the specified index in the array of names. 
        /// 
        public string GetAtomizedName(int index) {
            Debug.Assert(this.atomizedNames != null);
            return this.atomizedNames[index]; 
        }
 
        ///  
        /// Get the name filter at the specified index in the array of filters.
        ///  
        public XmlNavigatorFilter GetNameFilter(int index) {
            Debug.Assert(this.filters != null);
            return this.filters[index];
        } 

        ///  
        /// XPathNodeType.All: Filters all nodes 
        /// XPathNodeType.Attribute: Filters attributes
        /// XPathNodeType.Namespace: Not allowed 
        /// XPathNodeType.XXX: Filters all nodes *except* those having XPathNodeType.XXX
        /// 
        public XmlNavigatorFilter GetTypeFilter(XPathNodeType nodeType) {
            if (nodeType == XPathNodeType.All) 
                return XmlNavNeverFilter.Create();
 
            if (nodeType == XPathNodeType.Attribute) 
                return XmlNavAttrFilter.Create();
 
            return XmlNavTypeFilter.Create(nodeType);
        }

        ///  
        /// Parse the specified tag name (foo:bar) and resolve the resulting prefix.  If the prefix cannot be resolved,
        /// then throw an error.  Return an XmlQualifiedName. 
        ///  
        public XmlQualifiedName ParseTagName(string tagName, int indexPrefixMappings) {
            string prefix, localName, ns; 

            // Parse the tagName as a prefix, localName pair and resolve the prefix
            ParseTagName(tagName, indexPrefixMappings, out prefix, out localName, out ns);
            return new XmlQualifiedName(localName, ns); 
        }
 
        ///  
        /// Parse the specified tag name (foo:bar).  Return an XmlQualifiedName consisting of the parsed local name
        /// and the specified namespace. 
        /// 
        public XmlQualifiedName ParseTagName(string tagName, string ns) {
            string prefix, localName;
 
            // Parse the tagName as a prefix, localName pair
            ValidateNames.ParseQNameThrow(tagName, out prefix, out localName); 
            return new XmlQualifiedName(localName, ns); 
        }
 
        /// 
        /// Parse the specified tag name (foo:bar) and resolve the resulting prefix.  If the prefix cannot be resolved,
        /// then throw an error.  Return the prefix, localName, and namespace URI.
        ///  
        internal void ParseTagName(string tagName, int idxPrefixMappings, out string prefix, out string localName, out string ns) {
            Debug.Assert(this.prefixMappingsList != null); 
 
            // Parse the tagName as a prefix, localName pair
            ValidateNames.ParseQNameThrow(tagName, out prefix, out localName); 

            // Map the prefix to a namespace URI
            ns = null;
            foreach (StringPair pair in this.prefixMappingsList[idxPrefixMappings]) { 
                if (prefix == pair.Left) {
                    ns = pair.Right; 
                    break; 
                }
            } 

            // Throw exception if prefix could not be resolved
            if (ns == null) {
                // Check for mappings that are always in-scope 
                if (prefix.Length == 0)
                    ns = ""; 
                else if (prefix.Equals("xml")) 
                    ns = XmlReservedNs.NsXml;
                else if (prefix.Equals("xmlns")) 
                    ns = XmlReservedNs.NsXmlNs;
                else
                    throw new XslTransformException(Res.Xslt_InvalidPrefix, prefix);
            } 
        }
 
        ///  
        /// Return true if the nav1's LocalName and NamespaceURI properties equal nav2's corresponding properties.
        ///  
        public bool IsQNameEqual(XPathNavigator n1, XPathNavigator n2) {
            if ((object) n1.NameTable == (object) n2.NameTable) {
                // Use atomized comparison
                return (object) n1.LocalName == (object) n2.LocalName && (object) n1.NamespaceURI == (object) n2.NamespaceURI; 
            }
 
            return (n1.LocalName == n2.LocalName) && (n1.NamespaceURI == n2.NamespaceURI); 
        }
 
        /// 
        /// Return true if the specified navigator's LocalName and NamespaceURI properties equal the argument names.
        /// 
        public bool IsQNameEqual(XPathNavigator navigator, int indexLocalName, int indexNamespaceUri) { 
            if ((object) navigator.NameTable == (object) this.nameTableQuery) {
                // Use atomized comparison 
                return ((object) GetAtomizedName(indexLocalName) == (object) navigator.LocalName && 
                        (object) GetAtomizedName(indexNamespaceUri) == (object) navigator.NamespaceURI);
            } 

            // Use string comparison
            return (GetAtomizedName(indexLocalName) == navigator.LocalName) && (GetAtomizedName(indexNamespaceUri) == navigator.NamespaceURI);
        } 

 
        //----------------------------------------------- 
        // Xml types
        //----------------------------------------------- 

        /// 
        /// Get the array of xml types that are used within this query.
        ///  
        internal XmlQueryType[] XmlTypes {
            get { return this.types; } 
        } 

        ///  
        /// Get the Xml query type at the specified index in the array of types.
        /// 
        internal XmlQueryType GetXmlType(int idxType) {
            Debug.Assert(this.types != null); 
            return this.types[idxType];
        } 
 
        /// 
        /// Forward call to ChangeTypeXsltArgument(XmlQueryType, object, Type). 
        /// 
        public object ChangeTypeXsltArgument(int indexType, object value, Type destinationType) {
            return ChangeTypeXsltArgument(GetXmlType(indexType), value, destinationType);
        } 

        ///  
        /// Convert from the Clr type of "value" to Clr type "destinationType" using V1 Xslt rules. 
        /// These rules include converting any Rtf values to Nodes.
        ///  
        internal object ChangeTypeXsltArgument(XmlQueryType xmlType, object value, Type destinationType) {
            Debug.Assert(XmlILTypeHelper.GetStorageType(xmlType).IsAssignableFrom(value.GetType()),
                         "Values passed to ChangeTypeXsltArgument should be in ILGen's default Clr representation.");
            Debug.Assert(destinationType == XsltConvert.ObjectType || !destinationType.IsAssignableFrom(value.GetType()), 
                         "No need to call ChangeTypeXsltArgument since value is already assignable to destinationType " + destinationType);
 
            switch (xmlType.TypeCode) { 
                case XmlTypeCode.String:
                    if (destinationType == XsltConvert.DateTimeType) 
                        value = XsltConvert.ToDateTime((string) value);
                    break;

                case XmlTypeCode.Double: 
                    if (destinationType != XsltConvert.DoubleType)
                        value = Convert.ChangeType(value, destinationType, CultureInfo.InvariantCulture); 
                    break; 

                case XmlTypeCode.Node: 
                    Debug.Assert(xmlType != XmlQueryTypeFactory.Node && xmlType != XmlQueryTypeFactory.NodeS,
                                 "Rtf values should have been eliminated by caller.");

                    if (destinationType == XsltConvert.XPathNodeIteratorType) { 
                        value = new XPathArrayIterator((IList) value);
                    } 
                    else if (destinationType == XsltConvert.XPathNavigatorArrayType) { 
                        // Copy sequence to XPathNavigator[]
                        IList seq = (IList) value; 
                        XPathNavigator[] navArray = new XPathNavigator[seq.Count];

                        for (int i = 0; i < seq.Count; i++)
                            navArray[i] = seq[i]; 

                        value = navArray; 
                    } 
                    break;
 
                case XmlTypeCode.Item: {
                    // Only typeof(object) is supported as a destination type
                    if (destinationType != XsltConvert.ObjectType)
                        throw new XslTransformException(Res.Xslt_UnsupportedClrType, destinationType.Name); 

                    // Convert to default, backwards-compatible representation 
                    //   1. NodeSet: System.Xml.XPath.XPathNodeIterator 
                    //   2. Rtf: System.Xml.XPath.XPathNavigator
                    //   3. Other:   Default V1 representation 
                    IList seq = (IList) value;
                    if (seq.Count == 1) {
                        XPathItem item = seq[0];
 
                        if (item.IsNode) {
                            // Node or Rtf 
                            RtfNavigator rtf = item as RtfNavigator; 
                            if (rtf != null)
                                value = rtf.ToNavigator(); 
                            else
                                value = new XPathArrayIterator((IList) value);
                        }
                        else { 
                            // Atomic value
                            value = item.TypedValue; 
                        } 
                    }
                    else { 
                        // Nodeset
                        value = new XPathArrayIterator((IList) value);
                    }
                    break; 
                }
            } 
 
            Debug.Assert(destinationType.IsAssignableFrom(value.GetType()), "ChangeType from type " + value.GetType().Name + " to type " + destinationType.Name + " failed");
            return value; 
        }

        /// 
        /// Forward call to ChangeTypeXsltResult(XmlQueryType, object) 
        /// 
        public object ChangeTypeXsltResult(int indexType, object value) { 
            return ChangeTypeXsltResult(GetXmlType(indexType), value); 
        }
 
        /// 
        /// Convert from the Clr type of "value" to the default Clr type that ILGen uses to represent the xml type, using
        /// the conversion rules of the xml type.
        ///  
        internal object ChangeTypeXsltResult(XmlQueryType xmlType, object value) {
            if (value == null) 
                throw new XslTransformException(Res.Xslt_ItemNull, string.Empty); 

            switch (xmlType.TypeCode) { 
                case XmlTypeCode.String:
                    if (value.GetType() == XsltConvert.DateTimeType)
                        value = XsltConvert.ToString((DateTime) value);
                    break; 

                case XmlTypeCode.Double: 
                    if (value.GetType() != XsltConvert.DoubleType) 
                        value = ((IConvertible) value).ToDouble(null);
 
                    break;

                case XmlTypeCode.Node:
                    if (!xmlType.IsSingleton) { 
                        XPathArrayIterator iter = value as XPathArrayIterator;
 
                        // Special-case XPathArrayIterator in order to avoid copies 
                        if (iter != null && iter.AsList is XmlQueryNodeSequence) {
                            value = iter.AsList as XmlQueryNodeSequence; 
                        }
                        else {
                            // Iterate over list and ensure it only contains nodes
                            XmlQueryNodeSequence seq = new XmlQueryNodeSequence(); 
                            IList list = value as IList;
 
                            if (list != null) { 
                                for (int i = 0; i < list.Count; i++)
                                    seq.Add(EnsureNavigator(list[i])); 
                            }
                            else {
                                foreach (object o in (IEnumerable) value)
                                    seq.Add(EnsureNavigator(o)); 
                            }
 
                            value = seq; 
                        }
 
                        // Always sort node-set by document order
                        value = ((XmlQueryNodeSequence) value).DocOrderDistinct(this.docOrderCmp);
                    }
                    break; 

                case XmlTypeCode.Item: { 
                    Type sourceType = value.GetType(); 
                    IXPathNavigable navigable;
 
                    // If static type is item, then infer type based on dynamic value
                    switch (XsltConvert.InferXsltType(sourceType).TypeCode) {
                        case XmlTypeCode.Boolean:
                            value = new XmlQueryItemSequence(new XmlAtomicValue(XmlSchemaType.GetBuiltInSimpleType(XmlTypeCode.Boolean), value)); 
                            break;
 
                        case XmlTypeCode.Double: 
                            value = new XmlQueryItemSequence(new XmlAtomicValue(XmlSchemaType.GetBuiltInSimpleType(XmlTypeCode.Double), ((IConvertible) value).ToDouble(null)));
                            break; 

                        case XmlTypeCode.String:
                            if (sourceType == XsltConvert.DateTimeType)
                                value = new XmlQueryItemSequence(new XmlAtomicValue(XmlSchemaType.GetBuiltInSimpleType(XmlTypeCode.String), XsltConvert.ToString((DateTime) value))); 
                            else
                                value = new XmlQueryItemSequence(new XmlAtomicValue(XmlSchemaType.GetBuiltInSimpleType(XmlTypeCode.String), value)); 
                            break; 

                        case XmlTypeCode.Node: 
                            // Support XPathNavigator[]
                            value = ChangeTypeXsltResult(XmlQueryTypeFactory.NodeS, value);
                            break;
 
                        case XmlTypeCode.Item:
                            // Support XPathNodeIterator 
                            if (value is XPathNodeIterator) { 
                                value = ChangeTypeXsltResult(XmlQueryTypeFactory.NodeS, value);
                                break; 
                            }

                            // Support IXPathNavigable and XPathNavigator
                            navigable = value as IXPathNavigable; 
                            if (navigable != null) {
                                if (value is XPathNavigator) 
                                    value = new XmlQueryNodeSequence((XPathNavigator) value); 
                                else
                                    value = new XmlQueryNodeSequence(navigable.CreateNavigator()); 
                                break;
                            }

                            throw new XslTransformException(Res.Xslt_UnsupportedClrType, sourceType.Name); 
                    }
                    break; 
                } 
            }
 
            Debug.Assert(XmlILTypeHelper.GetStorageType(xmlType).IsAssignableFrom(value.GetType()), "Xml type " + xmlType + " is not represented in ILGen as " + value.GetType().Name);
            return value;
        }
 
        /// 
        /// Ensure that "value" is a navigator and not null. 
        ///  
        private static XPathNavigator EnsureNavigator(object value) {
            XPathNavigator nav = value as XPathNavigator; 

            if (nav == null)
                throw new XslTransformException(Res.Xslt_ItemNull, string.Empty);
 
            return nav;
        } 
 
        /// 
        /// Return true if the type of every item in "seq" matches the xml type identified by "idxType". 
        /// 
        public bool MatchesXmlType(IList seq, int indexType) {
            XmlQueryType typBase = GetXmlType(indexType);
            XmlQueryCardinality card; 

            switch (seq.Count) { 
                case 0: card = XmlQueryCardinality.Zero; break; 
                case 1: card = XmlQueryCardinality.One; break;
                default: card = XmlQueryCardinality.More; break; 
            }

            if (!(card <= typBase.Cardinality))
                return false; 

            typBase = typBase.Prime; 
            for (int i = 0; i < seq.Count; i++) { 
                if (!CreateXmlType(seq[0]).IsSubtypeOf(typBase))
                    return false; 
            }

            return true;
        } 

        ///  
        /// Return true if the type of "item" matches the xml type identified by "idxType". 
        /// 
        public bool MatchesXmlType(XPathItem item, int indexType) { 
            return CreateXmlType(item).IsSubtypeOf(GetXmlType(indexType));
        }

        ///  
        /// Return true if the type of "seq" is a subtype of a singleton type identified by "code".
        ///  
        public bool MatchesXmlType(IList seq, XmlTypeCode code) { 
            if (seq.Count != 1)
                return false; 

            return MatchesXmlType(seq[0], code);
        }
 
        /// 
        /// Return true if the type of "item" is a subtype of the type identified by "code". 
        ///  
        public bool MatchesXmlType(XPathItem item, XmlTypeCode code) {
            // All atomic type codes appear after AnyAtomicType 
            if (code > XmlTypeCode.AnyAtomicType)
                    return !item.IsNode && item.XmlType.TypeCode == code;

            // Handle node code and AnyAtomicType 
            switch (code) {
                case XmlTypeCode.AnyAtomicType: return !item.IsNode; 
                case XmlTypeCode.Node: return item.IsNode; 
                case XmlTypeCode.Item: return true;
                default: 
                    if (!item.IsNode)
                        return false;

                    switch (((XPathNavigator) item).NodeType) { 
                        case XPathNodeType.Root: return code == XmlTypeCode.Document;
                        case XPathNodeType.Element: return code == XmlTypeCode.Element; 
                        case XPathNodeType.Attribute: return code == XmlTypeCode.Attribute; 
                        case XPathNodeType.Namespace: return code == XmlTypeCode.Namespace;
                        case XPathNodeType.Text: return code == XmlTypeCode.Text; 
                        case XPathNodeType.SignificantWhitespace: return code == XmlTypeCode.Text;
                        case XPathNodeType.Whitespace: return code == XmlTypeCode.Text;
                        case XPathNodeType.ProcessingInstruction: return code == XmlTypeCode.ProcessingInstruction;
                        case XPathNodeType.Comment: return code == XmlTypeCode.Comment; 
                    }
                    break; 
            } 

            Debug.Fail("XmlTypeCode " + code + " was not fully handled."); 
            return false;
        }

        ///  
        /// Create an XmlQueryType that represents the type of "item".
        ///  
        private XmlQueryType CreateXmlType(XPathItem item) { 
            if (item.IsNode) {
                // Rtf 
                RtfNavigator rtf = item as RtfNavigator;
                if (rtf != null)
                    return XmlQueryTypeFactory.Node;
 
                // Node
                XPathNavigator nav = (XPathNavigator) item; 
                switch (nav.NodeType) { 
                    case XPathNodeType.Root:
                    case XPathNodeType.Element: 
                        if (nav.XmlType == null)
                            return XmlQueryTypeFactory.Type(nav.NodeType, XmlQualifiedNameTest.New(nav.LocalName, nav.NamespaceURI), XmlSchemaComplexType.UntypedAnyType, false);

                        return XmlQueryTypeFactory.Type(nav.NodeType, XmlQualifiedNameTest.New(nav.LocalName, nav.NamespaceURI), nav.XmlType, nav.SchemaInfo.SchemaElement.IsNillable); 

                    case XPathNodeType.Attribute: 
                        if (nav.XmlType == null) 
                            return XmlQueryTypeFactory.Type(nav.NodeType, XmlQualifiedNameTest.New(nav.LocalName, nav.NamespaceURI), DatatypeImplementation.UntypedAtomicType, false);
 
                        return XmlQueryTypeFactory.Type(nav.NodeType, XmlQualifiedNameTest.New(nav.LocalName, nav.NamespaceURI), nav.XmlType, false);
                }

                return XmlQueryTypeFactory.Type(nav.NodeType, XmlQualifiedNameTest.Wildcard, XmlSchemaComplexType.AnyType, false); 
            }
 
            // Atomic value 
            return XmlQueryTypeFactory.Type((XmlSchemaSimpleType)item.XmlType, true);
        } 


        //-----------------------------------------------
        // Xml collations 
        //-----------------------------------------------
 
        ///  
        /// Get a collation that was statically created.
        ///  
        public XmlCollation GetCollation(int index) {
            Debug.Assert(this.collations != null);
            return this.collations[index];
        } 

        ///  
        /// Create a collation from a string. 
        /// 
        public XmlCollation CreateCollation(string collation) { 
            return XmlCollation.Create(collation);
        }

 
        //-----------------------------------------------
        // Document Ordering and Identity 
        //----------------------------------------------- 

        ///  
        /// Compare the relative positions of two navigators.  Return -1 if navThis is before navThat, 1 if after, and
        /// 0 if they are positioned to the same node.
        /// 
        public int ComparePosition(XPathNavigator navigatorThis, XPathNavigator navigatorThat) { 
            return this.docOrderCmp.Compare(navigatorThis, navigatorThat);
        } 
 
        /// 
        /// Get a comparer which guarantees a stable ordering among nodes, even those from different documents. 
        /// 
        public IList DocOrderDistinct(IList seq) {
            if (seq.Count <= 1)
                return seq; 

            XmlQueryNodeSequence nodeSeq = (XmlQueryNodeSequence) seq; 
            if (nodeSeq == null) 
                nodeSeq = new XmlQueryNodeSequence(seq);
 
            return nodeSeq.DocOrderDistinct(this.docOrderCmp);
        }

        ///  
        /// Generate a unique string identifier for the specified node.  Do this by asking the navigator for an identifier
        /// that is unique within the document, and then prepend a document index. 
        ///  
        public string GenerateId(XPathNavigator navigator) {
            return string.Concat("ID", this.docOrderCmp.GetDocumentIndex(navigator).ToString(CultureInfo.InvariantCulture), navigator.UniqueId); 
        }


        //----------------------------------------------- 
        // Indexes
        //----------------------------------------------- 
 
        /// 
        /// If an index having the specified Id has already been created over the "context" document, then return it 
        /// in "index" and return true.  Otherwise, create a new, empty index and return false.
        /// 
        public bool FindIndex(XPathNavigator context, int indexId, out XmlILIndex index) {
            XPathNavigator navRoot; 
            ArrayList docIndexes;
            Debug.Assert(context != null); 
 
            // Get root of document
            navRoot = context.Clone(); 
            navRoot.MoveToRoot();

            // Search pre-existing indexes in order to determine whether the specified index has already been created
            if (this.indexes != null && indexId < this.indexes.Length) { 
                docIndexes = (ArrayList) this.indexes[indexId];
                if (docIndexes != null) { 
                    // Search for an index defined over the specified document 
                    for (int i = 0; i < docIndexes.Count; i += 2) {
                        // If we find a matching document, then return the index saved in the next slot 
                        if (((XPathNavigator) docIndexes[i]).IsSamePosition(navRoot)) {
                            index = (XmlILIndex) docIndexes[i + 1];
                            return true;
                        } 
                    }
                } 
            } 

            // Return a new, empty index 
            index = new XmlILIndex();
            return false;
        }
 
        /// 
        /// Add a newly built index over the specified "context" document to the existing collection of indexes. 
        ///  
        public void AddNewIndex(XPathNavigator context, int indexId, XmlILIndex index) {
            XPathNavigator navRoot; 
            ArrayList docIndexes;
            Debug.Assert(context != null);

            // Get root of document 
            navRoot = context.Clone();
            navRoot.MoveToRoot(); 
 
            // Ensure that a slot exists for the new index
            if (this.indexes == null) { 
                this.indexes = new ArrayList[indexId + 4];
            }
            else if (indexId >= this.indexes.Length) {
                // Resize array 
                ArrayList[] indexesNew = new ArrayList[indexId + 4];
                Array.Copy(this.indexes, 0, indexesNew, 0, this.indexes.Length); 
                this.indexes = indexesNew; 
            }
 
            docIndexes = (ArrayList) this.indexes[indexId];
            if (docIndexes == null) {
                docIndexes = new ArrayList();
                this.indexes[indexId] = docIndexes; 
            }
 
            docIndexes.Add(navRoot); 
            docIndexes.Add(index);
        } 


        //-----------------------------------------------
        // Output construction 
        //-----------------------------------------------
 
        ///  
        /// Get output writer object.
        ///  
        public XmlQueryOutput Output {
            get { return this.output; }
        }
 
        /// 
        /// Start construction of a nested sequence of items. Return a new XmlQueryOutput that will be 
        /// used to construct this new sequence. 
        /// 
        public void StartSequenceConstruction(out XmlQueryOutput output) { 
            // Push current writer
            this.stkOutput.Push(this.output);

            // Create new writers 
            output = this.output = new XmlQueryOutput(this, new XmlCachedSequenceWriter());
        } 
 
        /// 
        /// End construction of a nested sequence of items and return the items as an IList 
        /// internal class.  Return previous XmlQueryOutput.
        /// 
        public IList EndSequenceConstruction(out XmlQueryOutput output) {
            IList seq = ((XmlCachedSequenceWriter) this.output.SequenceWriter).ResultSequence; 

            // Restore previous XmlQueryOutput 
            output = this.output = this.stkOutput.Pop(); 

            return seq; 
        }

        /// 
        /// Start construction of an Rtf. Return a new XmlQueryOutput object that will be used to construct this Rtf. 
        /// 
        public void StartRtfConstruction(string baseUri, out XmlQueryOutput output) { 
            // Push current writer 
            this.stkOutput.Push(this.output);
 
            // Create new XmlQueryOutput over an Rtf writer
            output = this.output = new XmlQueryOutput(this, new XmlEventCache(baseUri, true));
        }
 
        /// 
        /// End construction of an Rtf and return it as an RtfNavigator.  Return previous XmlQueryOutput object. 
        ///  
        public XPathNavigator EndRtfConstruction(out XmlQueryOutput output) {
            XmlEventCache events; 

            events = (XmlEventCache) this.output.Writer;

            // Restore previous XmlQueryOutput 
            output = this.output = this.stkOutput.Pop();
 
            // Return Rtf as an RtfNavigator 
            events.EndEvents();
            return new RtfTreeNavigator(events, this.nameTableQuery); 
        }

        /// 
        /// Construct a new RtfTextNavigator from the specified "text".  This is much more efficient than calling 
        /// StartNodeConstruction(), StartRtf(), WriteString(), EndRtf(), and EndNodeConstruction().
        ///  
        public XPathNavigator TextRtfConstruction(string text, string baseUri) { 
            return new RtfTextNavigator(text, baseUri);
        } 


        //-----------------------------------------------
        // Miscellaneous 
        //-----------------------------------------------
 
        ///  
        /// Report query execution information to event handler.
        ///  
        public void SendMessage(string message) {
            this.ctxt.OnXsltMessageEncountered(message);
        }
 
        /// 
        /// Throw an Xml exception having the specified message text. 
        ///  
        public void ThrowException(string text) {
            throw new XslTransformException(text); 
        }

        /// 
        /// Position navThis to the same location as navThat. 
        /// 
        internal static XPathNavigator SyncToNavigator(XPathNavigator navigatorThis, XPathNavigator navigatorThat) { 
            if (navigatorThis == null || !navigatorThis.MoveTo(navigatorThat)) 
                return navigatorThat.Clone();
 
            return navigatorThis;
        }

        ///  
        /// Function is called in Debug mode on each time context node change.
        ///  
        public static int OnCurrentNodeChanged(XPathNavigator currentNode) { 
            IXmlLineInfo lineInfo = currentNode as IXmlLineInfo;
 
            // In case of a namespace node, check whether it is inherited or locally defined
            if (lineInfo != null && ! (currentNode.NodeType == XPathNodeType.Namespace && IsInheritedNamespace(currentNode))) {
                OnCurrentNodeChanged2(currentNode.BaseURI, lineInfo.LineNumber, lineInfo.LinePosition);
            } 
            return 0;
        } 
 
 	// 'true' if current Namespace "inherited" from it's parent. Not defined localy.
        private static bool IsInheritedNamespace(XPathNavigator node) { 
            Debug.Assert(node.NodeType == XPathNodeType.Namespace);
            XPathNavigator nav = node.Clone();
            if (nav.MoveToParent()) {
                if (nav.MoveToFirstNamespace(XPathNamespaceScope.Local)) { 
                    do {
                        if ((object)nav.LocalName == (object)node.LocalName) { 
                            return false; 
                        }
                    } while (nav.MoveToNextNamespace(XPathNamespaceScope.Local)); 
                }
            }
            return true;
        } 

 
        private static void OnCurrentNodeChanged2(string baseUri, int lineNumber, int linePosition) {} 
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
                        

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