File: System\Xml\BinaryXml\XmlBinaryReader.cs
Project: ndp\fx\src\Xml\System.Xml.csproj (System.Xml)
//------------------------------------------------------------------------------
// <copyright file="XmlBinaryWriter.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
// <owner current="true" primary="true">Microsoft</owner>
//------------------------------------------------------------------------------
 
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Diagnostics;
using System.Globalization;
using System.Xml.Schema;
 
namespace System.Xml {
 
    internal sealed partial class XmlSqlBinaryReader : XmlReader, IXmlNamespaceResolver {
        internal static readonly Type TypeOfObject = typeof(System.Object);
        internal static readonly Type TypeOfString = typeof(System.String);
 
        static volatile Type[] TokenTypeMap = null;
 
        static byte[] XsdKatmaiTimeScaleToValueLengthMap = new byte[8] {
        // length scale
            3, // 0
            3, // 1
            3, // 2
            4, // 3
            4, // 4
            5, // 5
            5, // 6
            5, // 7
        };
 
        enum ScanState {
            Doc = 0,
            XmlText = 1,
            Attr = 2,
            AttrVal = 3,
            AttrValPseudoValue = 4,
            Init = 5,
            Error = 6,
            EOF = 7,
            Closed = 8
        }
 
        static ReadState[] ScanState2ReadState = {
            ReadState.Interactive,
            ReadState.Interactive,
            ReadState.Interactive,
            ReadState.Interactive,
            ReadState.Interactive,
            ReadState.Initial,
            ReadState.Error,
            ReadState.EndOfFile,
            ReadState.Closed
        };
 
        // Note: also used by XmlBinaryWriter
        internal struct QName {
            public string prefix;
            public string localname;
            public string namespaceUri;
 
            public QName(string prefix, string lname, string nsUri) {
                this.prefix = prefix; this.localname = lname; this.namespaceUri = nsUri;
            }
            public void Set(string prefix, string lname, string nsUri) {
                this.prefix = prefix; this.localname = lname; this.namespaceUri = nsUri;
            }
 
            public void Clear() {
                this.prefix = this.localname = this.namespaceUri = String.Empty;
            }
 
            public bool MatchNs(string lname, string nsUri) {
                return lname == this.localname && nsUri == this.namespaceUri;
            }
            public bool MatchPrefix(string prefix, string lname) {
                return lname == this.localname && prefix == this.prefix;
            }
 
            public void CheckPrefixNS(string prefix, string namespaceUri) {
                if (this.prefix == prefix && this.namespaceUri != namespaceUri)
                    throw new XmlException(Res.XmlBinary_NoRemapPrefix, new String[] { prefix, this.namespaceUri, namespaceUri });
            }
 
            public override int GetHashCode() {
                return this.prefix.GetHashCode() ^ this.localname.GetHashCode();
            }
 
            public int GetNSHashCode(SecureStringHasher hasher) {
                return hasher.GetHashCode(this.namespaceUri) ^ hasher.GetHashCode(this.localname);
            }
 
 
            public override bool Equals(object other) {
                if (other is QName) {
                    QName that = (QName)other;
                    return this == that;
                }
                return false;
            }
 
            public override string ToString() {
                if (prefix.Length == 0)
                    return this.localname;
                else
                    return this.prefix + ":" + this.localname;
            }
 
            public static bool operator ==(QName a, QName b) {
                return ((a.prefix == b.prefix)
                    && (a.localname == b.localname)
                    && (a.namespaceUri == b.namespaceUri));
            }
 
            public static bool operator !=(QName a, QName b) {
                return !(a == b);
            }
        };
 
        struct ElemInfo {
            public QName name;
            public string xmlLang;
            public XmlSpace xmlSpace;
            public bool xmlspacePreserve;
            public NamespaceDecl nsdecls;
 
            public void Set(QName name, bool xmlspacePreserve) {
                this.name = name;
                this.xmlLang = null;
                this.xmlSpace = XmlSpace.None;
                this.xmlspacePreserve = xmlspacePreserve;
            }
            public NamespaceDecl Clear() {
                NamespaceDecl nsdecls = this.nsdecls;
                this.nsdecls = null;
                return nsdecls;
            }
        };
 
        struct AttrInfo {
            public QName name;
            public string val;
            public int contentPos;
            public int hashCode;
            public int prevHash;
 
            public void Set(QName n, string v) {
                this.name = n;
                this.val = v;
                this.contentPos = 0;
                this.hashCode = 0;
                this.prevHash = 0;
            }
            public void Set(QName n, int pos) {
                this.name = n;
                this.val = null;
                this.contentPos = pos;
                this.hashCode = 0;
                this.prevHash = 0;
            }
 
            public void GetLocalnameAndNamespaceUri(out string localname, out string namespaceUri) {
                localname = this.name.localname;
                namespaceUri = this.name.namespaceUri;
            }
 
            public int GetLocalnameAndNamespaceUriAndHash(SecureStringHasher hasher, out string localname, out string namespaceUri) {
                localname = this.name.localname;
                namespaceUri = this.name.namespaceUri;
                return this.hashCode = this.name.GetNSHashCode(hasher);
            }
 
            public bool MatchNS(string localname, string namespaceUri) {
                return this.name.MatchNs(localname, namespaceUri);
            }
 
            public bool MatchHashNS(int hash, string localname, string namespaceUri) {
                return this.hashCode == hash && this.name.MatchNs(localname, namespaceUri);
            }
 
            public void AdjustPosition(int adj) {
                if (this.contentPos != 0)
                    this.contentPos += adj;
            }
        }
 
        class NamespaceDecl {
            public string prefix;
            public string uri;
            public NamespaceDecl scopeLink;
            public NamespaceDecl prevLink;
            public int scope;
            public bool implied;
 
            public NamespaceDecl(string prefix, string nsuri,
                                NamespaceDecl nextInScope, NamespaceDecl prevDecl,
                                int scope, bool implied) {
                this.prefix = prefix;
                this.uri = nsuri;
                this.scopeLink = nextInScope;
                this.prevLink = prevDecl;
                this.scope = scope;
                this.implied = implied;
            }
        }
 
        // symbol and qname tables
        struct SymbolTables {
            public string[] symtable;
            public int symCount;
            public QName[] qnametable;
            public int qnameCount;
            public void Init() {
                this.symtable = new string[64];
                this.qnametable = new QName[16];
                this.symtable[0] = String.Empty;
                this.symCount = 1;
                this.qnameCount = 1;
            }
        }
        class NestedBinXml {
            public SymbolTables symbolTables;
            public int docState;
            public NestedBinXml next;
            public NestedBinXml(SymbolTables symbolTables, int docState, NestedBinXml next) {
                this.symbolTables = symbolTables;
                this.docState = docState;
                this.next = next;
            }
        }
 
        // input data
        Stream inStrm;
        byte[] data;
        int pos;
        int mark;
        int end;
        long offset; // how much read and shift out of buffer
        bool eof;
        bool sniffed;
        bool isEmpty; // short-tag element start tag
 
        int docState; // 0=>auto, 1=>doc/pre-dtd, 2=>doc/pre-elem, 3=>doc/instance -1=>doc/post-elem, 9=>frag
 
        // symbol and qname tables
        SymbolTables symbolTables;
 
        XmlNameTable xnt;
        bool xntFromSettings;
        string xml;
        string xmlns;
        string nsxmlns;
 
        // base uri...
        string baseUri;
 
        // current parse state
        ScanState state;
        XmlNodeType nodetype;
        BinXmlToken token;
        // current attribute
        int attrIndex;
        // index of current qname
        QName qnameOther;
        // saved qname of element (for MoveToElement)
        QName qnameElement;
        XmlNodeType parentNodeType; // use for MoveToElement()
        // stack of current open element tags
        ElemInfo[] elementStack;
        int elemDepth;
        // current attributes
        AttrInfo[] attributes;
        int[] attrHashTbl;
        int attrCount;
        int posAfterAttrs;
        // xml:space
        bool xmlspacePreserve;
        // position/parse info for current typed token
        int tokLen;
        int tokDataPos;
        bool hasTypedValue;
        System.Type valueType;
        // if it is a simple string value, we cache it
        string stringValue;
        // hashtable of current namespaces
        Dictionary<String, NamespaceDecl> namespaces;
        //Hashtable namespaces;
        // linked list of pushed nametables (to support nested binary-xml documents)
        NestedBinXml prevNameInfo;
        // XmlTextReader to handle embeded text blocks
        XmlReader textXmlReader;
        // close input flag
        bool closeInput;
 
        bool checkCharacters;
        bool ignoreWhitespace;
        bool ignorePIs;
        bool ignoreComments;
        DtdProcessing dtdProcessing;
 
        SecureStringHasher hasher;
        XmlCharType xmlCharType;
        Encoding unicode;
 
        // current version of the protocol
        byte version;
 
        public XmlSqlBinaryReader(System.IO.Stream stream, byte[] data, int len, string baseUri, bool closeInput, XmlReaderSettings settings) {
            unicode = System.Text.Encoding.Unicode;
            xmlCharType = XmlCharType.Instance;
 
            this.xnt = settings.NameTable;
            if (this.xnt == null) {
                this.xnt = new NameTable();
                this.xntFromSettings = false;
            }
            else {
                this.xntFromSettings = true;
            }
            this.xml = this.xnt.Add("xml");
            this.xmlns = this.xnt.Add("xmlns");
            this.nsxmlns = this.xnt.Add(XmlReservedNs.NsXmlNs);
            this.baseUri = baseUri;
            this.state = ScanState.Init;
            this.nodetype = XmlNodeType.None;
            this.token = BinXmlToken.Error;
            this.elementStack = new ElemInfo[16];
            //this.elemDepth = 0;
            this.attributes = new AttrInfo[8];
            this.attrHashTbl = new int[8];
            //this.attrCount = 0;
            //this.attrIndex = 0;
            this.symbolTables.Init();
            this.qnameOther.Clear();
            this.qnameElement.Clear();
            this.xmlspacePreserve = false;
            this.hasher = new SecureStringHasher();
            this.namespaces = new Dictionary<String, NamespaceDecl>(hasher);
            AddInitNamespace(String.Empty, String.Empty);
            AddInitNamespace(this.xml, this.xnt.Add(XmlReservedNs.NsXml));
            AddInitNamespace(this.xmlns, this.nsxmlns);
            this.valueType = TypeOfString;
            // init buffer position, etc
            this.inStrm = stream;
            if (data != null) {
                Debug.Assert(len >= 2 && (data[0] == 0xdf && data[1] == 0xff));
                this.data = data;
                this.end = len;
                this.pos = 2;
                this.sniffed = true;
            }
            else {
                this.data = new byte[XmlReader.DefaultBufferSize];
                this.end = stream.Read(this.data, 0, XmlReader.DefaultBufferSize);
                this.pos = 0;
                this.sniffed = false;
            }
 
            this.mark = -1;
            this.eof = (0 == this.end);
            this.offset = 0;
            this.closeInput = closeInput;
            switch (settings.ConformanceLevel) {
                case ConformanceLevel.Auto:
                    this.docState = 0; break;
                case ConformanceLevel.Fragment:
                    this.docState = 9; break;
                case ConformanceLevel.Document:
                    this.docState = 1; break;
            }
            this.checkCharacters = settings.CheckCharacters;
            this.dtdProcessing = settings.DtdProcessing;
            this.ignoreWhitespace = settings.IgnoreWhitespace;
            this.ignorePIs = settings.IgnoreProcessingInstructions;
            this.ignoreComments = settings.IgnoreComments;
 
            if (TokenTypeMap == null)
                GenerateTokenTypeMap();
        }
 
        public override XmlReaderSettings Settings { 
            get {
                XmlReaderSettings settings = new XmlReaderSettings();
                if (xntFromSettings) {
                    settings.NameTable = xnt;
                }
                // 0=>auto, 1=>doc/pre-dtd, 2=>doc/pre-elem, 3=>doc/instance -1=>doc/post-elem, 9=>frag
                switch (this.docState) {
                    case 0:
                        settings.ConformanceLevel = ConformanceLevel.Auto; break;
                    case 9:
                        settings.ConformanceLevel = ConformanceLevel.Fragment; break;
                    default:
                        settings.ConformanceLevel = ConformanceLevel.Document; break;
                }
                settings.CheckCharacters = this.checkCharacters;
                settings.IgnoreWhitespace = this.ignoreWhitespace;
                settings.IgnoreProcessingInstructions = this.ignorePIs;
                settings.IgnoreComments = this.ignoreComments;
                settings.DtdProcessing = this.dtdProcessing;
                settings.CloseInput = this.closeInput;
 
                settings.ReadOnly = true;
                return settings;
            }
        }
 
        public override XmlNodeType NodeType {
            get {
                return this.nodetype;
            }
        }
 
        public override string LocalName {
            get {
                return this.qnameOther.localname;
            }
        }
 
        public override string NamespaceURI {
            get {
                return this.qnameOther.namespaceUri;
            }
        }
 
        public override string Prefix {
            get {
                return this.qnameOther.prefix;
            }
        }
 
        public override bool HasValue {
            get {
                if (ScanState.XmlText == this.state)
                    return this.textXmlReader.HasValue;
                else
                    return XmlReader.HasValueInternal(this.nodetype);
            }
        }
 
        public override string Value {
            get {
                if (null != this.stringValue)
                    return stringValue;
                switch (this.state) {
                    case ScanState.Doc:
                        switch (this.nodetype) {
                            case XmlNodeType.DocumentType:
                            case XmlNodeType.ProcessingInstruction:
                            case XmlNodeType.Comment:
                                return this.stringValue = GetString(this.tokDataPos, this.tokLen);
 
                            case XmlNodeType.CDATA:
                                return this.stringValue = CDATAValue();
 
                            case XmlNodeType.XmlDeclaration:
                                return this.stringValue = XmlDeclValue();
 
                            case XmlNodeType.Text:
                            case XmlNodeType.Whitespace:
                            case XmlNodeType.SignificantWhitespace:
                                return this.stringValue = ValueAsString(this.token);
                        }
                        break;
 
                    case ScanState.XmlText:
                        return this.textXmlReader.Value;
 
                    case ScanState.Attr:
                    case ScanState.AttrValPseudoValue:
                        return this.stringValue = GetAttributeText(this.attrIndex - 1);
 
                    case ScanState.AttrVal:
                        return this.stringValue = ValueAsString(this.token);
                }
                return String.Empty;
            }
        }
 
        public override int Depth {
            get {
                int adj = 0;
                switch (this.state) {
                    case ScanState.Doc:
                        if (this.nodetype == XmlNodeType.Element
                            || this.nodetype == XmlNodeType.EndElement)
                            adj = -1;
                        break;
 
                    case ScanState.XmlText:
                        adj = this.textXmlReader.Depth;
                        break;
 
                    case ScanState.Attr:
                        if (this.parentNodeType != XmlNodeType.Element)
                            adj = 1;
                        break;
                    case ScanState.AttrVal:
                    case ScanState.AttrValPseudoValue:
                        if (this.parentNodeType != XmlNodeType.Element)
                            adj = 1;
                        adj += 1;
                        break;
                    default:
                        return 0;
                }
                return this.elemDepth + adj;
            }
        }
 
        public override string BaseURI {
            get {
                return this.baseUri;
            }
        }
 
        public override bool IsEmptyElement {
            get {
                switch (this.state) {
                    case ScanState.Doc:
                    case ScanState.XmlText:
                        return this.isEmpty;
                    default:
                        return false;
                }
            }
        }
 
        public override XmlSpace XmlSpace {
            get {
                if (ScanState.XmlText != this.state) {
                    for (int i = this.elemDepth; i >= 0; i--) {
                        XmlSpace xs = this.elementStack[i].xmlSpace;
                        if (xs != XmlSpace.None)
                            return xs;
                    }
                    return XmlSpace.None;
                }
                else {
                    return this.textXmlReader.XmlSpace;
                }
            }
        }
 
        public override string XmlLang {
            get {
                if (ScanState.XmlText != this.state) {
                    for (int i = this.elemDepth; i >= 0; i--) {
                        string xl = this.elementStack[i].xmlLang;
                        if (null != xl)
                            return xl;
                    }
                    return string.Empty;
                }
                else {
                    return this.textXmlReader.XmlLang;
                }
            }
        }
 
        public override System.Type ValueType {
            get {
                return this.valueType;
            }
        }
 
        public override int AttributeCount {
            get {
                switch (this.state) {
                    case ScanState.Doc:
                    // for compatibility with XmlTextReader
                    //  we return the attribute count for the element
                    //  when positioned on an attribute under that
                    //  element...
                    case ScanState.Attr:
                    case ScanState.AttrVal:
                    case ScanState.AttrValPseudoValue:
                        return this.attrCount;
                    case ScanState.XmlText:
                        return this.textXmlReader.AttributeCount;
                    default:
                        return 0;
                }
            }
        }
 
        public override string GetAttribute(string name, string ns) {
            if (ScanState.XmlText == this.state) {
                return this.textXmlReader.GetAttribute(name, ns);
            }
            else {
                if (null == name)
                    throw new ArgumentNullException("name");
                if (null == ns)
                    ns = String.Empty;
                int index = LocateAttribute(name, ns);
                if (-1 == index)
                    return null;
                return GetAttribute(index);
            }
        }
 
        public override string GetAttribute(string name) {
            if (ScanState.XmlText == this.state) {
                return this.textXmlReader.GetAttribute(name);
            }
            else {
                int index = LocateAttribute(name);
                if (-1 == index)
                    return null;
                return GetAttribute(index);
            }
        }
 
        public override string GetAttribute(int i) {
            if (ScanState.XmlText == this.state) {
                return this.textXmlReader.GetAttribute(i);
            }
            else {
                if (i < 0 || i >= this.attrCount)
                    throw new ArgumentOutOfRangeException("i");
                return GetAttributeText(i);
            }
        }
 
        public override bool MoveToAttribute(string name, string ns) {
            if (ScanState.XmlText == this.state) {
                return UpdateFromTextReader(this.textXmlReader.MoveToAttribute(name, ns));
            }
            else {
                if (null == name)
                    throw new ArgumentNullException("name");
                if (null == ns)
                    ns = String.Empty;
                int index = LocateAttribute(name, ns);
                if ((-1 != index) && (this.state < ScanState.Init)) {
                    PositionOnAttribute(index + 1);
                    return true;
                }
                return false;
            }
        }
 
        public override bool MoveToAttribute(string name) {
            if (ScanState.XmlText == this.state) {
                return UpdateFromTextReader(this.textXmlReader.MoveToAttribute(name));
            }
            else {
                int index = LocateAttribute(name);
                if ((-1 != index) && (this.state < ScanState.Init)) {
                    PositionOnAttribute(index + 1);
                    return true;
                }
                return false;
            }
        }
 
        public override void MoveToAttribute(int i) {
            if (ScanState.XmlText == this.state) {
                this.textXmlReader.MoveToAttribute(i);
                UpdateFromTextReader(true);
            }
            else {
                if (i < 0 || i >= this.attrCount) {
                    throw new ArgumentOutOfRangeException("i");
                }
                PositionOnAttribute(i + 1);
            }
        }
 
        public override bool MoveToFirstAttribute() {
            if (ScanState.XmlText == this.state) {
                return UpdateFromTextReader(this.textXmlReader.MoveToFirstAttribute());
            }
            else {
                if (this.attrCount == 0)
                    return false;
                // set up for walking attributes
                PositionOnAttribute(1);
                return true;
            }
        }
 
        public override bool MoveToNextAttribute() {
            switch (this.state) {
                case ScanState.Doc:
                case ScanState.Attr:
                case ScanState.AttrVal:
                case ScanState.AttrValPseudoValue:
                    if (this.attrIndex >= this.attrCount)
                        return false;
                    PositionOnAttribute(++this.attrIndex);
                    return true;
 
                case ScanState.XmlText:
                    return UpdateFromTextReader(this.textXmlReader.MoveToNextAttribute());
 
                default:
                    return false;
            }
        }
 
        public override bool MoveToElement() {
            switch (this.state) {
                case ScanState.Attr:
                case ScanState.AttrVal:
                case ScanState.AttrValPseudoValue:
                    this.attrIndex = 0;
                    this.qnameOther = this.qnameElement;
                    if (XmlNodeType.Element == this.parentNodeType)
                        this.token = BinXmlToken.Element;
                    else if (XmlNodeType.XmlDeclaration == this.parentNodeType)
                        this.token = BinXmlToken.XmlDecl;
                    else if (XmlNodeType.DocumentType == this.parentNodeType)
                        this.token = BinXmlToken.DocType;
                    else
                        Debug.Fail("Unexpected parent NodeType");
                    this.nodetype = this.parentNodeType;
                    this.state = ScanState.Doc;
                    this.pos = this.posAfterAttrs;
                    this.stringValue = null;
                    return true;
 
                case ScanState.XmlText:
                    return UpdateFromTextReader(this.textXmlReader.MoveToElement());
 
                default:
                    return false;
            }
        }
 
        public override bool EOF {
            get {
                return this.state == ScanState.EOF;
            }
        }
 
        public override bool ReadAttributeValue() {
            this.stringValue = null;
            switch (this.state) {
                case ScanState.Attr:
                    if (null == this.attributes[this.attrIndex - 1].val) {
                        this.pos = this.attributes[this.attrIndex - 1].contentPos;
                        BinXmlToken tok = RescanNextToken();
                        if (BinXmlToken.Attr == tok || BinXmlToken.EndAttrs == tok) {
                            return false;
                        }
                        this.token = tok;
                        ReScanOverValue(tok);
                        this.valueType = GetValueType(tok);
                        this.state = ScanState.AttrVal;
                    }
                    else {
                        this.token = BinXmlToken.Error;
                        this.valueType = TypeOfString;
                        this.state = ScanState.AttrValPseudoValue;
                    }
                    this.qnameOther.Clear();
                    this.nodetype = XmlNodeType.Text;
                    return true;
 
                case ScanState.AttrVal:
                    return false;
 
                case ScanState.XmlText:
                    return UpdateFromTextReader(this.textXmlReader.ReadAttributeValue());
 
                default:
                    return false;
            }
        }
 
        public override void Close() {
            this.state = ScanState.Closed;
            this.nodetype = XmlNodeType.None;
            this.token = BinXmlToken.Error;
            this.stringValue = null;
            if (null != this.textXmlReader) {
                this.textXmlReader.Close();
                this.textXmlReader = null;
            }
            if (null != this.inStrm && closeInput)
                this.inStrm.Close();
            this.inStrm = null;
            this.pos = this.end = 0;
        }
 
        public override XmlNameTable NameTable {
            get {
                return this.xnt;
            }
        }
 
        public override string LookupNamespace(string prefix) {
            if (ScanState.XmlText == this.state)
                return this.textXmlReader.LookupNamespace(prefix);
            NamespaceDecl decl;
            if (prefix != null && this.namespaces.TryGetValue(prefix, out decl)) {
                Debug.Assert(decl != null);
                return decl.uri;
            }
            return null;
        }
 
        public override void ResolveEntity() {
            throw new NotSupportedException();
        }
 
        public override ReadState ReadState {
            get {
                return ScanState2ReadState[(int)this.state];
            }
        }
 
        public override bool Read() {
            try {
                switch (this.state) {
                    case ScanState.Init:
                        return ReadInit(false);
 
                    case ScanState.Doc:
                        return ReadDoc();
 
                    case ScanState.XmlText:
                        if (this.textXmlReader.Read()) {
                            return UpdateFromTextReader(true);
                        }
                        this.state = ScanState.Doc;
                        this.nodetype = XmlNodeType.None;
                        this.isEmpty = false;
                        goto case ScanState.Doc;
 
                    case ScanState.Attr:
                    case ScanState.AttrVal:
                    case ScanState.AttrValPseudoValue:
                        // clean up attribute stuff...
                        MoveToElement();
                        goto case ScanState.Doc;
 
                    default:
                        return false;
                }
            }
            catch (OverflowException e) {
                this.state = ScanState.Error;
                throw new XmlException(e.Message, e);
            }
            catch {
                this.state = ScanState.Error;
                throw;
            }
        }
 
        // Use default implementation of and ReadContentAsString and ReadElementContentAsString
        // (there is no benefit to providing a custom version)
        // public override bool ReadElementContentAsString( string localName, string namespaceURI )
        // public override bool ReadElementContentAsString()
        // public override bool ReadContentAsString()
 
        // Do setup work for ReadContentAsXXX methods
        // If ready for a typed value read, returns true, otherwise returns
        //  false to indicate caller should ball back to XmlReader.ReadContentAsXXX
        // Special-Case: returns true and positioned on Element or EndElem to force parse of empty-string
        private bool SetupContentAsXXX(string name) {
            if (!CanReadContentAs(this.NodeType)) {
                throw CreateReadContentAsException(name);
            }
            switch (this.state) {
                case ScanState.Doc:
                    if (this.NodeType == XmlNodeType.EndElement)
                        return true;
                    if (this.NodeType == XmlNodeType.ProcessingInstruction || this.NodeType == XmlNodeType.Comment) {
                        while (Read() && (this.NodeType == XmlNodeType.ProcessingInstruction || this.NodeType == XmlNodeType.Comment))
                            ;
                        if (this.NodeType == XmlNodeType.EndElement)
                            return true;
                    }
                    if (this.hasTypedValue) {
                        return true;
                    }
                    break;
                case ScanState.Attr:
                    this.pos = this.attributes[this.attrIndex - 1].contentPos;
                    BinXmlToken token = RescanNextToken();
                    if (BinXmlToken.Attr == token || BinXmlToken.EndAttrs == token)
                        break;
                    this.token = token;
                    ReScanOverValue(token);
                    return true;
                case ScanState.AttrVal:
                    return true;
                default:
                    break;
            }
            return false;
        }
 
        private int FinishContentAsXXX(int origPos) {
            if (this.state == ScanState.Doc) {
                // if we are already on a tag, then don't move
                if (this.NodeType != XmlNodeType.Element && this.NodeType != XmlNodeType.EndElement) {
                // advance over PIs and Comments
                Loop:
                    if (Read()) {
                        switch (this.NodeType) {
                            case XmlNodeType.ProcessingInstruction:
                            case XmlNodeType.Comment:
                                goto Loop;
 
                            case XmlNodeType.Element:
                            case XmlNodeType.EndElement:
                                break;
 
                            default:
                                throw ThrowNotSupported(Res.XmlBinary_ListsOfValuesNotSupported);
                        }
                    }
                }
                return this.pos;
            }
            return origPos;
        }
 
        public override bool ReadContentAsBoolean() {
            int origPos = this.pos;
            bool value = false;
            try {
                if (SetupContentAsXXX("ReadContentAsBoolean")) {
                    try {
                        switch (this.token) {
                            case BinXmlToken.XSD_BOOLEAN:
                                value = 0 != this.data[this.tokDataPos];
                                break;
 
                            case BinXmlToken.SQL_BIT:
                            case BinXmlToken.SQL_TINYINT:
                            case BinXmlToken.SQL_SMALLINT:
                            case BinXmlToken.SQL_INT:
                            case BinXmlToken.SQL_BIGINT:
                            case BinXmlToken.SQL_REAL:
                            case BinXmlToken.SQL_FLOAT:
                            case BinXmlToken.SQL_MONEY:
                            case BinXmlToken.SQL_SMALLMONEY:
                            case BinXmlToken.SQL_DATETIME:
                            case BinXmlToken.SQL_SMALLDATETIME:
                            case BinXmlToken.SQL_DECIMAL:
                            case BinXmlToken.SQL_NUMERIC:
                            case BinXmlToken.XSD_DECIMAL:
                            case BinXmlToken.SQL_UUID:
                            case BinXmlToken.SQL_VARBINARY:
                            case BinXmlToken.SQL_BINARY:
                            case BinXmlToken.SQL_IMAGE:
                            case BinXmlToken.SQL_UDT:
                            case BinXmlToken.XSD_KATMAI_DATE:
                            case BinXmlToken.XSD_KATMAI_DATETIME:
                            case BinXmlToken.XSD_KATMAI_TIME:
                            case BinXmlToken.XSD_KATMAI_DATEOFFSET:
                            case BinXmlToken.XSD_KATMAI_DATETIMEOFFSET:
                            case BinXmlToken.XSD_KATMAI_TIMEOFFSET:
                            case BinXmlToken.XSD_BINHEX:
                            case BinXmlToken.XSD_BASE64:
                            case BinXmlToken.XSD_TIME:
                            case BinXmlToken.XSD_DATETIME:
                            case BinXmlToken.XSD_DATE:
                            case BinXmlToken.XSD_BYTE:
                            case BinXmlToken.XSD_UNSIGNEDSHORT:
                            case BinXmlToken.XSD_UNSIGNEDINT:
                            case BinXmlToken.XSD_UNSIGNEDLONG:
                            case BinXmlToken.XSD_QNAME:
                                throw new InvalidCastException(Res.GetString(Res.XmlBinary_CastNotSupported, this.token, "Boolean"));
 
                            case BinXmlToken.SQL_CHAR:
                            case BinXmlToken.SQL_VARCHAR:
                            case BinXmlToken.SQL_TEXT:
                            case BinXmlToken.SQL_NCHAR:
                            case BinXmlToken.SQL_NVARCHAR:
                            case BinXmlToken.SQL_NTEXT:
                                goto Fallback;
 
                            case BinXmlToken.Element:
                            case BinXmlToken.EndElem:
                                return XmlConvert.ToBoolean(String.Empty);
 
                            default:
                                Debug.Fail("should never happen");
                                goto Fallback;
                        }
                    }
                    catch (InvalidCastException e) {
                        throw new XmlException(Res.Xml_ReadContentAsFormatException, "Boolean", e, null);
                    }
                    catch (FormatException e) {
                        throw new XmlException(Res.Xml_ReadContentAsFormatException, "Boolean", e, null);
                    }
                    origPos = FinishContentAsXXX(origPos);
                    return value;
                }
            }
            finally {
                this.pos = origPos;
            }
        Fallback:
            return base.ReadContentAsBoolean();
        }
 
        public override DateTime ReadContentAsDateTime() {
            int origPos = this.pos;
            DateTime value;
            try {
                if (SetupContentAsXXX("ReadContentAsDateTime")) {
                    try {
                        switch (this.token) {
                            case BinXmlToken.SQL_DATETIME:
                            case BinXmlToken.SQL_SMALLDATETIME:
                            case BinXmlToken.XSD_TIME:
                            case BinXmlToken.XSD_DATETIME:
                            case BinXmlToken.XSD_DATE:
                            case BinXmlToken.XSD_KATMAI_DATE:
                            case BinXmlToken.XSD_KATMAI_DATETIME:
                            case BinXmlToken.XSD_KATMAI_TIME:
                            case BinXmlToken.XSD_KATMAI_DATEOFFSET:
                            case BinXmlToken.XSD_KATMAI_DATETIMEOFFSET:
                            case BinXmlToken.XSD_KATMAI_TIMEOFFSET:
                                value = ValueAsDateTime();
                                break;
 
                            case BinXmlToken.SQL_BIT:
                            case BinXmlToken.SQL_TINYINT:
                            case BinXmlToken.SQL_SMALLINT:
                            case BinXmlToken.SQL_INT:
                            case BinXmlToken.SQL_BIGINT:
                            case BinXmlToken.SQL_REAL:
                            case BinXmlToken.SQL_FLOAT:
                            case BinXmlToken.SQL_MONEY:
                            case BinXmlToken.SQL_SMALLMONEY:
                            case BinXmlToken.SQL_DECIMAL:
                            case BinXmlToken.SQL_NUMERIC:
                            case BinXmlToken.XSD_DECIMAL:
                            case BinXmlToken.SQL_UUID:
                            case BinXmlToken.SQL_VARBINARY:
                            case BinXmlToken.SQL_BINARY:
                            case BinXmlToken.SQL_IMAGE:
                            case BinXmlToken.SQL_UDT:
                            case BinXmlToken.XSD_BINHEX:
                            case BinXmlToken.XSD_BASE64:
                            case BinXmlToken.XSD_BOOLEAN:
                            case BinXmlToken.XSD_BYTE:
                            case BinXmlToken.XSD_UNSIGNEDSHORT:
                            case BinXmlToken.XSD_UNSIGNEDINT:
                            case BinXmlToken.XSD_UNSIGNEDLONG:
                            case BinXmlToken.XSD_QNAME:
                                throw new InvalidCastException(Res.GetString(Res.XmlBinary_CastNotSupported, this.token, "DateTime"));
 
                            case BinXmlToken.SQL_CHAR:
                            case BinXmlToken.SQL_VARCHAR:
                            case BinXmlToken.SQL_TEXT:
                            case BinXmlToken.SQL_NCHAR:
                            case BinXmlToken.SQL_NVARCHAR:
                            case BinXmlToken.SQL_NTEXT:
                                goto Fallback;
 
                            case BinXmlToken.Element:
                            case BinXmlToken.EndElem:
                                return XmlConvert.ToDateTime(String.Empty, XmlDateTimeSerializationMode.RoundtripKind);
 
                            default:
                                Debug.Fail("should never happen");
                                goto Fallback;
                        }
                    }
                    catch (InvalidCastException e) {
                        throw new XmlException(Res.Xml_ReadContentAsFormatException, "DateTime", e, null);
                    }
                    catch (FormatException e) {
                        throw new XmlException(Res.Xml_ReadContentAsFormatException, "DateTime", e, null);
                    }
                    catch (OverflowException e) {
                        throw new XmlException(Res.Xml_ReadContentAsFormatException, "DateTime", e, null);
                    }
 
                    origPos = FinishContentAsXXX(origPos);
                    return value;
                }
            }
            finally {
                this.pos = origPos;
            }
        Fallback:
            return base.ReadContentAsDateTime();
        }
 
        public override Double ReadContentAsDouble() {
            int origPos = this.pos;
            Double value;
            try {
                if (SetupContentAsXXX("ReadContentAsDouble")) {
                    try {
                        switch (this.token) {
                            case BinXmlToken.SQL_REAL:
                            case BinXmlToken.SQL_FLOAT:
                                value = ValueAsDouble();
                                break;
 
                            case BinXmlToken.SQL_BIT:
                            case BinXmlToken.SQL_TINYINT:
                            case BinXmlToken.SQL_SMALLINT:
                            case BinXmlToken.SQL_INT:
                            case BinXmlToken.SQL_BIGINT:
                            case BinXmlToken.SQL_MONEY:
                            case BinXmlToken.SQL_SMALLMONEY:
                            case BinXmlToken.SQL_DATETIME:
                            case BinXmlToken.SQL_SMALLDATETIME:
                            case BinXmlToken.SQL_DECIMAL:
                            case BinXmlToken.SQL_NUMERIC:
                            case BinXmlToken.XSD_DECIMAL:
                            case BinXmlToken.SQL_UUID:
                            case BinXmlToken.SQL_VARBINARY:
                            case BinXmlToken.SQL_BINARY:
                            case BinXmlToken.SQL_IMAGE:
                            case BinXmlToken.SQL_UDT:
                            case BinXmlToken.XSD_KATMAI_DATE:
                            case BinXmlToken.XSD_KATMAI_DATETIME:
                            case BinXmlToken.XSD_KATMAI_TIME:
                            case BinXmlToken.XSD_KATMAI_DATEOFFSET:
                            case BinXmlToken.XSD_KATMAI_DATETIMEOFFSET:
                            case BinXmlToken.XSD_KATMAI_TIMEOFFSET:
                            case BinXmlToken.XSD_BINHEX:
                            case BinXmlToken.XSD_BASE64:
                            case BinXmlToken.XSD_BOOLEAN:
                            case BinXmlToken.XSD_TIME:
                            case BinXmlToken.XSD_DATETIME:
                            case BinXmlToken.XSD_DATE:
                            case BinXmlToken.XSD_BYTE:
                            case BinXmlToken.XSD_UNSIGNEDSHORT:
                            case BinXmlToken.XSD_UNSIGNEDINT:
                            case BinXmlToken.XSD_UNSIGNEDLONG:
                            case BinXmlToken.XSD_QNAME:
                                throw new InvalidCastException(Res.GetString(Res.XmlBinary_CastNotSupported, this.token, "Double"));
 
                            case BinXmlToken.SQL_CHAR:
                            case BinXmlToken.SQL_VARCHAR:
                            case BinXmlToken.SQL_TEXT:
                            case BinXmlToken.SQL_NCHAR:
                            case BinXmlToken.SQL_NVARCHAR:
                            case BinXmlToken.SQL_NTEXT:
                                goto Fallback;
 
                            case BinXmlToken.Element:
                            case BinXmlToken.EndElem:
                                return XmlConvert.ToDouble(String.Empty);
 
                            default:
                                Debug.Fail("should never happen");
                                goto Fallback;
                        }
                    }
                    catch (InvalidCastException e) {
                        throw new XmlException(Res.Xml_ReadContentAsFormatException, "Double", e, null);
                    }
                    catch (FormatException e) {
                        throw new XmlException(Res.Xml_ReadContentAsFormatException, "Double", e, null);
                    }
                    catch (OverflowException e) {
                        throw new XmlException(Res.Xml_ReadContentAsFormatException, "Double", e, null);
                    }
 
                    origPos = FinishContentAsXXX(origPos);
                    return value;
                }
            }
            finally {
                this.pos = origPos;
            }
        Fallback:
            return base.ReadContentAsDouble();
        }
 
        public override float ReadContentAsFloat() {
            int origPos = this.pos;
            float value;
            try {
                if (SetupContentAsXXX("ReadContentAsFloat")) {
                    try {
                        switch (this.token) {
                            case BinXmlToken.SQL_REAL:
                            case BinXmlToken.SQL_FLOAT:
                                value = checked (((float)ValueAsDouble()));
                                break;
 
                            case BinXmlToken.SQL_BIT:
                            case BinXmlToken.SQL_TINYINT:
                            case BinXmlToken.SQL_SMALLINT:
                            case BinXmlToken.SQL_INT:
                            case BinXmlToken.SQL_BIGINT:
                            case BinXmlToken.SQL_MONEY:
                            case BinXmlToken.SQL_SMALLMONEY:
                            case BinXmlToken.SQL_DATETIME:
                            case BinXmlToken.SQL_SMALLDATETIME:
                            case BinXmlToken.SQL_DECIMAL:
                            case BinXmlToken.SQL_NUMERIC:
                            case BinXmlToken.XSD_DECIMAL:
                            case BinXmlToken.SQL_UUID:
                            case BinXmlToken.SQL_VARBINARY:
                            case BinXmlToken.SQL_BINARY:
                            case BinXmlToken.SQL_IMAGE:
                            case BinXmlToken.SQL_UDT:
                            case BinXmlToken.XSD_KATMAI_DATE:
                            case BinXmlToken.XSD_KATMAI_DATETIME:
                            case BinXmlToken.XSD_KATMAI_TIME:
                            case BinXmlToken.XSD_KATMAI_DATEOFFSET:
                            case BinXmlToken.XSD_KATMAI_DATETIMEOFFSET:
                            case BinXmlToken.XSD_KATMAI_TIMEOFFSET:
                            case BinXmlToken.XSD_BINHEX:
                            case BinXmlToken.XSD_BASE64:
                            case BinXmlToken.XSD_BOOLEAN:
                            case BinXmlToken.XSD_TIME:
                            case BinXmlToken.XSD_DATETIME:
                            case BinXmlToken.XSD_DATE:
                            case BinXmlToken.XSD_BYTE:
                            case BinXmlToken.XSD_UNSIGNEDSHORT:
                            case BinXmlToken.XSD_UNSIGNEDINT:
                            case BinXmlToken.XSD_UNSIGNEDLONG:
                            case BinXmlToken.XSD_QNAME:
                                throw new InvalidCastException(Res.GetString(Res.XmlBinary_CastNotSupported, this.token, "Float"));
 
                            case BinXmlToken.SQL_CHAR:
                            case BinXmlToken.SQL_VARCHAR:
                            case BinXmlToken.SQL_TEXT:
                            case BinXmlToken.SQL_NCHAR:
                            case BinXmlToken.SQL_NVARCHAR:
                            case BinXmlToken.SQL_NTEXT:
                                goto Fallback;
 
                            case BinXmlToken.Element:
                            case BinXmlToken.EndElem:
                                return XmlConvert.ToSingle(String.Empty);
 
                            default:
                                Debug.Fail("should never happen");
                                goto Fallback;
                        }
                    }
                    catch (InvalidCastException e) {
                        throw new XmlException(Res.Xml_ReadContentAsFormatException, "Float", e, null);
                    }
                    catch (FormatException e) {
                        throw new XmlException(Res.Xml_ReadContentAsFormatException, "Float", e, null);
                    }
                    catch (OverflowException e) {
                        throw new XmlException(Res.Xml_ReadContentAsFormatException, "Float", e, null);
                    }
 
                    origPos = FinishContentAsXXX(origPos);
                    return value;
                }
            }
            finally {
                this.pos = origPos;
            }
        Fallback:
            return base.ReadContentAsFloat();
        }
 
        public override decimal ReadContentAsDecimal() {
            int origPos = this.pos;
            decimal value;
            try {
                if (SetupContentAsXXX("ReadContentAsDecimal")) {
                    try {
                        switch (this.token) {
                            case BinXmlToken.SQL_BIT:
                            case BinXmlToken.SQL_TINYINT:
                            case BinXmlToken.SQL_SMALLINT:
                            case BinXmlToken.SQL_INT:
                            case BinXmlToken.SQL_BIGINT:
                            case BinXmlToken.SQL_MONEY:
                            case BinXmlToken.SQL_SMALLMONEY:
                            case BinXmlToken.SQL_DECIMAL:
                            case BinXmlToken.SQL_NUMERIC:
                            case BinXmlToken.XSD_DECIMAL:
                            case BinXmlToken.XSD_BYTE:
                            case BinXmlToken.XSD_UNSIGNEDSHORT:
                            case BinXmlToken.XSD_UNSIGNEDINT:
                            case BinXmlToken.XSD_UNSIGNEDLONG:
                                value = ValueAsDecimal();
                                break;
 
                            case BinXmlToken.SQL_REAL:
                            case BinXmlToken.SQL_FLOAT:
                            case BinXmlToken.SQL_DATETIME:
                            case BinXmlToken.SQL_SMALLDATETIME:
                            case BinXmlToken.SQL_UUID:
                            case BinXmlToken.SQL_VARBINARY:
                            case BinXmlToken.SQL_BINARY:
                            case BinXmlToken.SQL_IMAGE:
                            case BinXmlToken.SQL_UDT:
                            case BinXmlToken.XSD_KATMAI_DATE:
                            case BinXmlToken.XSD_KATMAI_DATETIME:
                            case BinXmlToken.XSD_KATMAI_TIME:
                            case BinXmlToken.XSD_KATMAI_DATEOFFSET:
                            case BinXmlToken.XSD_KATMAI_DATETIMEOFFSET:
                            case BinXmlToken.XSD_KATMAI_TIMEOFFSET:
                            case BinXmlToken.XSD_BINHEX:
                            case BinXmlToken.XSD_BASE64:
                            case BinXmlToken.XSD_BOOLEAN:
                            case BinXmlToken.XSD_TIME:
                            case BinXmlToken.XSD_DATETIME:
                            case BinXmlToken.XSD_DATE:
                            case BinXmlToken.XSD_QNAME:
                                throw new InvalidCastException(Res.GetString(Res.XmlBinary_CastNotSupported, this.token, "Decimal"));
 
                            case BinXmlToken.SQL_CHAR:
                            case BinXmlToken.SQL_VARCHAR:
                            case BinXmlToken.SQL_TEXT:
                            case BinXmlToken.SQL_NCHAR:
                            case BinXmlToken.SQL_NVARCHAR:
                            case BinXmlToken.SQL_NTEXT:
                                goto Fallback;
 
                            case BinXmlToken.Element:
                            case BinXmlToken.EndElem:
                                return XmlConvert.ToDecimal(String.Empty);
 
                            default:
                                Debug.Fail("should never happen");
                                goto Fallback;
                        }
                    }
                    catch (InvalidCastException e) {
                        throw new XmlException(Res.Xml_ReadContentAsFormatException, "Decimal", e, null);
                    }
                    catch (FormatException e) {
                        throw new XmlException(Res.Xml_ReadContentAsFormatException, "Decimal", e, null);
                    }
                    catch (OverflowException e) {
                        throw new XmlException(Res.Xml_ReadContentAsFormatException, "Decimal", e, null);
                    }
 
                    origPos = FinishContentAsXXX(origPos);
                    return value;
                }
            }
            finally {
                this.pos = origPos;
            }
        Fallback:
            return base.ReadContentAsDecimal();
        }
 
        public override int ReadContentAsInt() {
            int origPos = this.pos;
            int value;
            try {
                if (SetupContentAsXXX("ReadContentAsInt")) {
                    try {
                        switch (this.token) {
                            case BinXmlToken.SQL_BIT:
                            case BinXmlToken.SQL_TINYINT:
                            case BinXmlToken.SQL_SMALLINT:
                            case BinXmlToken.SQL_INT:
                            case BinXmlToken.SQL_BIGINT:
                            case BinXmlToken.SQL_MONEY:
                            case BinXmlToken.SQL_SMALLMONEY:
                            case BinXmlToken.SQL_DECIMAL:
                            case BinXmlToken.SQL_NUMERIC:
                            case BinXmlToken.XSD_DECIMAL:
                            case BinXmlToken.XSD_BYTE:
                            case BinXmlToken.XSD_UNSIGNEDSHORT:
                            case BinXmlToken.XSD_UNSIGNEDINT:
                            case BinXmlToken.XSD_UNSIGNEDLONG:
                                value = checked((int)ValueAsLong());
                                break;
 
                            case BinXmlToken.SQL_REAL:
                            case BinXmlToken.SQL_FLOAT:
                            case BinXmlToken.SQL_DATETIME:
                            case BinXmlToken.SQL_SMALLDATETIME:
                            case BinXmlToken.SQL_UUID:
                            case BinXmlToken.SQL_VARBINARY:
                            case BinXmlToken.SQL_BINARY:
                            case BinXmlToken.SQL_IMAGE:
                            case BinXmlToken.SQL_UDT:
                            case BinXmlToken.XSD_KATMAI_DATE:
                            case BinXmlToken.XSD_KATMAI_DATETIME:
                            case BinXmlToken.XSD_KATMAI_TIME:
                            case BinXmlToken.XSD_KATMAI_DATEOFFSET:
                            case BinXmlToken.XSD_KATMAI_DATETIMEOFFSET:
                            case BinXmlToken.XSD_KATMAI_TIMEOFFSET:
                            case BinXmlToken.XSD_BINHEX:
                            case BinXmlToken.XSD_BASE64:
                            case BinXmlToken.XSD_BOOLEAN:
                            case BinXmlToken.XSD_TIME:
                            case BinXmlToken.XSD_DATETIME:
                            case BinXmlToken.XSD_DATE:
                            case BinXmlToken.XSD_QNAME:
                                throw new InvalidCastException(Res.GetString(Res.XmlBinary_CastNotSupported, this.token, "Int32"));
 
                            case BinXmlToken.SQL_CHAR:
                            case BinXmlToken.SQL_VARCHAR:
                            case BinXmlToken.SQL_TEXT:
                            case BinXmlToken.SQL_NCHAR:
                            case BinXmlToken.SQL_NVARCHAR:
                            case BinXmlToken.SQL_NTEXT:
                                goto Fallback;
 
                            case BinXmlToken.Element:
                            case BinXmlToken.EndElem:
                                return XmlConvert.ToInt32(String.Empty);
 
                            default:
                                Debug.Fail("should never happen");
                                goto Fallback;
                        }
                    }
                    catch (InvalidCastException e) {
                        throw new XmlException(Res.Xml_ReadContentAsFormatException, "Int32", e, null);
                    }
                    catch (FormatException e) {
                        throw new XmlException(Res.Xml_ReadContentAsFormatException, "Int32", e, null);
                    }
                    catch (OverflowException e) {
                        throw new XmlException(Res.Xml_ReadContentAsFormatException, "Int32", e, null);
                    }
 
                    origPos = FinishContentAsXXX(origPos);
                    return value;
                }
            }
            finally {
                this.pos = origPos;
            }
        Fallback:
            return base.ReadContentAsInt();
        }
 
        public override long ReadContentAsLong() {
            int origPos = this.pos;
            long value;
            try {
                if (SetupContentAsXXX("ReadContentAsLong")) {
                    try {
                        switch (this.token) {
                            case BinXmlToken.SQL_BIT:
                            case BinXmlToken.SQL_TINYINT:
                            case BinXmlToken.SQL_SMALLINT:
                            case BinXmlToken.SQL_INT:
                            case BinXmlToken.SQL_BIGINT:
                            case BinXmlToken.SQL_MONEY:
                            case BinXmlToken.SQL_SMALLMONEY:
                            case BinXmlToken.SQL_DECIMAL:
                            case BinXmlToken.SQL_NUMERIC:
                            case BinXmlToken.XSD_DECIMAL:
                            case BinXmlToken.XSD_BYTE:
                            case BinXmlToken.XSD_UNSIGNEDSHORT:
                            case BinXmlToken.XSD_UNSIGNEDINT:
                            case BinXmlToken.XSD_UNSIGNEDLONG:
                                value = ValueAsLong();
                                break;
 
                            case BinXmlToken.SQL_REAL:
                            case BinXmlToken.SQL_FLOAT:
                            case BinXmlToken.SQL_DATETIME:
                            case BinXmlToken.SQL_SMALLDATETIME:
                            case BinXmlToken.SQL_UUID:
                            case BinXmlToken.SQL_VARBINARY:
                            case BinXmlToken.SQL_BINARY:
                            case BinXmlToken.SQL_IMAGE:
                            case BinXmlToken.SQL_UDT:
                            case BinXmlToken.XSD_KATMAI_DATE:
                            case BinXmlToken.XSD_KATMAI_DATETIME:
                            case BinXmlToken.XSD_KATMAI_TIME:
                            case BinXmlToken.XSD_KATMAI_DATEOFFSET:
                            case BinXmlToken.XSD_KATMAI_DATETIMEOFFSET:
                            case BinXmlToken.XSD_KATMAI_TIMEOFFSET:
                            case BinXmlToken.XSD_BINHEX:
                            case BinXmlToken.XSD_BASE64:
                            case BinXmlToken.XSD_BOOLEAN:
                            case BinXmlToken.XSD_TIME:
                            case BinXmlToken.XSD_DATETIME:
                            case BinXmlToken.XSD_DATE:
                            case BinXmlToken.XSD_QNAME:
                                throw new InvalidCastException(Res.GetString(Res.XmlBinary_CastNotSupported, this.token, "Int64"));
 
                            case BinXmlToken.SQL_CHAR:
                            case BinXmlToken.SQL_VARCHAR:
                            case BinXmlToken.SQL_TEXT:
                            case BinXmlToken.SQL_NCHAR:
                            case BinXmlToken.SQL_NVARCHAR:
                            case BinXmlToken.SQL_NTEXT:
                                goto Fallback;
 
                            case BinXmlToken.Element:
                            case BinXmlToken.EndElem:
                                return XmlConvert.ToInt64(String.Empty);
 
                            default:
                                Debug.Fail("should never happen");
                                goto Fallback;
                        }
                    }
                    catch (InvalidCastException e) {
                        throw new XmlException(Res.Xml_ReadContentAsFormatException, "Int64", e, null);
                    }
                    catch (FormatException e) {
                        throw new XmlException(Res.Xml_ReadContentAsFormatException, "Int64", e, null);
                    }
                    catch (OverflowException e) {
                        throw new XmlException(Res.Xml_ReadContentAsFormatException, "Int64", e, null);
                    }
 
                    origPos = FinishContentAsXXX(origPos);
                    return value;
                }
            }
            finally {
                this.pos = origPos;
            }
        Fallback:
            return base.ReadContentAsLong();
        }
 
        public override object ReadContentAsObject() {
            int origPos = this.pos;
            try {
                if (SetupContentAsXXX("ReadContentAsObject")) {
                    object value;
                    try {
                        if (this.NodeType == XmlNodeType.Element || this.NodeType == XmlNodeType.EndElement)
                            value = String.Empty;
                        else
                            value = this.ValueAsObject(this.token, false);
                    }
                    catch (InvalidCastException e) {
                        throw new XmlException(Res.Xml_ReadContentAsFormatException, "Object", e, null);
                    }
                    catch (FormatException e) {
                        throw new XmlException(Res.Xml_ReadContentAsFormatException, "Object", e, null);
                    }
                    catch (OverflowException e) {
                        throw new XmlException(Res.Xml_ReadContentAsFormatException, "Object", e, null);
                    }
                    origPos = FinishContentAsXXX(origPos);
                    return value;
                }
            }
            finally {
                this.pos = origPos;
            }
            //Fallback:
            return base.ReadContentAsObject();
        }
 
        public override object ReadContentAs(Type returnType, IXmlNamespaceResolver namespaceResolver) {
            int origPos = this.pos;
            try {
                if (SetupContentAsXXX("ReadContentAs")) {
                    object value;
                    try {
                        if (this.NodeType == XmlNodeType.Element || this.NodeType == XmlNodeType.EndElement) {
                            value = String.Empty;
                        }
                        else if (returnType == this.ValueType || returnType == typeof(object)) {
                            value = this.ValueAsObject(this.token, false);
                        }
                        else {
                            value = this.ValueAs(this.token, returnType, namespaceResolver);
                        }
                    }
                    catch (InvalidCastException e) {
                        throw new XmlException(Res.Xml_ReadContentAsFormatException, returnType.ToString(), e, null);
                    }
                    catch (FormatException e) {
                        throw new XmlException(Res.Xml_ReadContentAsFormatException, returnType.ToString(), e, null);
                    }
                    catch (OverflowException e) {
                        throw new XmlException(Res.Xml_ReadContentAsFormatException, returnType.ToString(), e, null);
                    }
                    origPos = FinishContentAsXXX(origPos);
                    return value;
                }
            }
            finally {
                this.pos = origPos;
            }
            return base.ReadContentAs(returnType, namespaceResolver);
        }
 
        //////////
        // IXmlNamespaceResolver
 
        System.Collections.Generic.IDictionary<string, string> IXmlNamespaceResolver.GetNamespacesInScope(XmlNamespaceScope scope) {
            if (ScanState.XmlText == this.state) {
                IXmlNamespaceResolver resolver = (IXmlNamespaceResolver)this.textXmlReader;
                return resolver.GetNamespacesInScope(scope);
            }
            else {
                Dictionary<String, String> nstable = new Dictionary<String, String>();
                if (XmlNamespaceScope.Local == scope) {
                    // are we even inside an element? (depth==0 is where we have xml, and xmlns declared...)
                    if (this.elemDepth > 0) {
                        NamespaceDecl nsdecl = this.elementStack[this.elemDepth].nsdecls;
                        while (null != nsdecl) {
                            nstable.Add(nsdecl.prefix, nsdecl.uri);
                            nsdecl = nsdecl.scopeLink;
                        }
                    }
                }
                else {
                    foreach (NamespaceDecl nsdecl in this.namespaces.Values) {
                        // don't add predefined decls unless scope == all, then only add 'xml'                       
                        if (nsdecl.scope != -1 || (XmlNamespaceScope.All == scope && "xml" == nsdecl.prefix)) {
                            // xmlns="" only ever reported via scope==local
                            if (nsdecl.prefix.Length > 0 || nsdecl.uri.Length > 0)
                                nstable.Add(nsdecl.prefix, nsdecl.uri);
                        }
                    }
                }
                return nstable;
            }
        }
 
        string IXmlNamespaceResolver.LookupPrefix(string namespaceName) {
            if (ScanState.XmlText == this.state) {
                IXmlNamespaceResolver resolver = (IXmlNamespaceResolver)this.textXmlReader;
                return resolver.LookupPrefix(namespaceName);
            }
            else {
                if (null == namespaceName)
                    return null;
 
                namespaceName = this.xnt.Get(namespaceName);
                if (null == namespaceName)
                    return null;
 
                for (int i = this.elemDepth; i >= 0; i--) {
                    NamespaceDecl nsdecl = this.elementStack[i].nsdecls;
                    while (null != nsdecl) {
                        if ((object)nsdecl.uri == (object)namespaceName)
                            return nsdecl.prefix;
                        nsdecl = nsdecl.scopeLink;
                    }
                }
                return null;
            }
        }
 
        //////////
        // Internal implementation methods
 
        void VerifyVersion(int requiredVersion, BinXmlToken token) {
            if (version < requiredVersion) {
                throw ThrowUnexpectedToken(token);
            }
        }
 
        void AddInitNamespace(string prefix, string uri) {
            NamespaceDecl nsdecl = new NamespaceDecl(prefix, uri, this.elementStack[0].nsdecls, null, -1, true);
            this.elementStack[0].nsdecls = nsdecl;
            this.namespaces.Add(prefix, nsdecl);
        }
 
        void AddName() {
            string txt = ParseText();
            int symNum = this.symbolTables.symCount++;
            string[] symtable = this.symbolTables.symtable;
            if (symNum == symtable.Length) {
                string[] n = new string[checked(symNum * 2)];
                System.Array.Copy(symtable, 0, n, 0, symNum);
                this.symbolTables.symtable = symtable = n;
            }
            symtable[symNum] = xnt.Add(txt);
        }
 
        void AddQName() {
            int nsUri = ReadNameRef();
            int prefix = ReadNameRef();
            int lname = ReadNameRef();
            int qnameNum = this.symbolTables.qnameCount++;
            QName[] qnametable = this.symbolTables.qnametable;
            if (qnameNum == qnametable.Length) {
                QName[] n = new QName[checked(qnameNum * 2)];
                System.Array.Copy(qnametable, 0, n, 0, qnameNum);
                this.symbolTables.qnametable = qnametable = n;
            }
            string[] symtable = this.symbolTables.symtable;
            string prefixStr = symtable[prefix];
            string lnameStr;
            string nsUriStr;
            // xmlns attributes are encodes differently...
            if (lname == 0) { // xmlns attribute
                // for some reason, sqlserver sometimes generates these...
                if (prefix == 0 && nsUri == 0)
                    return;
                // it is a real namespace decl, make sure it looks valid
                if (!prefixStr.StartsWith("xmlns", StringComparison.Ordinal))
                    goto BadDecl;
                if (5 < prefixStr.Length) {
                    if (6 == prefixStr.Length || ':' != prefixStr[5])
                        goto BadDecl;
                    lnameStr = this.xnt.Add(prefixStr.Substring(6));
                    prefixStr = this.xmlns;
                }
                else {
                    lnameStr = prefixStr;
                    prefixStr = String.Empty;
                }
                nsUriStr = this.nsxmlns;
            }
            else {
                lnameStr = symtable[lname];
                nsUriStr = symtable[nsUri];
            }
            qnametable[qnameNum].Set(prefixStr, lnameStr, nsUriStr);
            return;
        BadDecl:
            throw new XmlException(Res.Xml_BadNamespaceDecl, (string[])null);
        }
 
        private void NameFlush() {
            this.symbolTables.symCount = this.symbolTables.qnameCount = 1;
            Array.Clear(this.symbolTables.symtable, 1, this.symbolTables.symtable.Length - 1);
            Array.Clear(this.symbolTables.qnametable, 0, this.symbolTables.qnametable.Length);
        }
 
        private void SkipExtn() {
            int cb = ParseMB32();
            checked{this.pos += cb;} 
            Fill(-1);
        }
 
        private int ReadQNameRef() {
            int nameNum = ParseMB32();
            if (nameNum < 0 || nameNum >= this.symbolTables.qnameCount)
                throw new XmlException(Res.XmlBin_InvalidQNameID, String.Empty);
            return nameNum;
        }
 
        private int ReadNameRef() {
            int nameNum = ParseMB32();
            if (nameNum < 0 || nameNum >= this.symbolTables.symCount)
                throw new XmlException(Res.XmlBin_InvalidQNameID, String.Empty);
            return nameNum;
        }
 
        // pull more data from input stream
        private bool FillAllowEOF() {
            if (this.eof)
                return false;
            byte[] data = this.data;
            int pos = this.pos;
            int mark = this.mark;
            int end = this.end;
            if (mark == -1) {
                mark = pos;
            }
            if (mark >= 0 && mark < end) {
                Debug.Assert(this.mark <= this.end, "Mark should never be past End");
                Debug.Assert(this.mark <= this.pos, "Mark should never be after Pos");
                int cbKeep = end - mark;
                if (cbKeep > 7 * (data.Length / 8)) {
                    // grow buffer
                    byte[] newdata = new byte[checked(data.Length * 2)];
                    System.Array.Copy(data, mark, newdata, 0, cbKeep);
                    this.data = data = newdata;
                }
                else {
                    System.Array.Copy(data, mark, data, 0, cbKeep);
                }
                pos -= mark;
                end -= mark;
                this.tokDataPos -= mark;
                for (int i = 0; i < this.attrCount; i++) {
                    this.attributes[i].AdjustPosition(-mark);
                    // make sure it is still a valid range
                    Debug.Assert((this.attributes[i].contentPos >= 0) && (this.attributes[i].contentPos <= (end)));
                }
                this.pos = pos;
                this.mark = 0;
                this.offset += mark;
            }
            else {
                Debug.Assert(this.attrCount == 0);
                this.pos -= end;
                this.mark -= end;
                this.offset += end;
                this.tokDataPos -= end;
                end = 0;
            }
            int cbFill = data.Length - end;
            int cbRead = this.inStrm.Read(data, end, cbFill);
            this.end = end + cbRead;
            this.eof = !(cbRead > 0);
            return (cbRead > 0);
        }
 
        // require must be < 1/8 buffer, or else Fill might not actually 
        // grab that much data
        void Fill_(int require) {
            Debug.Assert((this.pos + require) >= this.end);
            while (FillAllowEOF() && ((this.pos + require) >= this.end))
                ;
            if ((this.pos + require) >= this.end)
                throw ThrowXmlException(Res.Xml_UnexpectedEOF1);
        }
 
        // inline the common case
        void Fill(int require) {
            if ((this.pos + require) >= this.end)
                Fill_(require);
        }
 
        byte ReadByte() {
            Fill(0);
            return this.data[this.pos++];
        }
        ushort ReadUShort() {
            Fill(1);
            int pos = this.pos; byte[] data = this.data;
            ushort val = (ushort)(data[pos] + (data[pos + 1] << 8));
            this.pos += 2;
            return val;
        }
 
        int ParseMB32() {
            byte b = ReadByte();
            if (b > 127)
                return ParseMB32_(b);
            return b;
        }
 
        int ParseMB32_(byte b) {
            uint u, t;
            u = (uint)b & (uint)0x7F;
            Debug.Assert(0 != (b & 0x80));
            b = ReadByte();
            t = (uint)b & (uint)0x7F;
            u = u + (t << 7);
            if (b > 127) {
                b = ReadByte();
                t = (uint)b & (uint)0x7F;
                u = u + (t << 14);
                if (b > 127) {
                    b = ReadByte();
                    t = (uint)b & (uint)0x7F;
                    u = u + (t << 21);
                    if (b > 127) {
                        b = ReadByte();
                        // bottom 4 bits are all that are needed, 
                        // but we are mapping to 'int', which only
                        // actually has space for 3 more bits.
                        t = (uint)b & (uint)0x07;
                        if (b > 7)
                            throw ThrowXmlException(Res.XmlBinary_ValueTooBig);
                        u = u + (t << 28);
                    }
                }
            }
            return (int)u;
        }
 
        // this assumes that we have already ensured that all
        // necessary bytes are loaded in to the buffer
        int ParseMB32(int pos) {
            uint u, t;
            byte[] data = this.data;
            byte b = data[pos++];
            u = (uint)b & (uint)0x7F;
            if (b > 127) {
                b = data[pos++];
                t = (uint)b & (uint)0x7F;
                u = u + (t << 7);
                if (b > 127) {
                    b = data[pos++];
                    t = (uint)b & (uint)0x7F;
                    u = u + (t << 14);
                    if (b > 127) {
                        b = data[pos++];
                        t = (uint)b & (uint)0x7F;
                        u = u + (t << 21);
                        if (b > 127) {
                            b = data[pos++];
                            // last byte only has 4 significant digits
                            t = (uint)b & (uint)0x07;
                            if (b > 7)
                                throw ThrowXmlException(Res.XmlBinary_ValueTooBig);
                            u = u + (t << 28);
                        }
                    }
                }
            }
            return (int)u;
        }
 
        // we don't actually support MB64, since we use int for 
        // all our math anyway...
        int ParseMB64() {
            byte b = ReadByte();
            if (b > 127)
                return ParseMB32_(b);
            return b;
        }
 
        BinXmlToken PeekToken() {
            while ((this.pos >= this.end) && FillAllowEOF())
                ;
            if (this.pos >= this.end)
                return BinXmlToken.EOF;
            return (BinXmlToken)this.data[this.pos];
        }
 
        BinXmlToken ReadToken() {
            while ((this.pos >= this.end) && FillAllowEOF())
                ;
            if (this.pos >= this.end)
                return BinXmlToken.EOF;
            return (BinXmlToken)this.data[this.pos++];
        }
 
        BinXmlToken NextToken2(BinXmlToken token) {
            while (true) {
                switch (token) {
                    case BinXmlToken.Name:
                        AddName();
                        break;
                    case BinXmlToken.QName:
                        AddQName();
                        break;
                    case BinXmlToken.NmFlush:
                        NameFlush();
                        break;
                    case BinXmlToken.Extn:
                        SkipExtn();
                        break;
                    default:
                        return token;
                }
                token = ReadToken();
            }
        }
 
        BinXmlToken NextToken1() {
            BinXmlToken token;
            int pos = this.pos;
            if (pos >= this.end)
                token = ReadToken();
            else {
                token = (BinXmlToken)this.data[pos];
                this.pos = pos + 1;
            }
            // BinXmlToken.Name = 0xF0
            // BinXmlToken.QName = 0xEF
            // BinXmlToken.Extn = 0xEA,
            // BinXmlToken.NmFlush = 0xE9,
            if (token >= BinXmlToken.NmFlush
                && token <= BinXmlToken.Name)
                return NextToken2(token);
            return token;
        }
 
        BinXmlToken NextToken() {
            int pos = this.pos;
            if (pos < this.end) {
                BinXmlToken t = (BinXmlToken)this.data[pos];
                if (!(t >= BinXmlToken.NmFlush && t <= BinXmlToken.Name)) {
                    this.pos = pos + 1;
                    return t;
                }
            }
            return NextToken1();
        }
 
        // peek next non-meta token
        BinXmlToken PeekNextToken() {
            BinXmlToken token = NextToken();
            if (BinXmlToken.EOF != token)
                this.pos--;
            return token;
        }
 
        // like NextToken() but meta-tokens are skipped (not reinterpreted)
        BinXmlToken RescanNextToken() {
            BinXmlToken token;
            while (true) {
                token = ReadToken();
                switch (token) {
                    case BinXmlToken.Name: {
                            int cb = ParseMB32();
                            checked{this.pos += 2 * cb;}
                            break;
                        }
                    case BinXmlToken.QName:
                        ParseMB32();
                        ParseMB32();
                        ParseMB32();
                        break;
                    case BinXmlToken.Extn: {
                            int cb = ParseMB32();
                            checked{this.pos += cb;}
                            break;
                        }
                    case BinXmlToken.NmFlush:
                        break;
                    default:
                        return token;
                }
            }
        }
 
        string ParseText() {
            int oldmark = this.mark;
            try {
                if (oldmark < 0)
                    this.mark = this.pos;
                int cch, pos;
                cch = ScanText(out pos);
                return GetString(pos, cch);
            }
            finally {
                if (oldmark < 0)
                    this.mark = -1;
            }
        }
 
        int ScanText(out int start) {
            int cch = ParseMB32();
            int oldmark = this.mark;
            int begin = this.pos;
            checked{this.pos += cch * 2;} // cch = num utf-16 chars
            if (this.pos > this.end)
                Fill(-1);
            // Fill call might have moved buffer
            start = begin - (oldmark - this.mark);
            return cch;
        }
 
        string GetString(int pos, int cch) {
            Debug.Assert(pos >= 0 && cch >= 0);
            if (checked(pos + (cch * 2)) > this.end)
                throw new XmlException(Res.Xml_UnexpectedEOF1, (string[])null);
            if (cch == 0)
                return String.Empty;
            // GetStringUnaligned is _significantly_ faster than unicode.GetString()
            // but since IA64 doesn't support unaligned reads, we can't do it if
            // the address is not aligned properly.  Since the byte[] will be aligned,
            // we can detect address alignment my just looking at the offset
            if ((pos & 1) == 0)
                return GetStringAligned(this.data, pos, cch);
            else
                return unicode.GetString(this.data, pos, checked(cch * 2));
        }
 
        unsafe String GetStringAligned(byte[] data, int offset, int cch) {
            Debug.Assert((offset & 1) == 0);
            fixed (byte* pb = data) {
                char* p = (char*)(pb + offset);
                return new String(p, 0, cch);
            }
        }
 
        private string GetAttributeText(int i) {
            string val = this.attributes[i].val;
 
            if (null != val)
                return val;
            else {
                int origPos = this.pos;
                try {
                    this.pos = this.attributes[i].contentPos;
                    BinXmlToken token = RescanNextToken();
                    if (BinXmlToken.Attr == token || BinXmlToken.EndAttrs == token) {
                        return "";
                    }
                    this.token = token;
                    ReScanOverValue(token);
                    return ValueAsString(token);
                }
                finally {
                    this.pos = origPos;
                }
            }
        }
 
        private int LocateAttribute(string name, string ns) {
            for (int i = 0; i < this.attrCount; i++) {
                if (this.attributes[i].name.MatchNs(name, ns))
                    return i;
            }
 
            return -1;
        }
 
        private int LocateAttribute(string name) {
            string prefix, lname;
            ValidateNames.SplitQName(name, out prefix, out lname);
 
            for (int i = 0; i < this.attrCount; i++) {
                if (this.attributes[i].name.MatchPrefix(prefix, lname))
                    return i;
            }
 
            return -1;
        }
 
        private void PositionOnAttribute(int i) {
            // save element's qname
            this.attrIndex = i;
            this.qnameOther = this.attributes[i - 1].name;
            if (this.state == ScanState.Doc) {
                this.parentNodeType = this.nodetype;
            }
            this.token = BinXmlToken.Attr;
            this.nodetype = XmlNodeType.Attribute;
            this.state = ScanState.Attr;
            this.valueType = TypeOfObject;
            this.stringValue = null;
        }
 
        void GrowElements() {
            int newcount = this.elementStack.Length * 2;
            ElemInfo[] n = new ElemInfo[newcount];
 
            System.Array.Copy(this.elementStack, 0, n, 0, this.elementStack.Length);
            this.elementStack = n;
        }
 
        void GrowAttributes() {
            int newcount = this.attributes.Length * 2;
            AttrInfo[] n = new AttrInfo[newcount];
 
            System.Array.Copy(this.attributes, 0, n, 0, this.attrCount);
            this.attributes = n;
        }
 
        void ClearAttributes() {
            if (this.attrCount != 0)
                this.attrCount = 0;
        }
 
        void PushNamespace(string prefix, string ns, bool implied) {
            if (prefix == "xml")
                return;
            int elemDepth = this.elemDepth;
            NamespaceDecl curDecl;
            this.namespaces.TryGetValue(prefix, out curDecl);
            if (null != curDecl) {
                if (curDecl.uri == ns) {
                    // if we see the nsdecl after we saw the first reference in this scope
                    // fix up 'implied' flag
                    if (!implied && curDecl.implied
                        && (curDecl.scope == elemDepth)) {
                        curDecl.implied = false;
                    }
                    return;
                }
                // check that this doesn't conflict
                this.qnameElement.CheckPrefixNS(prefix, ns);
                if (prefix.Length != 0) {
                    for (int i = 0; i < this.attrCount; i++) {
                        if (this.attributes[i].name.prefix.Length != 0)
                            this.attributes[i].name.CheckPrefixNS(prefix, ns);
                    }
                }
            }
            // actually add ns decl
            NamespaceDecl decl = new NamespaceDecl(prefix, ns,
                this.elementStack[elemDepth].nsdecls,
                curDecl, elemDepth, implied);
            this.elementStack[elemDepth].nsdecls = decl;
            this.namespaces[prefix] = decl;
        }
 
        void PopNamespaces(NamespaceDecl firstInScopeChain) {
            NamespaceDecl decl = firstInScopeChain;
            while (null != decl) {
                if (null == decl.prevLink)
                    this.namespaces.Remove(decl.prefix);
                else
                    this.namespaces[decl.prefix] = decl.prevLink;
                NamespaceDecl next = decl.scopeLink;
                // unlink chains for better gc behaviour 
                decl.prevLink = null;
                decl.scopeLink = null;
                decl = next;
            }
        }
 
        void GenerateImpliedXmlnsAttrs() {
            QName name;
            NamespaceDecl decl = this.elementStack[this.elemDepth].nsdecls;
            while (null != decl) {
                if (decl.implied) {
                    if (this.attrCount == this.attributes.Length)
                        GrowAttributes();
                    if (decl.prefix.Length == 0)
                        name = new QName(string.Empty, this.xmlns, this.nsxmlns);
                    else
                        name = new QName(this.xmlns, xnt.Add(decl.prefix), this.nsxmlns);
                    this.attributes[this.attrCount].Set(name, decl.uri);
                    this.attrCount++;
                }
                decl = decl.scopeLink;
            }
        }
 
        bool ReadInit(bool skipXmlDecl) {
            string err = null;
            if (!sniffed) {
                // check magic header
                ushort magic = ReadUShort();
                if (magic != 0xFFDF) {
                    err = Res.XmlBinary_InvalidSignature;
                    goto Error;
                }
            }
 
            // check protocol version
            this.version = ReadByte();
            if (version != 0x1 && version != 0x2) {
                err = Res.XmlBinary_InvalidProtocolVersion;
                goto Error;
            }
 
            // check encoding marker, 1200 == utf16
            if (1200 != ReadUShort()) {
                err = Res.XmlBinary_UnsupportedCodePage;
                goto Error;
            }
 
            this.state = ScanState.Doc;
            if (BinXmlToken.XmlDecl == PeekToken()) {
                this.pos++;
                this.attributes[0].Set(new QName(string.Empty, this.xnt.Add("version"), string.Empty), ParseText());
                this.attrCount = 1;
                if (BinXmlToken.Encoding == PeekToken()) {
                    this.pos++;
                    this.attributes[1].Set(new QName(string.Empty, this.xnt.Add("encoding"), string.Empty), ParseText());
                    this.attrCount++;
                }
 
                byte standalone = ReadByte();
                switch (standalone) {
                    case 0:
                        break;
                    case 1:
                    case 2:
                        this.attributes[this.attrCount].Set(new QName(string.Empty, this.xnt.Add("standalone"), string.Empty), (standalone == 1) ? "yes" : "no");
                        this.attrCount++;
                        break;
                    default:
                        err = Res.XmlBinary_InvalidStandalone;
                        goto Error;
                }
                if (!skipXmlDecl) {
                    QName xmlDeclQName = new QName(String.Empty, this.xnt.Add("xml"), String.Empty);
                    this.qnameOther = this.qnameElement = xmlDeclQName;
                    this.nodetype = XmlNodeType.XmlDeclaration;
                    this.posAfterAttrs = this.pos;
                    return true;
                }
                // else ReadDoc will clear the attributes for us
            }
            return ReadDoc();
 
        Error:
            this.state = ScanState.Error;
            throw new XmlException(err, (string[])null);
        }
 
        void ScanAttributes() {
            BinXmlToken token;
            int xmlspace = -1;
            int xmllang = -1;
 
            this.mark = this.pos;
            string curDeclPrefix = null;
            bool lastWasValue = false;
 
            while (BinXmlToken.EndAttrs != (token = NextToken())) {
                if (BinXmlToken.Attr == token) {
                    // watch out for nsdecl with no actual content
                    if (null != curDeclPrefix) {
                        PushNamespace(curDeclPrefix, string.Empty, false);
                        curDeclPrefix = null;
                    }
                    // do we need to grow the array?
                    if (this.attrCount == this.attributes.Length)
                        GrowAttributes();
                    // note: ParseMB32 _must_ happen _before_ we grab this.pos...
                    QName n = this.symbolTables.qnametable[ReadQNameRef()];
                    this.attributes[this.attrCount].Set(n, (int)this.pos);
                    if (n.prefix == "xml") {
                        if (n.localname == "lang") {
                            xmllang = this.attrCount;
                        }
                        else if (n.localname == "space") {
                            xmlspace = this.attrCount;
                        }
                    }
                    else if (Ref.Equal(n.namespaceUri, this.nsxmlns)) {
                        // push namespace when we get the value
                        curDeclPrefix = n.localname;
                        if (curDeclPrefix == "xmlns")
                            curDeclPrefix = string.Empty;
                    }
                    else if (n.prefix.Length != 0) {
                        if (n.namespaceUri.Length == 0)
                            throw new XmlException(Res.Xml_PrefixForEmptyNs, String.Empty);
                        this.PushNamespace(n.prefix, n.namespaceUri, true);
                    }
                    else if (n.namespaceUri.Length != 0) {
                        throw ThrowXmlException(Res.XmlBinary_AttrWithNsNoPrefix, n.localname, n.namespaceUri);
                    }
                    this.attrCount++;
                    lastWasValue = false;
                }
                else {
                    // first scan over token to make sure it is a value token
                    ScanOverValue(token, true, true);
                    // don't allow lists of values
                    if (lastWasValue) {
                        throw ThrowNotSupported(Res.XmlBinary_ListsOfValuesNotSupported);
                    }
 
                    // if char checking is on, we need to scan text values to
                    // validate that they don't use invalid CharData, so we
                    // might as well store the saved string for quick attr value access
                    string val = this.stringValue;
                    if (null != val) {
                        this.attributes[this.attrCount - 1].val = val;
                        this.stringValue = null;
                    }
                    // namespace decls can only have text values, and should only
                    // have a single value, so we just grab it here...
                    if (null != curDeclPrefix) {
                        string nsuri = this.xnt.Add(ValueAsString(token));
                        PushNamespace(curDeclPrefix, nsuri, false);
                        curDeclPrefix = null;
                    }
                    lastWasValue = true;
                }
            }
 
            if (xmlspace != -1) {
                string val = GetAttributeText(xmlspace);
                XmlSpace xs = XmlSpace.None;
                if (val == "preserve")
                    xs = XmlSpace.Preserve;
                else if (val == "default")
                    xs = XmlSpace.Default;
                this.elementStack[this.elemDepth].xmlSpace = xs;
                this.xmlspacePreserve = (XmlSpace.Preserve == xs);
            }
            if (xmllang != -1) {
                this.elementStack[this.elemDepth].xmlLang = GetAttributeText(xmllang);
            }
 
            if (this.attrCount < 200)
                SimpleCheckForDuplicateAttributes();
            else
                HashCheckForDuplicateAttributes();
        }
 
        void SimpleCheckForDuplicateAttributes() {
            for (int i = 0; i < this.attrCount; i++) {
                string localname, namespaceUri;
                this.attributes[i].GetLocalnameAndNamespaceUri(out localname, out namespaceUri);
                for (int j = i + 1; j < this.attrCount; j++) {
                    if (this.attributes[j].MatchNS(localname, namespaceUri))
                        throw new XmlException(Res.Xml_DupAttributeName, this.attributes[i].name.ToString());
                }
            }
        }
 
        void HashCheckForDuplicateAttributes() {
            int tblSize = 256;
            while (tblSize < this.attrCount)
                tblSize = checked(tblSize * 2);
            if (this.attrHashTbl.Length < tblSize)
                this.attrHashTbl = new int[tblSize];
            for (int i = 0; i < this.attrCount; i++) {
                string localname, namespaceUri;
                int hash = this.attributes[i].GetLocalnameAndNamespaceUriAndHash(hasher, out localname, out namespaceUri);
                int index = hash & (tblSize - 1);
                int next = this.attrHashTbl[index];
                this.attrHashTbl[index] = i + 1;
                this.attributes[i].prevHash = next;
                while (next != 0) {
                    next--;
                    if (this.attributes[next].MatchHashNS(hash, localname, namespaceUri)) {
                        throw new XmlException(Res.Xml_DupAttributeName, this.attributes[i].name.ToString());
                    }
                    next = this.attributes[next].prevHash;
                }
            }
            Array.Clear(this.attrHashTbl, 0, tblSize);
        }
 
        string XmlDeclValue() {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < this.attrCount; i++) {
                if (i > 0)
                    sb.Append(' ');
                sb.Append(this.attributes[i].name.localname);
                sb.Append("=\"");
                sb.Append(this.attributes[i].val);
                sb.Append('"');
            }
            return sb.ToString();
        }
 
        string CDATAValue() {
            Debug.Assert(this.stringValue == null, "this.stringValue == null");
            Debug.Assert(this.token == BinXmlToken.CData, "this.token == BinXmlToken.CData");
            String value = GetString(this.tokDataPos, this.tokLen);
            StringBuilder sb = null;
            while (PeekToken() == BinXmlToken.CData) {
                this.pos++; // skip over token byte
                if (sb == null) {
                    sb = new StringBuilder(value.Length + value.Length / 2);
                    sb.Append(value);
                }
                sb.Append(ParseText());
            }
            if (sb != null)
                value = sb.ToString();
            this.stringValue = value;
            return value;
        }
 
        void FinishCDATA() {
            for (; ; ) {
                switch (PeekToken()) {
                    case BinXmlToken.CData:
                        // skip
                        this.pos++;
                        int pos;
                        ScanText(out pos);
                        // try again
                        break;
                    case BinXmlToken.EndCData:
                        // done... on to next token...
                        this.pos++;
                        return;
                    default:
                        throw new XmlException(Res.XmlBin_MissingEndCDATA);
                }
            }
        }
 
        void FinishEndElement() {
            NamespaceDecl nsdecls = this.elementStack[this.elemDepth].Clear();
            this.PopNamespaces(nsdecls);
            this.elemDepth--;
        }
 
        bool ReadDoc() {
            switch (this.nodetype) {
                case XmlNodeType.CDATA:
                    FinishCDATA();
                    break;
                case XmlNodeType.EndElement:
                    FinishEndElement();
                    break;
                case XmlNodeType.Element:
                    if (this.isEmpty) {
                        FinishEndElement();
                        this.isEmpty = false;
                    }
                    break;
            }
 
        Read:
            // clear existing state
            this.nodetype = XmlNodeType.None;
            this.mark = -1;
            if (this.qnameOther.localname.Length != 0)
                this.qnameOther.Clear();
 
            ClearAttributes();
            this.attrCount = 0;
            this.valueType = TypeOfString;
            this.stringValue = null;
            this.hasTypedValue = false;
 
            this.token = NextToken();
            switch (this.token) {
                case BinXmlToken.EOF:
                    if (this.elemDepth > 0)
                        throw new XmlException(Res.Xml_UnexpectedEOF1, (string[])null);
                    this.state = ScanState.EOF;
                    return false;
 
                case BinXmlToken.Element:
                    ImplReadElement();
                    break;
 
                case BinXmlToken.EndElem:
                    ImplReadEndElement();
                    break;
 
                case BinXmlToken.DocType:
                    ImplReadDoctype();
                    if (this.dtdProcessing == DtdProcessing.Ignore)
                        goto Read;
                    // nested, don't report doctype
                    if (prevNameInfo != null)
                        goto Read;
                    break;
 
                case BinXmlToken.PI:
                    ImplReadPI();
                    if (this.ignorePIs)
                        goto Read;
                    break;
 
                case BinXmlToken.Comment:
                    ImplReadComment();
                    if (this.ignoreComments)
                        goto Read;
                    break;
 
                case BinXmlToken.CData:
                    ImplReadCDATA();
                    break;
 
                case BinXmlToken.Nest:
                    ImplReadNest();
                    // parse first token in nested document
                    sniffed = false;
                    return ReadInit(true);
 
                case BinXmlToken.EndNest:
                    if (null == this.prevNameInfo)
                        goto default;
                    ImplReadEndNest();
                    return ReadDoc();
 
                case BinXmlToken.XmlText:
                    ImplReadXmlText();
                    break;
 
                // text values
                case BinXmlToken.SQL_BIT:
                case BinXmlToken.SQL_TINYINT:
                case BinXmlToken.SQL_SMALLINT:
                case BinXmlToken.SQL_INT:
                case BinXmlToken.SQL_BIGINT:
                case BinXmlToken.SQL_REAL:
                case BinXmlToken.SQL_FLOAT:
                case BinXmlToken.SQL_MONEY:
                case BinXmlToken.SQL_SMALLMONEY:
                case BinXmlToken.SQL_DATETIME:
                case BinXmlToken.SQL_SMALLDATETIME:
                case BinXmlToken.SQL_DECIMAL:
                case BinXmlToken.SQL_NUMERIC:
                case BinXmlToken.XSD_DECIMAL:
                case BinXmlToken.SQL_UUID:
                case BinXmlToken.SQL_VARBINARY:
                case BinXmlToken.SQL_BINARY:
                case BinXmlToken.SQL_IMAGE:
                case BinXmlToken.SQL_UDT:
                case BinXmlToken.XSD_KATMAI_DATE:
                case BinXmlToken.XSD_KATMAI_DATETIME:
                case BinXmlToken.XSD_KATMAI_TIME:
                case BinXmlToken.XSD_KATMAI_DATEOFFSET:
                case BinXmlToken.XSD_KATMAI_DATETIMEOFFSET:
                case BinXmlToken.XSD_KATMAI_TIMEOFFSET:
                case BinXmlToken.XSD_BINHEX:
                case BinXmlToken.XSD_BASE64:
                case BinXmlToken.SQL_CHAR:
                case BinXmlToken.SQL_VARCHAR:
                case BinXmlToken.SQL_TEXT:
                case BinXmlToken.SQL_NCHAR:
                case BinXmlToken.SQL_NVARCHAR:
                case BinXmlToken.SQL_NTEXT:
                case BinXmlToken.XSD_BOOLEAN:
                case BinXmlToken.XSD_TIME:
                case BinXmlToken.XSD_DATETIME:
                case BinXmlToken.XSD_DATE:
                case BinXmlToken.XSD_BYTE:
                case BinXmlToken.XSD_UNSIGNEDSHORT:
                case BinXmlToken.XSD_UNSIGNEDINT:
                case BinXmlToken.XSD_UNSIGNEDLONG:
                case BinXmlToken.XSD_QNAME:
                    ImplReadData(this.token);
                    if (XmlNodeType.Text == this.nodetype)
                        CheckAllowContent();
                    else if (this.ignoreWhitespace && !this.xmlspacePreserve)
                        goto Read; // skip to next token
                    return true;
 
                default:
                    throw ThrowUnexpectedToken(token);
            }
 
            return true;
        }
 
        void ImplReadData(BinXmlToken tokenType) {
            Debug.Assert(this.mark < 0);
            this.mark = this.pos;
 
            switch (tokenType) {
                case BinXmlToken.SQL_CHAR:
                case BinXmlToken.SQL_VARCHAR:
                case BinXmlToken.SQL_TEXT:
                case BinXmlToken.SQL_NCHAR:
                case BinXmlToken.SQL_NVARCHAR:
                case BinXmlToken.SQL_NTEXT:
                    this.valueType = TypeOfString;
                    this.hasTypedValue = false;
                    break;
                default:
                    this.valueType = GetValueType(this.token);
                    this.hasTypedValue = true;
                    break;
            }
 
            this.nodetype = ScanOverValue(this.token, false, true);
 
            // we don't support lists of values
            BinXmlToken tNext = PeekNextToken();
            switch (tNext) {
                case BinXmlToken.SQL_BIT:
                case BinXmlToken.SQL_TINYINT:
                case BinXmlToken.SQL_SMALLINT:
                case BinXmlToken.SQL_INT:
                case BinXmlToken.SQL_BIGINT:
                case BinXmlToken.SQL_REAL:
                case BinXmlToken.SQL_FLOAT:
                case BinXmlToken.SQL_MONEY:
                case BinXmlToken.SQL_SMALLMONEY:
                case BinXmlToken.SQL_DATETIME:
                case BinXmlToken.SQL_SMALLDATETIME:
                case BinXmlToken.SQL_DECIMAL:
                case BinXmlToken.SQL_NUMERIC:
                case BinXmlToken.XSD_DECIMAL:
                case BinXmlToken.SQL_UUID:
                case BinXmlToken.SQL_VARBINARY:
                case BinXmlToken.SQL_BINARY:
                case BinXmlToken.SQL_IMAGE:
                case BinXmlToken.SQL_UDT:
                case BinXmlToken.XSD_KATMAI_DATE:
                case BinXmlToken.XSD_KATMAI_DATETIME:
                case BinXmlToken.XSD_KATMAI_TIME:
                case BinXmlToken.XSD_KATMAI_DATEOFFSET:
                case BinXmlToken.XSD_KATMAI_DATETIMEOFFSET:
                case BinXmlToken.XSD_KATMAI_TIMEOFFSET:
                case BinXmlToken.XSD_BINHEX:
                case BinXmlToken.XSD_BASE64:
                case BinXmlToken.SQL_CHAR:
                case BinXmlToken.SQL_VARCHAR:
                case BinXmlToken.SQL_TEXT:
                case BinXmlToken.SQL_NCHAR:
                case BinXmlToken.SQL_NVARCHAR:
                case BinXmlToken.SQL_NTEXT:
                case BinXmlToken.XSD_BOOLEAN:
                case BinXmlToken.XSD_TIME:
                case BinXmlToken.XSD_DATETIME:
                case BinXmlToken.XSD_DATE:
                case BinXmlToken.XSD_BYTE:
                case BinXmlToken.XSD_UNSIGNEDSHORT:
                case BinXmlToken.XSD_UNSIGNEDINT:
                case BinXmlToken.XSD_UNSIGNEDLONG:
                case BinXmlToken.XSD_QNAME:
                    throw ThrowNotSupported(Res.XmlBinary_ListsOfValuesNotSupported);
                default:
                    break;
            }
        }
 
        void ImplReadElement() {
            if (3 != this.docState || 9 != this.docState) {
                switch (this.docState) {
                    case 0:
                        this.docState = 9;
                        break;
                    case 1:
                    case 2:
                        this.docState = 3;
                        break;
                    case -1:
                        throw ThrowUnexpectedToken(this.token);
                    default:
                        break;
                }
            }
            this.elemDepth++;
            if (this.elemDepth == this.elementStack.Length)
                GrowElements();
            QName qname = this.symbolTables.qnametable[ReadQNameRef()];
            this.qnameOther = this.qnameElement = qname;
            this.elementStack[this.elemDepth].Set(qname, this.xmlspacePreserve);
            this.PushNamespace(qname.prefix, qname.namespaceUri, true);
            BinXmlToken t = PeekNextToken();
            if (BinXmlToken.Attr == t) {
                ScanAttributes();
                t = PeekNextToken();
            }
            GenerateImpliedXmlnsAttrs();
            if (BinXmlToken.EndElem == t) {
                NextToken(); // move over token...
                this.isEmpty = true;
            }
            else if (BinXmlToken.SQL_NVARCHAR == t) {
                if (this.mark < 0)
                    this.mark = this.pos;
                // skip over token byte
                this.pos++;
                // is this a zero-length string?  if yes, skip it.  
                // (It just indicates that this is _not_ an empty element)
                // Also make sure that the following token is an EndElem
                if (0 == ReadByte()) {
                    if (BinXmlToken.EndElem != (BinXmlToken)ReadByte()) {
                        Debug.Assert(this.pos >= 3);
                        this.pos -= 3; // jump back to start of NVarChar token
                    }
                    else {
                        Debug.Assert(this.pos >= 1);
                        this.pos -= 1; // jump back to EndElem token
                    }
                }
                else {
                    Debug.Assert(this.pos >= 2);
                    this.pos -= 2; // jump back to start of NVarChar token
                }
            }
            this.nodetype = XmlNodeType.Element;
            this.valueType = TypeOfObject;
            this.posAfterAttrs = this.pos;
        }
 
        void ImplReadEndElement() {
            if (this.elemDepth == 0)
                throw ThrowXmlException(Res.Xml_UnexpectedEndTag);
            int index = this.elemDepth;
            if (1 == index && 3 == this.docState)
                this.docState = -1;
            this.qnameOther = this.elementStack[index].name;
            this.xmlspacePreserve = this.elementStack[index].xmlspacePreserve;
            this.nodetype = XmlNodeType.EndElement;
        }
 
        void ImplReadDoctype() {
            if (this.dtdProcessing == DtdProcessing.Prohibit)
                throw ThrowXmlException(Res.Xml_DtdIsProhibited);
            // 0=>auto, 1=>doc/pre-dtd, 2=>doc/pre-elem, 3=>doc/instance -1=>doc/post-elem, 9=>frag
            switch (this.docState) {
                case 0: // 0=>auto
                case 1: // 1=>doc/pre-dtd
                    break;
                case 9: // 9=>frag
                    throw ThrowXmlException(Res.Xml_DtdNotAllowedInFragment);
                default: // 2=>doc/pre-elem, 3=>doc/instance -1=>doc/post-elem
                    throw ThrowXmlException(Res.Xml_BadDTDLocation);
            }
            this.docState = 2;
            this.qnameOther.localname = ParseText();
            if (BinXmlToken.System == PeekToken()) {
                this.pos++;
                this.attributes[this.attrCount++].Set(new QName(string.Empty, this.xnt.Add("SYSTEM"), string.Empty), ParseText());
            }
            if (BinXmlToken.Public == PeekToken()) {
                this.pos++;
                this.attributes[this.attrCount++].Set(new QName(string.Empty, this.xnt.Add("PUBLIC"), string.Empty), ParseText());
            }
            if (BinXmlToken.Subset == PeekToken()) {
                this.pos++;
                this.mark = this.pos;
                this.tokLen = ScanText(out this.tokDataPos);
            }
            else {
                this.tokLen = this.tokDataPos = 0;
            }
            this.nodetype = XmlNodeType.DocumentType;
            this.posAfterAttrs = this.pos;
        }
 
        void ImplReadPI() {
            this.qnameOther.localname = this.symbolTables.symtable[ReadNameRef()];
            this.mark = this.pos;
            this.tokLen = ScanText(out this.tokDataPos);
            this.nodetype = XmlNodeType.ProcessingInstruction;
        }
 
        void ImplReadComment() {
            this.nodetype = XmlNodeType.Comment;
            this.mark = this.pos;
            this.tokLen = ScanText(out this.tokDataPos);
        }
 
        void ImplReadCDATA() {
            CheckAllowContent();
            this.nodetype = XmlNodeType.CDATA;
            this.mark = this.pos;
            this.tokLen = ScanText(out this.tokDataPos);
        }
 
        void ImplReadNest() {
            CheckAllowContent();
            // push current nametables
            this.prevNameInfo = new NestedBinXml(this.symbolTables, this.docState, this.prevNameInfo);
            this.symbolTables.Init();
            this.docState = 0; // auto
        }
 
        void ImplReadEndNest() {
            NestedBinXml nested = this.prevNameInfo;
            this.symbolTables = nested.symbolTables;
            this.docState = nested.docState;
            this.prevNameInfo = nested.next;
        }
 
        void ImplReadXmlText() {
            CheckAllowContent();
            string xmltext = ParseText();
            XmlNamespaceManager xnm = new XmlNamespaceManager(this.xnt);
            foreach (NamespaceDecl decl in this.namespaces.Values) {
                if (decl.scope > 0) {
#if DEBUG
                    if ((object)decl.prefix != (object)this.xnt.Get(decl.prefix))
                        throw new Exception("Prefix not interned: \'" + decl.prefix + "\'");
                    if ((object)decl.uri != (object)this.xnt.Get(decl.uri))
                        throw new Exception("Uri not interned: \'" + decl.uri + "\'");
#endif
                    xnm.AddNamespace(decl.prefix, decl.uri);
                }
            }
            XmlReaderSettings settings = this.Settings;
            settings.ReadOnly = false;
            settings.NameTable = this.xnt;
            settings.DtdProcessing = DtdProcessing.Prohibit;
            if (0 != this.elemDepth) {
                settings.ConformanceLevel = ConformanceLevel.Fragment;
            }
            settings.ReadOnly = true;
            XmlParserContext xpc = new XmlParserContext(this.xnt, xnm, this.XmlLang, this.XmlSpace);
            this.textXmlReader = new XmlTextReaderImpl(xmltext, xpc, settings);
            if (!this.textXmlReader.Read()
                || ((this.textXmlReader.NodeType == XmlNodeType.XmlDeclaration)
                    && !this.textXmlReader.Read())) {
                this.state = ScanState.Doc;
                ReadDoc();
            }
            else {
                this.state = ScanState.XmlText;
                UpdateFromTextReader();
            }
        }
 
        void UpdateFromTextReader() {
            XmlReader r = this.textXmlReader;
            this.nodetype = r.NodeType;
            this.qnameOther.prefix = r.Prefix;
            this.qnameOther.localname = r.LocalName;
            this.qnameOther.namespaceUri = r.NamespaceURI;
            this.valueType = r.ValueType;
            this.isEmpty = r.IsEmptyElement;
        }
 
        bool UpdateFromTextReader(bool needUpdate) {
            if (needUpdate)
                UpdateFromTextReader();
            return needUpdate;
        }
 
        void CheckAllowContent() {
            switch (this.docState) {
                case 0: // auto
                    this.docState = 9;
                    break;
                case 9: // conformance = fragment
                case 3:
                    break;
                default:
                    throw ThrowXmlException(Res.Xml_InvalidRootData);
            }
        }
 
        private void GenerateTokenTypeMap() {
            Type[] map = new Type[256];
            map[(int)BinXmlToken.XSD_BOOLEAN] = typeof(System.Boolean);
            map[(int)BinXmlToken.SQL_TINYINT] = typeof(System.Byte);
            map[(int)BinXmlToken.XSD_BYTE] = typeof(System.SByte);
            map[(int)BinXmlToken.SQL_SMALLINT] = typeof(Int16);
            map[(int)BinXmlToken.XSD_UNSIGNEDSHORT] = typeof(UInt16);
            map[(int)BinXmlToken.XSD_UNSIGNEDINT] = typeof(UInt32);
            map[(int)BinXmlToken.SQL_REAL] = typeof(Single);
            map[(int)BinXmlToken.SQL_FLOAT] = typeof(Double);
            map[(int)BinXmlToken.SQL_BIGINT] = typeof(Int64);
            map[(int)BinXmlToken.XSD_UNSIGNEDLONG] = typeof(UInt64);
            map[(int)BinXmlToken.XSD_QNAME] = typeof(XmlQualifiedName);
            Type TypeOfInt32 = typeof(System.Int32);
            map[(int)BinXmlToken.SQL_BIT] = TypeOfInt32;
            map[(int)BinXmlToken.SQL_INT] = TypeOfInt32;
            Type TypeOfDecimal = typeof(System.Decimal);
            map[(int)BinXmlToken.SQL_SMALLMONEY] = TypeOfDecimal;
            map[(int)BinXmlToken.SQL_MONEY] = TypeOfDecimal;
            map[(int)BinXmlToken.SQL_DECIMAL] = TypeOfDecimal;
            map[(int)BinXmlToken.SQL_NUMERIC] = TypeOfDecimal;
            map[(int)BinXmlToken.XSD_DECIMAL] = TypeOfDecimal;
            Type TypeOfDateTime = typeof(System.DateTime);
            map[(int)BinXmlToken.SQL_SMALLDATETIME] = TypeOfDateTime;
            map[(int)BinXmlToken.SQL_DATETIME] = TypeOfDateTime;
            map[(int)BinXmlToken.XSD_TIME] = TypeOfDateTime;
            map[(int)BinXmlToken.XSD_DATETIME] = TypeOfDateTime;
            map[(int)BinXmlToken.XSD_DATE] = TypeOfDateTime;
            map[(int)BinXmlToken.XSD_KATMAI_DATE] = TypeOfDateTime;
            map[(int)BinXmlToken.XSD_KATMAI_DATETIME] = TypeOfDateTime;
            map[(int)BinXmlToken.XSD_KATMAI_TIME] = TypeOfDateTime;
            Type TypeOfDateTimeOffset = typeof( System.DateTimeOffset );
            map[(int)BinXmlToken.XSD_KATMAI_DATEOFFSET] = TypeOfDateTimeOffset;
            map[(int)BinXmlToken.XSD_KATMAI_DATETIMEOFFSET] = TypeOfDateTimeOffset;
            map[(int)BinXmlToken.XSD_KATMAI_TIMEOFFSET] = TypeOfDateTimeOffset;
            Type TypeOfByteArray = typeof( System.Byte[] );
            map[(int)BinXmlToken.SQL_VARBINARY] = TypeOfByteArray;
            map[(int)BinXmlToken.SQL_BINARY] = TypeOfByteArray;
            map[(int)BinXmlToken.SQL_IMAGE] = TypeOfByteArray;
            map[(int)BinXmlToken.SQL_UDT] = TypeOfByteArray;
            map[(int)BinXmlToken.XSD_BINHEX] = TypeOfByteArray;
            map[(int)BinXmlToken.XSD_BASE64] = TypeOfByteArray;
            map[(int)BinXmlToken.SQL_CHAR] = TypeOfString;
            map[(int)BinXmlToken.SQL_VARCHAR] = TypeOfString;
            map[(int)BinXmlToken.SQL_TEXT] = TypeOfString;
            map[(int)BinXmlToken.SQL_NCHAR] = TypeOfString;
            map[(int)BinXmlToken.SQL_NVARCHAR] = TypeOfString;
            map[(int)BinXmlToken.SQL_NTEXT] = TypeOfString;
            map[(int)BinXmlToken.SQL_UUID] = TypeOfString;
            if (TokenTypeMap == null)
                TokenTypeMap = map;
        }
 
        System.Type GetValueType(BinXmlToken token) {
            Type t = TokenTypeMap[(int)token];
            if (t == null)
                throw ThrowUnexpectedToken(token);
            return t;
        }
 
        // helper method...
        void ReScanOverValue(BinXmlToken token) {
            ScanOverValue(token, true, false);
        }
 
        XmlNodeType ScanOverValue(BinXmlToken token, bool attr, bool checkChars) {
            if (token == BinXmlToken.SQL_NVARCHAR) {
                if (this.mark < 0)
                    this.mark = this.pos;
                this.tokLen = ParseMB32();
                this.tokDataPos = this.pos;
                checked{this.pos += this.tokLen * 2;}
                Fill(-1);
                // check chars (if this is the first pass and settings.CheckCharacters was set)
                if (checkChars && this.checkCharacters) {
                    // check for invalid chardata
                    return CheckText(attr);
                }
                else if (!attr) { // attribute values are always reported as Text
                    // check for whitespace-only text
                    return CheckTextIsWS();
                }
                else {
                    return XmlNodeType.Text;
                }
            }
            else {
                return ScanOverAnyValue(token, attr, checkChars);
            }
        }
 
        XmlNodeType ScanOverAnyValue(BinXmlToken token, bool attr, bool checkChars) {
            if (this.mark < 0)
                this.mark = this.pos;
            checked {
                switch (token) {
                    case BinXmlToken.SQL_BIT:
                    case BinXmlToken.SQL_TINYINT:
                    case BinXmlToken.XSD_BOOLEAN:
                    case BinXmlToken.XSD_BYTE:
                        this.tokDataPos = this.pos;
                        this.tokLen = 1;
                        this.pos += 1;
                        break;
 
                    case BinXmlToken.SQL_SMALLINT:
                    case BinXmlToken.XSD_UNSIGNEDSHORT:
                        this.tokDataPos = this.pos;
                        this.tokLen = 2;
                        this.pos += 2;
                        break;
 
                    case BinXmlToken.SQL_INT:
                    case BinXmlToken.XSD_UNSIGNEDINT:
                    case BinXmlToken.SQL_REAL:
                    case BinXmlToken.SQL_SMALLMONEY:
                    case BinXmlToken.SQL_SMALLDATETIME:
                        this.tokDataPos = this.pos;
                        this.tokLen = 4;
                        this.pos += 4;
                        break;
 
                    case BinXmlToken.SQL_BIGINT:
                    case BinXmlToken.XSD_UNSIGNEDLONG:
                    case BinXmlToken.SQL_FLOAT:
                    case BinXmlToken.SQL_MONEY:
                    case BinXmlToken.SQL_DATETIME:
                    case BinXmlToken.XSD_TIME:
                    case BinXmlToken.XSD_DATETIME:
                    case BinXmlToken.XSD_DATE:
                        this.tokDataPos = this.pos;
                        this.tokLen = 8;
                        this.pos += 8;
                        break;
 
                    case BinXmlToken.SQL_UUID:
                        this.tokDataPos = this.pos;
                        this.tokLen = 16;
                        this.pos += 16;
                        break;
 
                    case BinXmlToken.SQL_DECIMAL:
                    case BinXmlToken.SQL_NUMERIC:
                    case BinXmlToken.XSD_DECIMAL:
                        this.tokDataPos = this.pos;
                        this.tokLen = ParseMB64();
                        this.pos += this.tokLen;
                        break;
 
                    case BinXmlToken.SQL_VARBINARY:
                    case BinXmlToken.SQL_BINARY:
                    case BinXmlToken.SQL_IMAGE:
                    case BinXmlToken.SQL_UDT:
                    case BinXmlToken.XSD_BINHEX:
                    case BinXmlToken.XSD_BASE64:
                        this.tokLen = ParseMB64();
                        this.tokDataPos = this.pos;
                        this.pos += this.tokLen;
                        break;
 
                    case BinXmlToken.SQL_CHAR:
                    case BinXmlToken.SQL_VARCHAR:
                    case BinXmlToken.SQL_TEXT:
                        this.tokLen = ParseMB64();
                        this.tokDataPos = this.pos;
                        this.pos += this.tokLen;
                        if (checkChars && this.checkCharacters) {
                            // check for invalid chardata
                            Fill(-1);
                            string val = ValueAsString(token);
                            XmlConvert.VerifyCharData(val, ExceptionType.ArgumentException, ExceptionType.XmlException);
                            this.stringValue = val;
                        }
                        break;
 
                    case BinXmlToken.SQL_NVARCHAR:
                    case BinXmlToken.SQL_NCHAR:
                    case BinXmlToken.SQL_NTEXT:
                        return ScanOverValue(BinXmlToken.SQL_NVARCHAR, attr, checkChars);
 
                    case BinXmlToken.XSD_QNAME:
                        this.tokDataPos = this.pos;
                        ParseMB32();
                        break;
 
                    case BinXmlToken.XSD_KATMAI_DATE:
                    case BinXmlToken.XSD_KATMAI_DATETIME:
                    case BinXmlToken.XSD_KATMAI_TIME:
                    case BinXmlToken.XSD_KATMAI_DATEOFFSET:
                    case BinXmlToken.XSD_KATMAI_DATETIMEOFFSET:
                    case BinXmlToken.XSD_KATMAI_TIMEOFFSET:
                        VerifyVersion(2, token);
                        this.tokDataPos = this.pos;
                        this.tokLen = GetXsdKatmaiTokenLength(token);
                        this.pos += tokLen;
                        break;
 
                    default:
                        throw ThrowUnexpectedToken(token);
                }
            }
            Fill(-1);
            return XmlNodeType.Text;
        }
 
        unsafe XmlNodeType CheckText(bool attr) {
            Debug.Assert(this.checkCharacters, "this.checkCharacters");
            // assert that size is an even number
            Debug.Assert(0 == ((this.pos - this.tokDataPos) & 1), "Data size should not be odd");
            // grab local copy (perf)
            XmlCharType xmlCharType = this.xmlCharType;
 
            fixed (byte* pb = this.data) {
                int end = this.pos;
                int pos = this.tokDataPos;
 
                if (!attr) {
                    // scan if this is whitespace
                    for (; ; ) {
                        int posNext = pos + 2;
                        if (posNext > end)
                            return this.xmlspacePreserve ? XmlNodeType.SignificantWhitespace : XmlNodeType.Whitespace;
                        if (pb[pos + 1] != 0 || (xmlCharType.charProperties[pb[pos]] & XmlCharType.fWhitespace) == 0)
                            break;
                        pos = posNext;
                    }
                }
 
                for (; ; ) {
                    char ch;
                    for (; ; ) {
                        int posNext = pos + 2;
                        if (posNext > end)
                            return XmlNodeType.Text;
                        ch = (char)(pb[pos] | ((int)(pb[pos + 1]) << 8));
                        if ((xmlCharType.charProperties[ch] & XmlCharType.fCharData) == 0)
                            break;
                        pos = posNext;
                    }
 
                    if (!XmlCharType.IsHighSurrogate(ch)) {
                        throw XmlConvert.CreateInvalidCharException(ch, '\0', ExceptionType.XmlException);
                    }
                    else {
                        if ((pos + 4) > end) {
                            throw ThrowXmlException(Res.Xml_InvalidSurrogateMissingLowChar);
                        }
                        char chNext = (char)(pb[pos + 2] | ((int)(pb[pos + 3]) << 8));
                        if (!XmlCharType.IsLowSurrogate(chNext)) {
                            throw XmlConvert.CreateInvalidSurrogatePairException(ch, chNext);
                        }
                    }
                    pos += 4;
                }
            }
        }
 
        XmlNodeType CheckTextIsWS() {
            Debug.Assert(!this.checkCharacters, "!this.checkCharacters");
            byte[] data = this.data;
            // assert that size is an even number
            Debug.Assert(0 == ((this.pos - this.tokDataPos) & 1), "Data size should not be odd");
            for (int pos = this.tokDataPos; pos < this.pos; pos += 2) {
                if (0 != data[pos + 1])
                    goto NonWSText;
                switch (data[pos]) {
                    case 0x09: // tab
                    case 0x0A: // nl
                    case 0x0D: // cr
                    case 0x20: // space
                        break;
                    default:
                        goto NonWSText;
                }
            }
            if (this.xmlspacePreserve)
                return XmlNodeType.SignificantWhitespace;
            return XmlNodeType.Whitespace;
        NonWSText:
            return XmlNodeType.Text;
        }
 
        void CheckValueTokenBounds() {
            if ((this.end - this.tokDataPos) < this.tokLen)
                throw ThrowXmlException(Res.Xml_UnexpectedEOF1);
        }
 
        int GetXsdKatmaiTokenLength(BinXmlToken token) {
            byte scale;
            switch (token) {
                case BinXmlToken.XSD_KATMAI_DATE:
                    // SQL Katmai type DATE = date(3b)
                    return 3;                                           
                case BinXmlToken.XSD_KATMAI_TIME:
                case BinXmlToken.XSD_KATMAI_DATETIME:
                    // SQL Katmai type DATETIME2 = scale(1b) + time(3-5b) + date(3b)
                    Fill(0);
                    scale = this.data[this.pos];
                    return 4 + XsdKatmaiTimeScaleToValueLength(scale);  
                case BinXmlToken.XSD_KATMAI_DATEOFFSET:
                case BinXmlToken.XSD_KATMAI_TIMEOFFSET:
                case BinXmlToken.XSD_KATMAI_DATETIMEOFFSET:
                    // SQL Katmai type DATETIMEOFFSET = scale(1b) + time(3-5b) + date(3b) + zone(2b)
                    Fill(0);
                    scale = this.data[this.pos];
                    return 6 + XsdKatmaiTimeScaleToValueLength(scale);
                default:
                    throw ThrowUnexpectedToken(this.token);
            }
        }
 
        int XsdKatmaiTimeScaleToValueLength(byte scale) {
            if (scale > 7) {
                throw new XmlException(Res.SqlTypes_ArithOverflow, (string)null);
            }
            return XsdKatmaiTimeScaleToValueLengthMap[scale];
        }
 
        long ValueAsLong() {
            CheckValueTokenBounds();
            switch (this.token) {
                case BinXmlToken.SQL_BIT:
                case BinXmlToken.SQL_TINYINT: {
                        byte v = this.data[this.tokDataPos];
                        return v;
                    }
 
                case BinXmlToken.XSD_BYTE: {
                        sbyte v = unchecked((sbyte)this.data[this.tokDataPos]);
                        return v;
                    }
 
                case BinXmlToken.SQL_SMALLINT:
                    return GetInt16(this.tokDataPos);
 
                case BinXmlToken.SQL_INT:
                    return GetInt32(this.tokDataPos);
 
                case BinXmlToken.SQL_BIGINT:
                    return GetInt64(this.tokDataPos);
 
                case BinXmlToken.XSD_UNSIGNEDSHORT:
                    return GetUInt16(this.tokDataPos);
 
                case BinXmlToken.XSD_UNSIGNEDINT:
                    return GetUInt32(this.tokDataPos);
 
                case BinXmlToken.XSD_UNSIGNEDLONG: {
                        ulong v = GetUInt64(this.tokDataPos);
                        return checked((long)v);
                    }
 
                case BinXmlToken.SQL_REAL:
                case BinXmlToken.SQL_FLOAT: {
                        double v = ValueAsDouble();
                        return (long)v;
                    }
 
                case BinXmlToken.SQL_MONEY:
                case BinXmlToken.SQL_SMALLMONEY:
                case BinXmlToken.SQL_DECIMAL:
                case BinXmlToken.SQL_NUMERIC:
                case BinXmlToken.XSD_DECIMAL: {
                        Decimal v = ValueAsDecimal();
                        return (long)v;
                    }
 
                default:
                    throw ThrowUnexpectedToken(this.token);
            }
        }
 
        ulong ValueAsULong() {
            if (BinXmlToken.XSD_UNSIGNEDLONG == this.token) {
                CheckValueTokenBounds();
                return GetUInt64(this.tokDataPos);
            }
            else {
                throw ThrowUnexpectedToken(this.token);
            }
        }
 
        Decimal ValueAsDecimal() {
            CheckValueTokenBounds();
            switch (token) {
                case BinXmlToken.SQL_BIT:
                case BinXmlToken.SQL_TINYINT:
                case BinXmlToken.SQL_SMALLINT:
                case BinXmlToken.SQL_INT:
                case BinXmlToken.SQL_BIGINT:
                case BinXmlToken.XSD_BYTE:
                case BinXmlToken.XSD_UNSIGNEDSHORT:
                case BinXmlToken.XSD_UNSIGNEDINT:
                    return new Decimal(ValueAsLong());
 
                case BinXmlToken.XSD_UNSIGNEDLONG:
                    return new Decimal(ValueAsULong());
 
                case BinXmlToken.SQL_REAL:
                    return new Decimal(GetSingle(this.tokDataPos));
 
                case BinXmlToken.SQL_FLOAT:
                    return new Decimal(GetDouble(this.tokDataPos));
 
                case BinXmlToken.SQL_SMALLMONEY: {
                        BinXmlSqlMoney v = new BinXmlSqlMoney(GetInt32(this.tokDataPos));
                        return v.ToDecimal();
                    }
                case BinXmlToken.SQL_MONEY: {
                        BinXmlSqlMoney v = new BinXmlSqlMoney(GetInt64(this.tokDataPos));
                        return v.ToDecimal();
                    }
 
                case BinXmlToken.XSD_DECIMAL:
                case BinXmlToken.SQL_DECIMAL:
                case BinXmlToken.SQL_NUMERIC: {
                        BinXmlSqlDecimal v = new BinXmlSqlDecimal(this.data, this.tokDataPos, token == BinXmlToken.XSD_DECIMAL);
                        return v.ToDecimal();
                    }
 
                default:
                    throw ThrowUnexpectedToken(this.token);
            }
        }
 
        double ValueAsDouble() {
            CheckValueTokenBounds();
            switch (token) {
                case BinXmlToken.SQL_BIT:
                case BinXmlToken.SQL_TINYINT:
                case BinXmlToken.SQL_SMALLINT:
                case BinXmlToken.SQL_INT:
                case BinXmlToken.SQL_BIGINT:
                case BinXmlToken.XSD_BYTE:
                case BinXmlToken.XSD_UNSIGNEDSHORT:
                case BinXmlToken.XSD_UNSIGNEDINT:
                    return (double)ValueAsLong();
 
                case BinXmlToken.XSD_UNSIGNEDLONG:
                    return (double)ValueAsULong();
 
                case BinXmlToken.SQL_REAL:
                    return GetSingle(this.tokDataPos);
 
                case BinXmlToken.SQL_FLOAT:
                    return GetDouble(this.tokDataPos);
 
                case BinXmlToken.SQL_SMALLMONEY:
                case BinXmlToken.SQL_MONEY:
                case BinXmlToken.XSD_DECIMAL:
                case BinXmlToken.SQL_DECIMAL:
                case BinXmlToken.SQL_NUMERIC:
                    return (double)ValueAsDecimal();
 
                default:
                    throw ThrowUnexpectedToken(this.token);
            }
        }
 
        DateTime ValueAsDateTime() {
            CheckValueTokenBounds();
            switch (token) {
                case BinXmlToken.SQL_DATETIME: {
                        int pos = this.tokDataPos;
                        int dateticks; uint timeticks;
                        dateticks = GetInt32(pos);
                        timeticks = GetUInt32(pos + 4);
                        return BinXmlDateTime.SqlDateTimeToDateTime(dateticks, timeticks);
                    }
 
                case BinXmlToken.SQL_SMALLDATETIME: {
                        int pos = this.tokDataPos;
                        short dateticks; ushort timeticks;
                        dateticks = GetInt16(pos);
                        timeticks = GetUInt16(pos + 2);
                        return BinXmlDateTime.SqlSmallDateTimeToDateTime(dateticks, timeticks);
                    }
 
                case BinXmlToken.XSD_TIME: {
                        long time = GetInt64(this.tokDataPos);
                        return BinXmlDateTime.XsdTimeToDateTime(time);
                    }
 
                case BinXmlToken.XSD_DATE: {
                        long time = GetInt64(this.tokDataPos);
                        return BinXmlDateTime.XsdDateToDateTime(time);
                    }
 
                case BinXmlToken.XSD_DATETIME: {
                        long time = GetInt64(this.tokDataPos);
                        return BinXmlDateTime.XsdDateTimeToDateTime(time);
                    }
 
                case BinXmlToken.XSD_KATMAI_DATE:
                    return BinXmlDateTime.XsdKatmaiDateToDateTime(this.data, this.tokDataPos);
 
                case BinXmlToken.XSD_KATMAI_DATETIME:
                    return BinXmlDateTime.XsdKatmaiDateTimeToDateTime(this.data, this.tokDataPos);
 
                case BinXmlToken.XSD_KATMAI_TIME:
                    return BinXmlDateTime.XsdKatmaiTimeToDateTime(this.data, this.tokDataPos);
 
                case BinXmlToken.XSD_KATMAI_DATEOFFSET:
                    return BinXmlDateTime.XsdKatmaiDateOffsetToDateTime(this.data, this.tokDataPos);
 
                case BinXmlToken.XSD_KATMAI_DATETIMEOFFSET:
                    return BinXmlDateTime.XsdKatmaiDateTimeOffsetToDateTime(this.data, this.tokDataPos);
 
                case BinXmlToken.XSD_KATMAI_TIMEOFFSET:
                    return BinXmlDateTime.XsdKatmaiTimeOffsetToDateTime(this.data, this.tokDataPos);
 
                default:
                    throw ThrowUnexpectedToken(this.token);
            }
        }
 
        DateTimeOffset ValueAsDateTimeOffset() {
            CheckValueTokenBounds();
            switch (token) {
                case BinXmlToken.XSD_KATMAI_DATEOFFSET:
                    return BinXmlDateTime.XsdKatmaiDateOffsetToDateTimeOffset(this.data, this.tokDataPos);
 
                case BinXmlToken.XSD_KATMAI_DATETIMEOFFSET:
                    return BinXmlDateTime.XsdKatmaiDateTimeOffsetToDateTimeOffset(this.data, this.tokDataPos);
 
                case BinXmlToken.XSD_KATMAI_TIMEOFFSET:
                    return BinXmlDateTime.XsdKatmaiTimeOffsetToDateTimeOffset(this.data, this.tokDataPos);
 
                default:
                    throw ThrowUnexpectedToken(this.token);
            }
        }
 
 
        string ValueAsDateTimeString() {
            CheckValueTokenBounds();
            switch (token) {
                case BinXmlToken.SQL_DATETIME: {
                        int pos = this.tokDataPos;
                        int dateticks; uint timeticks;
                        dateticks = GetInt32(pos);
                        timeticks = GetUInt32(pos + 4);
                        return BinXmlDateTime.SqlDateTimeToString(dateticks, timeticks);
                    }
 
                case BinXmlToken.SQL_SMALLDATETIME: {
                        int pos = this.tokDataPos;
                        short dateticks; ushort timeticks;
                        dateticks = GetInt16(pos);
                        timeticks = GetUInt16(pos + 2);
                        return BinXmlDateTime.SqlSmallDateTimeToString(dateticks, timeticks);
                    }
 
                case BinXmlToken.XSD_TIME: {
                        long time = GetInt64(this.tokDataPos);
                        return BinXmlDateTime.XsdTimeToString(time);
                    }
 
                case BinXmlToken.XSD_DATE: {
                        long time = GetInt64(this.tokDataPos);
                        return BinXmlDateTime.XsdDateToString(time);
                    }
 
                case BinXmlToken.XSD_DATETIME: {
                        long time = GetInt64(this.tokDataPos);
                        return BinXmlDateTime.XsdDateTimeToString(time);
                    }
 
                case BinXmlToken.XSD_KATMAI_DATE:
                    return BinXmlDateTime.XsdKatmaiDateToString(this.data, this.tokDataPos);
 
                case BinXmlToken.XSD_KATMAI_DATETIME:
                    return BinXmlDateTime.XsdKatmaiDateTimeToString(this.data, this.tokDataPos);
 
                case BinXmlToken.XSD_KATMAI_TIME:
                    return BinXmlDateTime.XsdKatmaiTimeToString(this.data, this.tokDataPos);
 
                case BinXmlToken.XSD_KATMAI_DATEOFFSET:
                    return BinXmlDateTime.XsdKatmaiDateOffsetToString(this.data, this.tokDataPos);
 
                case BinXmlToken.XSD_KATMAI_DATETIMEOFFSET:
                    return BinXmlDateTime.XsdKatmaiDateTimeOffsetToString(this.data, this.tokDataPos);
 
                case BinXmlToken.XSD_KATMAI_TIMEOFFSET:
                    return BinXmlDateTime.XsdKatmaiTimeOffsetToString(this.data, this.tokDataPos);
 
                default:
                    throw ThrowUnexpectedToken(this.token);
            }
        }
 
        string ValueAsString(BinXmlToken token) {
            try {
                CheckValueTokenBounds();
                switch ( token ) {
                    case BinXmlToken.SQL_NCHAR:
                    case BinXmlToken.SQL_NVARCHAR:
                    case BinXmlToken.SQL_NTEXT:
                        return GetString( this.tokDataPos, this.tokLen );
 
                    case BinXmlToken.XSD_BOOLEAN: {
                            if ( 0 == this.data[this.tokDataPos] )
                                return "false";
                            else
                                return "true";
                        }
 
                    case BinXmlToken.SQL_BIT:
                    case BinXmlToken.SQL_TINYINT:
                    case BinXmlToken.SQL_SMALLINT:
                    case BinXmlToken.SQL_INT:
                    case BinXmlToken.SQL_BIGINT:
                    case BinXmlToken.XSD_BYTE:
                    case BinXmlToken.XSD_UNSIGNEDSHORT:
                    case BinXmlToken.XSD_UNSIGNEDINT:
                        return ValueAsLong().ToString( CultureInfo.InvariantCulture );
 
                    case BinXmlToken.XSD_UNSIGNEDLONG:
                        return ValueAsULong().ToString( CultureInfo.InvariantCulture );
 
                    case BinXmlToken.SQL_REAL:
                        return XmlConvert.ToString( GetSingle( this.tokDataPos ) );
 
                    case BinXmlToken.SQL_FLOAT:
                        return XmlConvert.ToString( GetDouble( this.tokDataPos ) );
 
                    case BinXmlToken.SQL_UUID: {
                            int a; short b, c;
                            int pos = this.tokDataPos;
                            a = GetInt32( pos );
                            b = GetInt16( pos + 4 );
                            c = GetInt16( pos + 6 );
                            Guid v = new Guid( a, b, c, data[pos + 8], data[pos + 9], data[pos + 10], data[pos + 11], data[pos + 12], data[pos + 13], data[pos + 14], data[pos + 15] );
                            return v.ToString();
                        }
 
                    case BinXmlToken.SQL_SMALLMONEY: {
                            BinXmlSqlMoney v = new BinXmlSqlMoney( GetInt32( this.tokDataPos ) );
                            return v.ToString();
                        }
                    case BinXmlToken.SQL_MONEY: {
                            BinXmlSqlMoney v = new BinXmlSqlMoney( GetInt64( this.tokDataPos ) );
                            return v.ToString();
                        }
 
                    case BinXmlToken.XSD_DECIMAL:
                    case BinXmlToken.SQL_DECIMAL:
                    case BinXmlToken.SQL_NUMERIC: {
                            BinXmlSqlDecimal v = new BinXmlSqlDecimal( this.data, this.tokDataPos, token == BinXmlToken.XSD_DECIMAL );
                            return v.ToString();
                        }
 
                    case BinXmlToken.SQL_CHAR:
                    case BinXmlToken.SQL_VARCHAR:
                    case BinXmlToken.SQL_TEXT: {
                            int pos = this.tokDataPos;
                            int codepage = GetInt32( pos );
                            Encoding enc = System.Text.Encoding.GetEncoding( codepage );
                            return enc.GetString( this.data, pos + 4, this.tokLen - 4 );
                        }
 
                    case BinXmlToken.SQL_VARBINARY:
                    case BinXmlToken.SQL_BINARY:
                    case BinXmlToken.SQL_IMAGE:
                    case BinXmlToken.SQL_UDT:
                    case BinXmlToken.XSD_BASE64: {
                            return Convert.ToBase64String( this.data, this.tokDataPos, this.tokLen );
                        }
 
                    case BinXmlToken.XSD_BINHEX:
                        return BinHexEncoder.Encode( this.data, this.tokDataPos, this.tokLen );
 
                    case BinXmlToken.SQL_DATETIME:
                    case BinXmlToken.SQL_SMALLDATETIME:
                    case BinXmlToken.XSD_TIME:
                    case BinXmlToken.XSD_DATE:
                    case BinXmlToken.XSD_DATETIME:
                    case BinXmlToken.XSD_KATMAI_DATE:
                    case BinXmlToken.XSD_KATMAI_DATETIME:
                    case BinXmlToken.XSD_KATMAI_TIME:
                    case BinXmlToken.XSD_KATMAI_DATEOFFSET:
                    case BinXmlToken.XSD_KATMAI_DATETIMEOFFSET:
                    case BinXmlToken.XSD_KATMAI_TIMEOFFSET:
                        return ValueAsDateTimeString();
 
                    case BinXmlToken.XSD_QNAME: {
                            int nameNum = ParseMB32( this.tokDataPos );
                            if ( nameNum < 0 || nameNum >= this.symbolTables.qnameCount )
                                throw new XmlException( Res.XmlBin_InvalidQNameID, String.Empty );
                            QName qname = this.symbolTables.qnametable[nameNum];
                            if ( qname.prefix.Length == 0 )
                                return qname.localname;
                            else
                                return String.Concat( qname.prefix, ":", qname.localname );
                        }
 
                    default:
                        throw ThrowUnexpectedToken( this.token );
                }
            }
            catch {
                this.state = ScanState.Error;
                throw;
            }
        }
 
        object ValueAsObject(BinXmlToken token, bool returnInternalTypes) {
            CheckValueTokenBounds();
            switch (token) {
                case BinXmlToken.SQL_NCHAR:
                case BinXmlToken.SQL_NVARCHAR:
                case BinXmlToken.SQL_NTEXT:
                    return GetString(this.tokDataPos, this.tokLen);
 
                case BinXmlToken.XSD_BOOLEAN:
                    return (0 != this.data[this.tokDataPos]);
 
                case BinXmlToken.SQL_BIT:
                    return (Int32)this.data[this.tokDataPos];
 
                case BinXmlToken.SQL_TINYINT:
                    return this.data[this.tokDataPos];
 
                case BinXmlToken.SQL_SMALLINT:
                    return GetInt16(this.tokDataPos);
 
                case BinXmlToken.SQL_INT:
                    return GetInt32(this.tokDataPos);
 
                case BinXmlToken.SQL_BIGINT:
                    return GetInt64(this.tokDataPos);
 
                case BinXmlToken.XSD_BYTE: {
                        sbyte v = unchecked((sbyte)this.data[this.tokDataPos]);
                        return v;
                    }
 
                case BinXmlToken.XSD_UNSIGNEDSHORT:
                    return GetUInt16(this.tokDataPos);
 
                case BinXmlToken.XSD_UNSIGNEDINT:
                    return GetUInt32(this.tokDataPos);
 
                case BinXmlToken.XSD_UNSIGNEDLONG:
                    return GetUInt64(this.tokDataPos);
 
                case BinXmlToken.SQL_REAL:
                    return GetSingle(this.tokDataPos);
 
                case BinXmlToken.SQL_FLOAT:
                    return GetDouble(this.tokDataPos);
 
                case BinXmlToken.SQL_UUID: {
                        int a; short b, c;
                        int pos = this.tokDataPos;
                        a = GetInt32(pos);
                        b = GetInt16(pos + 4);
                        c = GetInt16(pos + 6);
                        Guid v = new Guid(a, b, c, data[pos + 8], data[pos + 9], data[pos + 10], data[pos + 11], data[pos + 12], data[pos + 13], data[pos + 14], data[pos + 15]);
                        return v.ToString();
                    }
 
                case BinXmlToken.SQL_SMALLMONEY: {
                        BinXmlSqlMoney v = new BinXmlSqlMoney(GetInt32(this.tokDataPos));
                        if (returnInternalTypes)
                            return v;
                        else
                            return v.ToDecimal();
                    }
 
                case BinXmlToken.SQL_MONEY: {
                        BinXmlSqlMoney v = new BinXmlSqlMoney(GetInt64(this.tokDataPos));
                        if (returnInternalTypes)
                            return v;
                        else
                            return v.ToDecimal();
                    }
 
                case BinXmlToken.XSD_DECIMAL:
                case BinXmlToken.SQL_DECIMAL:
                case BinXmlToken.SQL_NUMERIC: {
                        BinXmlSqlDecimal v = new BinXmlSqlDecimal(this.data, this.tokDataPos, token == BinXmlToken.XSD_DECIMAL);
                        if (returnInternalTypes)
                            return v;
                        else
                            return v.ToDecimal();
                    }
 
                case BinXmlToken.SQL_CHAR:
                case BinXmlToken.SQL_VARCHAR:
                case BinXmlToken.SQL_TEXT: {
                        int pos = this.tokDataPos;
                        int codepage = GetInt32(pos);
                        Encoding enc = System.Text.Encoding.GetEncoding(codepage);
                        return enc.GetString(this.data, pos + 4, this.tokLen - 4);
                    }
 
                case BinXmlToken.SQL_VARBINARY:
                case BinXmlToken.SQL_BINARY:
                case BinXmlToken.SQL_IMAGE:
                case BinXmlToken.SQL_UDT:
                case BinXmlToken.XSD_BASE64:
                case BinXmlToken.XSD_BINHEX: {
                        byte[] data = new byte[this.tokLen];
                        Array.Copy(this.data, this.tokDataPos, data, 0, this.tokLen);
                        return data;
                    }
 
                case BinXmlToken.SQL_DATETIME:
                case BinXmlToken.SQL_SMALLDATETIME:
                case BinXmlToken.XSD_TIME:
                case BinXmlToken.XSD_DATE:
                case BinXmlToken.XSD_DATETIME:
                case BinXmlToken.XSD_KATMAI_DATE:
                case BinXmlToken.XSD_KATMAI_DATETIME:
                case BinXmlToken.XSD_KATMAI_TIME:
                    return ValueAsDateTime();
 
                case BinXmlToken.XSD_KATMAI_DATEOFFSET:
                case BinXmlToken.XSD_KATMAI_DATETIMEOFFSET:
                case BinXmlToken.XSD_KATMAI_TIMEOFFSET:
                    return ValueAsDateTimeOffset();
 
                case BinXmlToken.XSD_QNAME: {
                        int nameNum = ParseMB32(this.tokDataPos);
                        if (nameNum < 0 || nameNum >= this.symbolTables.qnameCount)
                            throw new XmlException(Res.XmlBin_InvalidQNameID, String.Empty);
                        QName qname = this.symbolTables.qnametable[nameNum];
                        return new XmlQualifiedName(qname.localname, qname.namespaceUri);
                    }
 
                default:
                    throw ThrowUnexpectedToken(this.token);
            }
        }
 
        XmlValueConverter GetValueConverter(XmlTypeCode typeCode) {
            XmlSchemaSimpleType xsst = DatatypeImplementation.GetSimpleTypeFromTypeCode(typeCode);
            return xsst.ValueConverter;
        }
 
        object ValueAs(BinXmlToken token, Type returnType, IXmlNamespaceResolver namespaceResolver) {
            object value;
            CheckValueTokenBounds();
            switch (token) {
                case BinXmlToken.SQL_NCHAR:
                case BinXmlToken.SQL_NVARCHAR:
                case BinXmlToken.SQL_NTEXT:
                    value = GetValueConverter(XmlTypeCode.UntypedAtomic).ChangeType(
                        GetString(this.tokDataPos, this.tokLen),
                        returnType, namespaceResolver);
                    break;
 
                case BinXmlToken.XSD_BOOLEAN:
                    value = GetValueConverter(XmlTypeCode.Boolean).ChangeType(
                        (0 != this.data[this.tokDataPos]),
                        returnType, namespaceResolver);
                    break;
 
                case BinXmlToken.SQL_BIT:
                    value = GetValueConverter(XmlTypeCode.NonNegativeInteger).ChangeType(
                        (Int32)this.data[this.tokDataPos],
                        returnType, namespaceResolver);
                    break;
 
                case BinXmlToken.SQL_TINYINT:
                    value = GetValueConverter(XmlTypeCode.UnsignedByte).ChangeType(
                        this.data[this.tokDataPos],
                        returnType, namespaceResolver);
                    break;
 
                case BinXmlToken.SQL_SMALLINT: {
                        int v = GetInt16(this.tokDataPos);
                        value = GetValueConverter(XmlTypeCode.Short).ChangeType(
                            v, returnType, namespaceResolver);
                        break;
                    }
                case BinXmlToken.SQL_INT: {
                        int v = GetInt32(this.tokDataPos);
                        value = GetValueConverter(XmlTypeCode.Int).ChangeType(
                            v, returnType, namespaceResolver);
                        break;
                    }
                case BinXmlToken.SQL_BIGINT: {
                        long v = GetInt64(this.tokDataPos);
                        value = GetValueConverter(XmlTypeCode.Long).ChangeType(
                            v, returnType, namespaceResolver);
                        break;
                    }
                case BinXmlToken.XSD_BYTE: {
                        value = GetValueConverter(XmlTypeCode.Byte).ChangeType(
                            (int)unchecked((sbyte)this.data[this.tokDataPos]),
                            returnType, namespaceResolver);
                        break;
                    }
                case BinXmlToken.XSD_UNSIGNEDSHORT: {
                        int v = GetUInt16(this.tokDataPos);
                        value = GetValueConverter(XmlTypeCode.UnsignedShort).ChangeType(
                            v, returnType, namespaceResolver);
                        break;
                    }
                case BinXmlToken.XSD_UNSIGNEDINT: {
                        long v = GetUInt32(this.tokDataPos);
                        value = GetValueConverter(XmlTypeCode.UnsignedInt).ChangeType(
                            v, returnType, namespaceResolver);
                        break;
                    }
                case BinXmlToken.XSD_UNSIGNEDLONG: {
                        Decimal v = (Decimal)GetUInt64(this.tokDataPos);
                        value = GetValueConverter(XmlTypeCode.UnsignedLong).ChangeType(
                            v, returnType, namespaceResolver);
                        break;
                    }
                case BinXmlToken.SQL_REAL: {
                        Single v = GetSingle(this.tokDataPos);
                        value = GetValueConverter(XmlTypeCode.Float).ChangeType(
                            v, returnType, namespaceResolver);
                        break;
                    }
                case BinXmlToken.SQL_FLOAT: {
                        Double v = GetDouble(this.tokDataPos);
                        value = GetValueConverter(XmlTypeCode.Double).ChangeType(
                            v, returnType, namespaceResolver);
                        break;
                    }
                case BinXmlToken.SQL_UUID:
                    value = GetValueConverter(XmlTypeCode.String).ChangeType(
                        this.ValueAsString(token), returnType, namespaceResolver);
                    break;
 
                case BinXmlToken.SQL_SMALLMONEY:
                    value = GetValueConverter(XmlTypeCode.Decimal).ChangeType(
                        (new BinXmlSqlMoney(GetInt32(this.tokDataPos))).ToDecimal(),
                        returnType, namespaceResolver);
                    break;
 
                case BinXmlToken.SQL_MONEY:
                    value = GetValueConverter(XmlTypeCode.Decimal).ChangeType(
                        (new BinXmlSqlMoney(GetInt64(this.tokDataPos))).ToDecimal(),
                        returnType, namespaceResolver);
                    break;
 
                case BinXmlToken.XSD_DECIMAL:
                case BinXmlToken.SQL_DECIMAL:
                case BinXmlToken.SQL_NUMERIC:
                    value = GetValueConverter(XmlTypeCode.Decimal).ChangeType(
                        (new BinXmlSqlDecimal(this.data, this.tokDataPos, token == BinXmlToken.XSD_DECIMAL)).ToDecimal(),
                        returnType, namespaceResolver);
                    break;
 
                case BinXmlToken.SQL_CHAR:
                case BinXmlToken.SQL_VARCHAR:
                case BinXmlToken.SQL_TEXT: {
                        int pos = this.tokDataPos;
                        int codepage = GetInt32(pos);
                        Encoding enc = System.Text.Encoding.GetEncoding(codepage);
                        value = GetValueConverter(XmlTypeCode.UntypedAtomic).ChangeType(
                            enc.GetString(this.data, pos + 4, this.tokLen - 4),
                            returnType, namespaceResolver);
                        break;
                    }
 
                case BinXmlToken.SQL_VARBINARY:
                case BinXmlToken.SQL_BINARY:
                case BinXmlToken.SQL_IMAGE:
                case BinXmlToken.SQL_UDT:
                case BinXmlToken.XSD_BASE64:
                case BinXmlToken.XSD_BINHEX: {
                        byte[] data = new byte[this.tokLen];
                        Array.Copy(this.data, this.tokDataPos, data, 0, this.tokLen);
                        value = GetValueConverter(token == BinXmlToken.XSD_BINHEX ? XmlTypeCode.HexBinary : XmlTypeCode.Base64Binary).ChangeType(
                            data, returnType, namespaceResolver);
                        break;
                    }
 
                case BinXmlToken.SQL_DATETIME:
                case BinXmlToken.SQL_SMALLDATETIME:
                case BinXmlToken.XSD_DATETIME:
                case BinXmlToken.XSD_KATMAI_DATE:
                case BinXmlToken.XSD_KATMAI_DATETIME:
                case BinXmlToken.XSD_KATMAI_TIME:
                    value = GetValueConverter(XmlTypeCode.DateTime).ChangeType(
                        ValueAsDateTime(),
                        returnType, namespaceResolver);
                    break;
 
                case BinXmlToken.XSD_KATMAI_DATEOFFSET:
                case BinXmlToken.XSD_KATMAI_DATETIMEOFFSET:
                case BinXmlToken.XSD_KATMAI_TIMEOFFSET:
                    value = GetValueConverter(XmlTypeCode.DateTime).ChangeType(
                        ValueAsDateTimeOffset(),
                        returnType, namespaceResolver);
                    break;
 
                case BinXmlToken.XSD_TIME:
                    value = GetValueConverter(XmlTypeCode.Time).ChangeType(
                        ValueAsDateTime(),
                        returnType, namespaceResolver);
                    break;
 
                case BinXmlToken.XSD_DATE:
                    value = GetValueConverter(XmlTypeCode.Date).ChangeType(
                        ValueAsDateTime(),
                        returnType, namespaceResolver);
                    break;
 
                case BinXmlToken.XSD_QNAME: {
                        int nameNum = ParseMB32(this.tokDataPos);
                        if (nameNum < 0 || nameNum >= this.symbolTables.qnameCount)
                            throw new XmlException(Res.XmlBin_InvalidQNameID, String.Empty);
                        QName qname = this.symbolTables.qnametable[nameNum];
                        value = GetValueConverter(XmlTypeCode.QName).ChangeType(
                            new XmlQualifiedName(qname.localname, qname.namespaceUri),
                            returnType, namespaceResolver);
                        break;
                    }
 
                default:
                    throw ThrowUnexpectedToken(this.token);
            }
            return value;
        }
 
        Int16 GetInt16(int pos) {
            byte[] data = this.data;
            return (Int16)(data[pos] | data[pos + 1] << 8);
        }
 
        UInt16 GetUInt16(int pos) {
            byte[] data = this.data;
            return (UInt16)(data[pos] | data[pos + 1] << 8);
        }
 
        Int32 GetInt32(int pos) {
            byte[] data = this.data;
            return (Int32)(data[pos] | data[pos + 1] << 8 | data[pos + 2] << 16 | data[pos + 3] << 24);
        }
 
        UInt32 GetUInt32(int pos) {
            byte[] data = this.data;
            return (UInt32)(data[pos] | data[pos + 1] << 8 | data[pos + 2] << 16 | data[pos + 3] << 24);
        }
 
        Int64 GetInt64(int pos) {
            byte[] data = this.data;
            uint lo = (uint)(data[pos] | data[pos + 1] << 8 | data[pos + 2] << 16 | data[pos + 3] << 24);
            uint hi = (uint)(data[pos + 4] | data[pos + 5] << 8 | data[pos + 6] << 16 | data[pos + 7] << 24);
            return (Int64)((ulong)hi) << 32 | lo;
        }
 
        UInt64 GetUInt64(int pos) {
            byte[] data = this.data;
            uint lo = (uint)(data[pos] | data[pos + 1] << 8 | data[pos + 2] << 16 | data[pos + 3] << 24);
            uint hi = (uint)(data[pos + 4] | data[pos + 5] << 8 | data[pos + 6] << 16 | data[pos + 7] << 24);
            return (UInt64)((ulong)hi) << 32 | lo;
        }
 
        Single GetSingle(int offset) {
            byte[] data = this.data;
            uint tmp = (uint)(data[offset]
                            | data[offset + 1] << 8
                            | data[offset + 2] << 16
                            | data[offset + 3] << 24);
            unsafe {
                return *((float*)&tmp);
            }
        }
 
        Double GetDouble(int offset) {
            uint lo = (uint)(data[offset + 0]
                            | data[offset + 1] << 8
                            | data[offset + 2] << 16
                            | data[offset + 3] << 24);
            uint hi = (uint)(data[offset + 4]
                            | data[offset + 5] << 8
                            | data[offset + 6] << 16
                            | data[offset + 7] << 24);
            ulong tmp = ((ulong)hi) << 32 | lo;
            unsafe {
                return *((double*)&tmp);
            }
        }
 
        Exception ThrowUnexpectedToken(BinXmlToken token) {
            System.Diagnostics.Debug.WriteLine("Unhandled token: " + token.ToString());
            return ThrowXmlException(Res.XmlBinary_UnexpectedToken);
        }
 
        Exception ThrowXmlException(string res) {
            this.state = ScanState.Error;
            return new XmlException(res, (string[])null);
        }
 
        // not currently used...
        //Exception ThrowXmlException(string res, string arg1) {
        //    this.state = ScanState.Error;
        //    return new XmlException(res, new string[] {arg1} );
        //}
 
        Exception ThrowXmlException(string res, string arg1, string arg2) {
            this.state = ScanState.Error;
            return new XmlException(res, new string[] { arg1, arg2 });
        }
 
        Exception ThrowNotSupported(string res) {
            this.state = ScanState.Error;
            return new NotSupportedException(Res.GetString(res));
        }
    }
}