|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using System.Buffers.Binary;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Xml.Schema;
namespace System.Xml
{
internal sealed partial class XmlSqlBinaryReader : XmlReader, IXmlNamespaceResolver
{
private static volatile Type?[] s_tokenTypeMap = null!;
private static ReadOnlySpan<byte> XsdKatmaiTimeScaleToValueLengthMap => // 8
[
// length scale
3, // 0
3, // 1
3, // 2
4, // 3
4, // 4
5, // 5
5, // 6
5, // 7
];
private enum ScanState
{
Doc = 0,
XmlText = 1,
Attr = 2,
AttrVal = 3,
AttrValPseudoValue = 4,
Init = 5,
Error = 6,
EOF = 7,
Closed = 8
}
private static readonly ReadState[] s_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 : IEquatable<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(SR.XmlBinary_NoRemapPrefix, new string[] { prefix, this.namespaceUri, namespaceUri });
}
public int GetNSHashCode() =>
HashCode.Combine(this.namespaceUri, this.localname);
public override int GetHashCode() =>
this.prefix.GetHashCode() ^ this.localname.GetHashCode();
public override bool Equals([NotNullWhen(true)] object? other) =>
other is QName qname && Equals(qname);
public bool Equals(QName other) =>
prefix == other.prefix &&
localname == other.localname &&
namespaceUri == other.namespaceUri;
public static bool operator ==(QName a, QName b) => a.Equals(b);
public static bool operator !=(QName a, QName b) => !a.Equals(b);
public override string ToString() =>
prefix.Length == 0 ? localname : $"{this.prefix}:{this.localname}";
};
private 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;
}
};
private 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(out string localname, out string namespaceUri)
{
localname = this.name.localname;
namespaceUri = this.name.namespaceUri;
return this.hashCode = this.name.GetNSHashCode();
}
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;
}
}
private sealed 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
private 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;
}
}
private sealed 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
private Stream _inStrm;
private byte[] _data;
private int _pos;
private int _mark;
private int _end;
private bool _eof;
private bool _sniffed;
private bool _isEmpty; // short-tag element start tag
private 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
private SymbolTables _symbolTables;
private readonly XmlNameTable _xnt;
private readonly bool _xntFromSettings;
private readonly string _xml;
private readonly string _xmlns;
private readonly string _nsxmlns;
// base uri...
private readonly string _baseUri;
// current parse state
private ScanState _state;
private XmlNodeType _nodetype;
private BinXmlToken _token;
// current attribute
private int _attrIndex;
// index of current qname
private QName _qnameOther;
// saved qname of element (for MoveToElement)
private QName _qnameElement;
private XmlNodeType _parentNodeType; // use for MoveToElement()
// stack of current open element tags
private ElemInfo[] _elementStack;
private int _elemDepth;
// current attributes
private AttrInfo[] _attributes;
private int[] _attrHashTbl;
private int _attrCount;
private int _posAfterAttrs;
// xml:space
private bool _xmlspacePreserve;
// position/parse info for current typed token
private int _tokLen;
private int _tokDataPos;
private bool _hasTypedValue;
private System.Type _valueType;
// if it is a simple string value, we cache it
private string? _stringValue;
// hashtable of current namespaces
private readonly Dictionary<string, NamespaceDecl> _namespaces;
//Hashtable namespaces;
// linked list of pushed nametables (to support nested binary-xml documents)
private NestedBinXml? _prevNameInfo;
// XmlTextReader to handle embedded text blocks
private XmlTextReaderImpl? _textXmlReader;
// close input flag
private readonly bool _closeInput;
private readonly bool _checkCharacters;
private readonly bool _ignoreWhitespace;
private readonly bool _ignorePIs;
private readonly bool _ignoreComments;
private readonly DtdProcessing _dtdProcessing;
// current version of the protocol
private byte _version;
public XmlSqlBinaryReader(Stream stream, byte[] data, int len, string baseUri, bool closeInput, XmlReaderSettings settings)
{
_xnt = settings.NameTable!;
if (_xnt == null)
{
_xnt = new NameTable();
_xntFromSettings = false;
}
else
{
_xntFromSettings = true;
}
_xml = _xnt.Add("xml");
_xmlns = _xnt.Add("xmlns");
_nsxmlns = _xnt.Add(XmlReservedNs.NsXmlNs);
_baseUri = baseUri;
_state = ScanState.Init;
_nodetype = XmlNodeType.None;
_token = BinXmlToken.Error;
_elementStack = new ElemInfo[16];
_attributes = new AttrInfo[8];
_attrHashTbl = new int[8];
_symbolTables.Init();
_qnameOther.Clear();
_qnameElement.Clear();
_xmlspacePreserve = false;
_namespaces = new Dictionary<string, NamespaceDecl>();
AddInitNamespace(string.Empty, string.Empty);
AddInitNamespace(_xml, _xnt.Add(XmlReservedNs.NsXml));
AddInitNamespace(_xmlns, _nsxmlns);
_valueType = typeof(string);
// init buffer position, etc
_inStrm = stream;
if (data != null)
{
Debug.Assert(len >= 2 && (data[0] == 0xdf && data[1] == 0xff));
_data = data;
_end = len;
_pos = 2;
_sniffed = true;
}
else
{
_data = new byte[XmlReader.DefaultBufferSize];
_end = stream.Read(_data, 0, XmlReader.DefaultBufferSize);
_pos = 0;
_sniffed = false;
}
_mark = -1;
_eof = (0 == _end);
_closeInput = closeInput;
switch (settings.ConformanceLevel)
{
case ConformanceLevel.Auto:
_docState = 0; break;
case ConformanceLevel.Fragment:
_docState = 9; break;
case ConformanceLevel.Document:
_docState = 1; break;
}
_checkCharacters = settings.CheckCharacters;
_dtdProcessing = settings.DtdProcessing;
_ignoreWhitespace = settings.IgnoreWhitespace;
_ignorePIs = settings.IgnoreProcessingInstructions;
_ignoreComments = settings.IgnoreComments;
s_tokenTypeMap ??= 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
settings.ConformanceLevel = _docState switch
{
0 => ConformanceLevel.Auto,
9 => ConformanceLevel.Fragment,
_ => ConformanceLevel.Document,
};
settings.CheckCharacters = _checkCharacters;
settings.IgnoreWhitespace = _ignoreWhitespace;
settings.IgnoreProcessingInstructions = _ignorePIs;
settings.IgnoreComments = _ignoreComments;
settings.DtdProcessing = _dtdProcessing;
settings.CloseInput = _closeInput;
settings.ReadOnly = true;
return settings;
}
}
public override XmlNodeType NodeType
{
get
{
return _nodetype;
}
}
public override string LocalName
{
get
{
return _qnameOther.localname;
}
}
public override string NamespaceURI
{
get
{
return _qnameOther.namespaceUri;
}
}
public override string Prefix
{
get
{
return _qnameOther.prefix;
}
}
public override bool HasValue
{
get
{
if (ScanState.XmlText == _state)
{
Debug.Assert(_textXmlReader != null);
return _textXmlReader.HasValue;
}
else
return XmlReader.HasValueInternal(_nodetype);
}
}
public override string Value
{
get
{
if (null != _stringValue)
return _stringValue;
switch (_state)
{
case ScanState.Doc:
switch (_nodetype)
{
case XmlNodeType.DocumentType:
case XmlNodeType.ProcessingInstruction:
case XmlNodeType.Comment:
return _stringValue = GetString(_tokDataPos, _tokLen);
case XmlNodeType.CDATA:
return _stringValue = CDATAValue();
case XmlNodeType.XmlDeclaration:
return _stringValue = XmlDeclValue();
case XmlNodeType.Text:
case XmlNodeType.Whitespace:
case XmlNodeType.SignificantWhitespace:
return _stringValue = ValueAsString(_token);
}
break;
case ScanState.XmlText:
{
Debug.Assert(_textXmlReader != null);
return _textXmlReader.Value;
}
case ScanState.Attr:
case ScanState.AttrValPseudoValue:
return _stringValue = GetAttributeText(_attrIndex - 1);
case ScanState.AttrVal:
return _stringValue = ValueAsString(_token);
}
return string.Empty;
}
}
public override int Depth
{
get
{
int adj = 0;
switch (_state)
{
case ScanState.Doc:
if (_nodetype == XmlNodeType.Element
|| _nodetype == XmlNodeType.EndElement)
adj = -1;
break;
case ScanState.XmlText:
Debug.Assert(_textXmlReader != null);
adj = _textXmlReader.Depth;
break;
case ScanState.Attr:
if (_parentNodeType != XmlNodeType.Element)
adj = 1;
break;
case ScanState.AttrVal:
case ScanState.AttrValPseudoValue:
if (_parentNodeType != XmlNodeType.Element)
adj = 1;
adj += 1;
break;
default:
return 0;
}
return _elemDepth + adj;
}
}
public override string BaseURI
{
get
{
return _baseUri;
}
}
public override bool IsEmptyElement
{
get
{
switch (_state)
{
case ScanState.Doc:
case ScanState.XmlText:
return _isEmpty;
default:
return false;
}
}
}
public override XmlSpace XmlSpace
{
get
{
if (ScanState.XmlText != _state)
{
for (int i = _elemDepth; i >= 0; i--)
{
XmlSpace xs = _elementStack[i].xmlSpace;
if (xs != XmlSpace.None)
return xs;
}
return XmlSpace.None;
}
else
{
Debug.Assert(_textXmlReader != null);
return _textXmlReader.XmlSpace;
}
}
}
public override string XmlLang
{
get
{
if (ScanState.XmlText != _state)
{
for (int i = _elemDepth; i >= 0; i--)
{
string? xl = _elementStack[i].xmlLang;
if (null != xl)
return xl;
}
return string.Empty;
}
else
{
Debug.Assert(_textXmlReader != null);
return _textXmlReader.XmlLang;
}
}
}
public override System.Type ValueType
{
get
{
return _valueType;
}
}
public override int AttributeCount
{
get
{
switch (_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 _attrCount;
case ScanState.XmlText:
{
Debug.Assert(_textXmlReader != null);
return _textXmlReader.AttributeCount;
}
default:
return 0;
}
}
}
public override string? GetAttribute(string name, string? ns)
{
if (ScanState.XmlText == _state)
{
Debug.Assert(_textXmlReader != null);
return _textXmlReader.GetAttribute(name, ns);
}
else
{
ArgumentNullException.ThrowIfNull(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 == _state)
{
Debug.Assert(_textXmlReader != null);
return _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 == _state)
{
Debug.Assert(_textXmlReader != null);
return _textXmlReader.GetAttribute(i);
}
else
{
ArgumentOutOfRangeException.ThrowIfNegative(i);
ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(i, _attrCount);
return GetAttributeText(i);
}
}
public override bool MoveToAttribute(string name, string? ns)
{
if (ScanState.XmlText == _state)
{
Debug.Assert(_textXmlReader != null);
return UpdateFromTextReader(_textXmlReader.MoveToAttribute(name, ns));
}
else
{
ArgumentNullException.ThrowIfNull(name);
if (null == ns)
ns = string.Empty;
int index = LocateAttribute(name, ns);
if ((-1 != index) && (_state < ScanState.Init))
{
PositionOnAttribute(index + 1);
return true;
}
return false;
}
}
public override bool MoveToAttribute(string name)
{
if (ScanState.XmlText == _state)
{
Debug.Assert(_textXmlReader != null);
return UpdateFromTextReader(_textXmlReader.MoveToAttribute(name));
}
else
{
int index = LocateAttribute(name);
if ((-1 != index) && (_state < ScanState.Init))
{
PositionOnAttribute(index + 1);
return true;
}
return false;
}
}
public override void MoveToAttribute(int i)
{
if (ScanState.XmlText == _state)
{
Debug.Assert(_textXmlReader != null);
_textXmlReader.MoveToAttribute(i);
UpdateFromTextReader(true);
}
else
{
ArgumentOutOfRangeException.ThrowIfNegative(i);
ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(i, _attrCount);
PositionOnAttribute(i + 1);
}
}
public override bool MoveToFirstAttribute()
{
if (ScanState.XmlText == _state)
{
Debug.Assert(_textXmlReader != null);
return UpdateFromTextReader(_textXmlReader.MoveToFirstAttribute());
}
else
{
if (_attrCount == 0)
return false;
// set up for walking attributes
PositionOnAttribute(1);
return true;
}
}
public override bool MoveToNextAttribute()
{
switch (_state)
{
case ScanState.Doc:
case ScanState.Attr:
case ScanState.AttrVal:
case ScanState.AttrValPseudoValue:
if (_attrIndex >= _attrCount)
return false;
PositionOnAttribute(++_attrIndex);
return true;
case ScanState.XmlText:
Debug.Assert(_textXmlReader != null);
return UpdateFromTextReader(_textXmlReader.MoveToNextAttribute());
default:
return false;
}
}
public override bool MoveToElement()
{
switch (_state)
{
case ScanState.Attr:
case ScanState.AttrVal:
case ScanState.AttrValPseudoValue:
_attrIndex = 0;
_qnameOther = _qnameElement;
if (XmlNodeType.Element == _parentNodeType)
_token = BinXmlToken.Element;
else if (XmlNodeType.XmlDeclaration == _parentNodeType)
_token = BinXmlToken.XmlDecl;
else if (XmlNodeType.DocumentType == _parentNodeType)
_token = BinXmlToken.DocType;
else
Debug.Fail("Unexpected parent NodeType");
_nodetype = _parentNodeType;
_state = ScanState.Doc;
_pos = _posAfterAttrs;
_stringValue = null;
return true;
case ScanState.XmlText:
Debug.Assert(_textXmlReader != null);
return UpdateFromTextReader(_textXmlReader.MoveToElement());
default:
return false;
}
}
public override bool EOF
{
get
{
return _state == ScanState.EOF;
}
}
public override bool ReadAttributeValue()
{
_stringValue = null;
switch (_state)
{
case ScanState.Attr:
if (null == _attributes[_attrIndex - 1].val)
{
_pos = _attributes[_attrIndex - 1].contentPos;
BinXmlToken tok = RescanNextToken();
if (BinXmlToken.Attr == tok || BinXmlToken.EndAttrs == tok)
{
return false;
}
_token = tok;
ReScanOverValue(tok);
_valueType = GetValueType(tok);
_state = ScanState.AttrVal;
}
else
{
_token = BinXmlToken.Error;
_valueType = typeof(string);
_state = ScanState.AttrValPseudoValue;
}
_qnameOther.Clear();
_nodetype = XmlNodeType.Text;
return true;
case ScanState.AttrVal:
return false;
case ScanState.XmlText:
Debug.Assert(_textXmlReader != null);
return UpdateFromTextReader(_textXmlReader.ReadAttributeValue());
default:
return false;
}
}
public override void Close()
{
_state = ScanState.Closed;
_nodetype = XmlNodeType.None;
_token = BinXmlToken.Error;
_stringValue = null;
if (null != _textXmlReader)
{
_textXmlReader.Close();
_textXmlReader = null;
}
if (null != _inStrm && _closeInput)
_inStrm.Dispose();
_inStrm = null!;
_pos = _end = 0;
}
public override XmlNameTable NameTable
{
get
{
return _xnt;
}
}
public override string? LookupNamespace(string prefix)
{
if (ScanState.XmlText == _state)
{
Debug.Assert(_textXmlReader != null);
return _textXmlReader.LookupNamespace(prefix);
}
NamespaceDecl? decl;
if (prefix != null && _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 s_scanState2ReadState[(int)_state];
}
}
public override bool Read()
{
try
{
switch (_state)
{
case ScanState.Init:
return ReadInit(false);
case ScanState.Doc:
return ReadDoc();
case ScanState.XmlText:
Debug.Assert(_textXmlReader != null);
if (_textXmlReader.Read())
{
return UpdateFromTextReader(true);
}
_state = ScanState.Doc;
_nodetype = XmlNodeType.None;
_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)
{
_state = ScanState.Error;
throw new XmlException(e.Message, e);
}
catch
{
_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 fall 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 (_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 (_hasTypedValue)
{
return true;
}
break;
case ScanState.Attr:
_pos = _attributes[_attrIndex - 1].contentPos;
BinXmlToken token = RescanNextToken();
if (BinXmlToken.Attr == token || BinXmlToken.EndAttrs == token)
break;
_token = token;
ReScanOverValue(token);
return true;
case ScanState.AttrVal:
return true;
default:
break;
}
return false;
}
private int FinishContentAsXXX(int origPos)
{
if (_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 CreateNotSupportedException(SR.XmlBinary_ListsOfValuesNotSupported);
}
}
}
return _pos;
}
return origPos;
}
public override bool ReadContentAsBoolean()
{
int origPos = _pos;
bool value;
try
{
if (SetupContentAsXXX("ReadContentAsBoolean"))
{
try
{
switch (_token)
{
case BinXmlToken.XSD_BOOLEAN:
value = 0 != _data[_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(SR.Format(SR.XmlBinary_CastNotSupported, _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(SR.Xml_ReadContentAsFormatException, "Boolean", e, null);
}
catch (FormatException e)
{
throw new XmlException(SR.Xml_ReadContentAsFormatException, "Boolean", e, null);
}
origPos = FinishContentAsXXX(origPos);
return value;
}
}
finally
{
_pos = origPos;
}
Fallback:
return base.ReadContentAsBoolean();
}
public override DateTime ReadContentAsDateTime()
{
int origPos = _pos;
DateTime value;
try
{
if (SetupContentAsXXX("ReadContentAsDateTime"))
{
try
{
switch (_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(SR.Format(SR.XmlBinary_CastNotSupported, _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(SR.Xml_ReadContentAsFormatException, "DateTime", e, null);
}
catch (FormatException e)
{
throw new XmlException(SR.Xml_ReadContentAsFormatException, "DateTime", e, null);
}
catch (OverflowException e)
{
throw new XmlException(SR.Xml_ReadContentAsFormatException, "DateTime", e, null);
}
origPos = FinishContentAsXXX(origPos);
return value;
}
}
finally
{
_pos = origPos;
}
Fallback:
return base.ReadContentAsDateTime();
}
public override double ReadContentAsDouble()
{
int origPos = _pos;
double value;
try
{
if (SetupContentAsXXX("ReadContentAsDouble"))
{
try
{
switch (_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(SR.Format(SR.XmlBinary_CastNotSupported, _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(SR.Xml_ReadContentAsFormatException, "Double", e, null);
}
catch (FormatException e)
{
throw new XmlException(SR.Xml_ReadContentAsFormatException, "Double", e, null);
}
catch (OverflowException e)
{
throw new XmlException(SR.Xml_ReadContentAsFormatException, "Double", e, null);
}
origPos = FinishContentAsXXX(origPos);
return value;
}
}
finally
{
_pos = origPos;
}
Fallback:
return base.ReadContentAsDouble();
}
public override float ReadContentAsFloat()
{
int origPos = _pos;
float value;
try
{
if (SetupContentAsXXX("ReadContentAsFloat"))
{
try
{
switch (_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(SR.Format(SR.XmlBinary_CastNotSupported, _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(SR.Xml_ReadContentAsFormatException, "Float", e, null);
}
catch (FormatException e)
{
throw new XmlException(SR.Xml_ReadContentAsFormatException, "Float", e, null);
}
catch (OverflowException e)
{
throw new XmlException(SR.Xml_ReadContentAsFormatException, "Float", e, null);
}
origPos = FinishContentAsXXX(origPos);
return value;
}
}
finally
{
_pos = origPos;
}
Fallback:
return base.ReadContentAsFloat();
}
public override decimal ReadContentAsDecimal()
{
int origPos = _pos;
decimal value;
try
{
if (SetupContentAsXXX("ReadContentAsDecimal"))
{
try
{
switch (_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(SR.Format(SR.XmlBinary_CastNotSupported, _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(SR.Xml_ReadContentAsFormatException, "Decimal", e, null);
}
catch (FormatException e)
{
throw new XmlException(SR.Xml_ReadContentAsFormatException, "Decimal", e, null);
}
catch (OverflowException e)
{
throw new XmlException(SR.Xml_ReadContentAsFormatException, "Decimal", e, null);
}
origPos = FinishContentAsXXX(origPos);
return value;
}
}
finally
{
_pos = origPos;
}
Fallback:
return base.ReadContentAsDecimal();
}
public override int ReadContentAsInt()
{
int origPos = _pos;
int value;
try
{
if (SetupContentAsXXX("ReadContentAsInt"))
{
try
{
switch (_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(SR.Format(SR.XmlBinary_CastNotSupported, _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(SR.Xml_ReadContentAsFormatException, "Int32", e, null);
}
catch (FormatException e)
{
throw new XmlException(SR.Xml_ReadContentAsFormatException, "Int32", e, null);
}
catch (OverflowException e)
{
throw new XmlException(SR.Xml_ReadContentAsFormatException, "Int32", e, null);
}
origPos = FinishContentAsXXX(origPos);
return value;
}
}
finally
{
_pos = origPos;
}
Fallback:
return base.ReadContentAsInt();
}
public override long ReadContentAsLong()
{
int origPos = _pos;
long value;
try
{
if (SetupContentAsXXX("ReadContentAsLong"))
{
try
{
switch (_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(SR.Format(SR.XmlBinary_CastNotSupported, _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(SR.Xml_ReadContentAsFormatException, "Int64", e, null);
}
catch (FormatException e)
{
throw new XmlException(SR.Xml_ReadContentAsFormatException, "Int64", e, null);
}
catch (OverflowException e)
{
throw new XmlException(SR.Xml_ReadContentAsFormatException, "Int64", e, null);
}
origPos = FinishContentAsXXX(origPos);
return value;
}
}
finally
{
_pos = origPos;
}
Fallback:
return base.ReadContentAsLong();
}
public override object ReadContentAsObject()
{
int origPos = _pos;
try
{
if (SetupContentAsXXX("ReadContentAsObject"))
{
object value;
try
{
if (this.NodeType == XmlNodeType.Element || this.NodeType == XmlNodeType.EndElement)
value = string.Empty;
else
value = this.ValueAsObject(_token, false);
}
catch (InvalidCastException e)
{
throw new XmlException(SR.Xml_ReadContentAsFormatException, "Object", e, null);
}
catch (FormatException e)
{
throw new XmlException(SR.Xml_ReadContentAsFormatException, "Object", e, null);
}
catch (OverflowException e)
{
throw new XmlException(SR.Xml_ReadContentAsFormatException, "Object", e, null);
}
origPos = FinishContentAsXXX(origPos);
return value;
}
}
finally
{
_pos = origPos;
}
//Fallback:
return base.ReadContentAsObject();
}
public override object ReadContentAs(Type returnType, IXmlNamespaceResolver? namespaceResolver)
{
int origPos = _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(_token, false);
}
else
{
value = this.ValueAs(_token, returnType, namespaceResolver);
}
}
catch (InvalidCastException e)
{
throw new XmlException(SR.Xml_ReadContentAsFormatException, returnType.ToString(), e, null);
}
catch (FormatException e)
{
throw new XmlException(SR.Xml_ReadContentAsFormatException, returnType.ToString(), e, null);
}
catch (OverflowException e)
{
throw new XmlException(SR.Xml_ReadContentAsFormatException, returnType.ToString(), e, null);
}
origPos = FinishContentAsXXX(origPos);
return value;
}
}
finally
{
_pos = origPos;
}
return base.ReadContentAs(returnType, namespaceResolver);
}
//////////
// IXmlNamespaceResolver
System.Collections.Generic.IDictionary<string, string> IXmlNamespaceResolver.GetNamespacesInScope(XmlNamespaceScope scope)
{
if (ScanState.XmlText == _state)
{
Debug.Assert(_textXmlReader != null);
return _textXmlReader.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 (_elemDepth > 0)
{
NamespaceDecl? nsdecl = _elementStack[_elemDepth].nsdecls;
while (null != nsdecl)
{
nstable.Add(nsdecl.prefix, nsdecl.uri);
nsdecl = nsdecl.scopeLink;
}
}
}
else
{
foreach (NamespaceDecl nsdecl in _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 == _state)
{
Debug.Assert(_textXmlReader != null);
return _textXmlReader.LookupPrefix(namespaceName);
}
else
{
if (null == namespaceName)
return null;
string? atomizedNamespaceName = _xnt.Get(namespaceName);
if (null == atomizedNamespaceName)
return null;
for (int i = _elemDepth; i >= 0; i--)
{
NamespaceDecl? nsdecl = _elementStack[i].nsdecls;
while (null != nsdecl)
{
if ((object)nsdecl.uri == (object?)atomizedNamespaceName)
return nsdecl.prefix;
nsdecl = nsdecl.scopeLink;
}
}
return null;
}
}
//////////
// Internal implementation methods
private void VerifyVersion(int requiredVersion, BinXmlToken token)
{
if (_version < requiredVersion)
{
throw CreateUnexpectedTokenException(token);
}
}
private void AddInitNamespace(string prefix, string uri)
{
NamespaceDecl nsdecl = new NamespaceDecl(prefix, uri, _elementStack[0].nsdecls, null, -1, true);
_elementStack[0].nsdecls = nsdecl;
_namespaces.Add(prefix, nsdecl);
}
private void AddName()
{
string txt = ParseText();
int symNum = _symbolTables.symCount++;
string[] symtable = _symbolTables.symtable;
if (symNum == symtable.Length)
{
string[] n = new string[checked(symNum * 2)];
System.Array.Copy(symtable, n, symNum);
_symbolTables.symtable = symtable = n;
}
symtable[symNum] = _xnt.Add(txt);
}
private void AddQName()
{
int nsUri = ReadNameRef();
int prefix = ReadNameRef();
int lname = ReadNameRef();
int qnameNum = _symbolTables.qnameCount++;
QName[] qnametable = _symbolTables.qnametable;
if (qnameNum == qnametable.Length)
{
QName[] n = new QName[checked(qnameNum * 2)];
System.Array.Copy(qnametable, n, qnameNum);
_symbolTables.qnametable = qnametable = n;
}
string[] symtable = _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 = _xnt.Add(prefixStr.Substring(6));
prefixStr = _xmlns;
}
else
{
lnameStr = prefixStr;
prefixStr = string.Empty;
}
nsUriStr = _nsxmlns;
}
else
{
lnameStr = symtable[lname];
nsUriStr = symtable[nsUri];
}
qnametable[qnameNum].Set(prefixStr, lnameStr, nsUriStr);
return;
BadDecl:
throw new XmlException(SR.Xml_BadNamespaceDecl, (string[]?)null);
}
private void NameFlush()
{
_symbolTables.symCount = _symbolTables.qnameCount = 1;
Array.Clear(_symbolTables.symtable, 1, _symbolTables.symtable.Length - 1);
Array.Clear(_symbolTables.qnametable);
}
private void SkipExtn()
{
int cb = ParseMB32();
checked { _pos += cb; }
Fill(-1);
}
private int ReadQNameRef()
{
int nameNum = ParseMB32();
if (nameNum < 0 || nameNum >= _symbolTables.qnameCount)
throw new XmlException(SR.XmlBin_InvalidQNameID, string.Empty);
return nameNum;
}
private int ReadNameRef()
{
int nameNum = ParseMB32();
if (nameNum < 0 || nameNum >= _symbolTables.symCount)
throw new XmlException(SR.XmlBin_InvalidQNameID, string.Empty);
return nameNum;
}
// pull more data from input stream
private bool FillAllowEOF()
{
if (_eof)
return false;
byte[] data = _data;
int pos = _pos;
int mark = _mark;
int end = _end;
if (mark == -1)
{
mark = pos;
}
if (mark >= 0 && mark < end)
{
Debug.Assert(_mark <= _end, "Mark should never be past End");
Debug.Assert(_mark <= _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);
_data = data = newdata;
}
else
{
System.Array.Copy(data, mark, data, 0, cbKeep);
}
pos -= mark;
end -= mark;
_tokDataPos -= mark;
for (int i = 0; i < _attrCount; i++)
{
_attributes[i].AdjustPosition(-mark);
// make sure it is still a valid range
Debug.Assert((_attributes[i].contentPos >= 0) && (_attributes[i].contentPos <= (end)));
}
_pos = pos;
_mark = 0;
}
else
{
Debug.Assert(_attrCount == 0);
_pos -= end;
_mark -= end;
_tokDataPos -= end;
end = 0;
}
int cbFill = data.Length - end;
int cbRead = _inStrm.Read(data, end, cbFill);
_end = end + cbRead;
_eof = !(cbRead > 0);
return (cbRead > 0);
}
// require must be < 1/8 buffer, or else Fill might not actually
// grab that much data
private void Fill_(int require)
{
Debug.Assert((_pos + require) >= _end);
while (FillAllowEOF() && ((_pos + require) >= _end))
;
if ((_pos + require) >= _end)
throw CreateXmlException(SR.Xml_UnexpectedEOF1);
}
// inline the common case
private void Fill(int require)
{
if ((_pos + require) >= _end)
Fill_(require);
}
private byte ReadByte()
{
Fill(0);
return _data[_pos++];
}
private ushort ReadUShort()
{
Fill(1);
int pos = _pos; byte[] data = _data;
ushort val = (ushort)(data[pos] + (data[pos + 1] << 8));
_pos += 2;
return val;
}
private int ParseMB32()
{
byte b = ReadByte();
if (b > 127)
return ParseMB32_(b);
return b;
}
private 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 += (t << 7);
if (b > 127)
{
b = ReadByte();
t = (uint)b & (uint)0x7F;
u += (t << 14);
if (b > 127)
{
b = ReadByte();
t = (uint)b & (uint)0x7F;
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 CreateXmlException(SR.XmlBinary_ValueTooBig);
u += (t << 28);
}
}
}
return (int)u;
}
// this assumes that we have already ensured that all
// necessary bytes are loaded in to the buffer
private int ParseMB32(int pos)
{
uint u, t;
byte[] data = _data;
byte b = data[pos++];
u = (uint)b & (uint)0x7F;
if (b > 127)
{
b = data[pos++];
t = (uint)b & (uint)0x7F;
u += (t << 7);
if (b > 127)
{
b = data[pos++];
t = (uint)b & (uint)0x7F;
u += (t << 14);
if (b > 127)
{
b = data[pos++];
t = (uint)b & (uint)0x7F;
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 CreateXmlException(SR.XmlBinary_ValueTooBig);
u += (t << 28);
}
}
}
}
return (int)u;
}
// we don't actually support MB64, since we use int for
// all our math anyway...
private int ParseMB64()
{
byte b = ReadByte();
if (b > 127)
return ParseMB32_(b);
return b;
}
private BinXmlToken PeekToken()
{
while ((_pos >= _end) && FillAllowEOF())
;
if (_pos >= _end)
return BinXmlToken.EOF;
return (BinXmlToken)_data[_pos];
}
private BinXmlToken ReadToken()
{
while ((_pos >= _end) && FillAllowEOF())
;
if (_pos >= _end)
return BinXmlToken.EOF;
return (BinXmlToken)_data[_pos++];
}
private 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();
}
}
private BinXmlToken NextToken1()
{
BinXmlToken token;
int pos = _pos;
if (pos >= _end)
token = ReadToken();
else
{
token = (BinXmlToken)_data[pos];
_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;
}
private BinXmlToken NextToken()
{
int pos = _pos;
if (pos < _end)
{
BinXmlToken t = (BinXmlToken)_data[pos];
if (!(t >= BinXmlToken.NmFlush && t <= BinXmlToken.Name))
{
_pos = pos + 1;
return t;
}
}
return NextToken1();
}
// peek next non-meta token
private BinXmlToken PeekNextToken()
{
BinXmlToken token = NextToken();
if (BinXmlToken.EOF != token)
_pos--;
return token;
}
// like NextToken() but meta-tokens are skipped (not reinterpreted)
private BinXmlToken RescanNextToken()
{
BinXmlToken token;
while (true)
{
token = ReadToken();
switch (token)
{
case BinXmlToken.Name:
{
int cb = ParseMB32();
checked { _pos += 2 * cb; }
break;
}
case BinXmlToken.QName:
ParseMB32();
ParseMB32();
ParseMB32();
break;
case BinXmlToken.Extn:
{
int cb = ParseMB32();
checked { _pos += cb; }
break;
}
case BinXmlToken.NmFlush:
break;
default:
return token;
}
}
}
private string ParseText()
{
int oldmark = _mark;
try
{
if (oldmark < 0)
_mark = _pos;
int cch, pos;
cch = ScanText(out pos);
return GetString(pos, cch);
}
finally
{
if (oldmark < 0)
_mark = -1;
}
}
private int ScanText(out int start)
{
int cch = ParseMB32();
int oldmark = _mark;
int begin = _pos;
checked { _pos += cch * 2; } // cch = num utf-16 chars
if (_pos > _end)
Fill(-1);
// Fill call might have moved buffer
start = begin - (oldmark - _mark);
return cch;
}
private string GetString(int pos, int cch)
{
Debug.Assert(pos >= 0 && cch >= 0);
if (checked(pos + (cch * sizeof(char))) > _end)
throw new XmlException(SR.Xml_UnexpectedEOF1, (string[]?)null);
if (cch == 0)
return string.Empty;
return string.Create(cch, (_data, pos), static (dstChars, state) =>
{
// bitblt source bytes directly into the destination char span
// n.b. source buffer assumed to be well-formed UTF-16 machine endian
int cch = dstChars.Length;
ReadOnlySpan<byte> srcBytes = state._data.AsSpan(state.pos, checked(cch * sizeof(char)));
Span<byte> dstBytes = MemoryMarshal.AsBytes(dstChars);
srcBytes.CopyTo(dstBytes);
});
}
private string GetAttributeText(int i)
{
string? val = _attributes[i].val;
if (null != val)
return val;
else
{
int origPos = _pos;
try
{
_pos = _attributes[i].contentPos;
BinXmlToken token = RescanNextToken();
if (BinXmlToken.Attr == token || BinXmlToken.EndAttrs == token)
{
return "";
}
_token = token;
ReScanOverValue(token);
return ValueAsString(token);
}
finally
{
_pos = origPos;
}
}
}
private int LocateAttribute(string name, string ns)
{
for (int i = 0; i < _attrCount; i++)
{
if (_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 < _attrCount; i++)
{
if (_attributes[i].name.MatchPrefix(prefix, lname))
return i;
}
return -1;
}
private void PositionOnAttribute(int i)
{
// save element's qname
_attrIndex = i;
_qnameOther = _attributes[i - 1].name;
if (_state == ScanState.Doc)
{
_parentNodeType = _nodetype;
}
_token = BinXmlToken.Attr;
_nodetype = XmlNodeType.Attribute;
_state = ScanState.Attr;
_valueType = typeof(object);
_stringValue = null;
}
private void GrowElements()
{
int newcount = _elementStack.Length * 2;
ElemInfo[] n = new ElemInfo[newcount];
System.Array.Copy(_elementStack, n, _elementStack.Length);
_elementStack = n;
}
private void GrowAttributes()
{
int newcount = _attributes.Length * 2;
AttrInfo[] n = new AttrInfo[newcount];
System.Array.Copy(_attributes, n, _attrCount);
_attributes = n;
}
private void ClearAttributes()
{
if (_attrCount != 0)
_attrCount = 0;
}
private void PushNamespace(string prefix, string ns, bool implied)
{
if (prefix == "xml")
return;
int elemDepth = _elemDepth;
NamespaceDecl? curDecl;
_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
_qnameElement.CheckPrefixNS(prefix, ns);
if (prefix.Length != 0)
{
for (int i = 0; i < _attrCount; i++)
{
if (_attributes[i].name.prefix.Length != 0)
_attributes[i].name.CheckPrefixNS(prefix, ns);
}
}
}
// actually add ns decl
NamespaceDecl decl = new NamespaceDecl(prefix, ns,
_elementStack[elemDepth].nsdecls,
curDecl, elemDepth, implied);
_elementStack[elemDepth].nsdecls = decl;
_namespaces[prefix] = decl;
}
private void PopNamespaces(NamespaceDecl? firstInScopeChain)
{
NamespaceDecl? decl = firstInScopeChain;
while (null != decl)
{
if (null == decl.prevLink)
_namespaces.Remove(decl.prefix);
else
_namespaces[decl.prefix] = decl.prevLink;
NamespaceDecl? next = decl.scopeLink;
// unlink chains for better gc behaviour
decl.prevLink = null;
decl.scopeLink = null;
decl = next;
}
}
private void GenerateImpliedXmlnsAttrs()
{
QName name;
NamespaceDecl? decl = _elementStack[_elemDepth].nsdecls;
while (null != decl)
{
if (decl.implied)
{
if (_attrCount == _attributes.Length)
GrowAttributes();
if (decl.prefix.Length == 0)
name = new QName(string.Empty, _xmlns, _nsxmlns);
else
name = new QName(_xmlns, _xnt.Add(decl.prefix), _nsxmlns);
_attributes[_attrCount].Set(name, decl.uri);
_attrCount++;
}
decl = decl.scopeLink;
}
}
private bool ReadInit(bool skipXmlDecl)
{
string? err;
if (!_sniffed)
{
// check magic header
ushort magic = ReadUShort();
if (magic != 0xFFDF)
{
err = SR.XmlBinary_InvalidSignature;
goto Error;
}
}
// check protocol version
_version = ReadByte();
if (_version != 0x1 && _version != 0x2)
{
err = SR.XmlBinary_InvalidProtocolVersion;
goto Error;
}
// check encoding marker, 1200 == utf16
if (1200 != ReadUShort())
{
err = SR.XmlBinary_UnsupportedCodePage;
goto Error;
}
_state = ScanState.Doc;
if (BinXmlToken.XmlDecl == PeekToken())
{
_pos++;
_attributes[0].Set(new QName(string.Empty, _xnt.Add("version"), string.Empty), ParseText());
_attrCount = 1;
if (BinXmlToken.Encoding == PeekToken())
{
_pos++;
_attributes[1].Set(new QName(string.Empty, _xnt.Add("encoding"), string.Empty), ParseText());
_attrCount++;
}
byte standalone = ReadByte();
switch (standalone)
{
case 0:
break;
case 1:
case 2:
_attributes[_attrCount].Set(new QName(string.Empty, _xnt.Add("standalone"), string.Empty), (standalone == 1) ? "yes" : "no");
_attrCount++;
break;
default:
err = SR.XmlBinary_InvalidStandalone;
goto Error;
}
if (!skipXmlDecl)
{
QName xmlDeclQName = new QName(string.Empty, _xnt.Add("xml"), string.Empty);
_qnameOther = _qnameElement = xmlDeclQName;
_nodetype = XmlNodeType.XmlDeclaration;
_posAfterAttrs = _pos;
return true;
}
// else ReadDoc will clear the attributes for us
}
return ReadDoc();
Error:
_state = ScanState.Error;
throw new XmlException(err, (string[]?)null);
}
private void ScanAttributes()
{
BinXmlToken token;
int xmlspace = -1;
int xmllang = -1;
_mark = _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 (_attrCount == _attributes.Length)
GrowAttributes();
// note: ParseMB32 _must_ happen _before_ we grab this.pos...
QName n = _symbolTables.qnametable[ReadQNameRef()];
_attributes[_attrCount].Set(n, (int)_pos);
if (n.prefix == "xml")
{
if (n.localname == "lang")
{
xmllang = _attrCount;
}
else if (n.localname == "space")
{
xmlspace = _attrCount;
}
}
else if (Ref.Equal(n.namespaceUri, _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(SR.Xml_PrefixForEmptyNs, string.Empty);
this.PushNamespace(n.prefix, n.namespaceUri, true);
}
else if (n.namespaceUri.Length != 0)
{
throw CreateXmlException(SR.XmlBinary_AttrWithNsNoPrefix, n.localname, n.namespaceUri);
}
_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 CreateNotSupportedException(SR.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 = _stringValue;
if (null != val)
{
_attributes[_attrCount - 1].val = val;
_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 = _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;
_elementStack[_elemDepth].xmlSpace = xs;
_xmlspacePreserve = (XmlSpace.Preserve == xs);
}
if (xmllang != -1)
{
_elementStack[_elemDepth].xmlLang = GetAttributeText(xmllang);
}
if (_attrCount < 200)
SimpleCheckForDuplicateAttributes();
else
HashCheckForDuplicateAttributes();
}
private void SimpleCheckForDuplicateAttributes()
{
for (int i = 0; i < _attrCount; i++)
{
string localname, namespaceUri;
_attributes[i].GetLocalnameAndNamespaceUri(out localname, out namespaceUri);
for (int j = i + 1; j < _attrCount; j++)
{
if (_attributes[j].MatchNS(localname, namespaceUri))
throw new XmlException(SR.Xml_DupAttributeName, _attributes[i].name.ToString());
}
}
}
private void HashCheckForDuplicateAttributes()
{
int tblSize = 256;
while (tblSize < _attrCount)
tblSize = checked(tblSize * 2);
if (_attrHashTbl.Length < tblSize)
_attrHashTbl = new int[tblSize];
for (int i = 0; i < _attrCount; i++)
{
string localname, namespaceUri;
int hash = _attributes[i].GetLocalnameAndNamespaceUriAndHash(out localname, out namespaceUri);
int index = hash & (tblSize - 1);
int next = _attrHashTbl[index];
_attrHashTbl[index] = i + 1;
_attributes[i].prevHash = next;
while (next != 0)
{
next--;
if (_attributes[next].MatchHashNS(hash, localname, namespaceUri))
{
throw new XmlException(SR.Xml_DupAttributeName, _attributes[i].name.ToString());
}
next = _attributes[next].prevHash;
}
}
Array.Clear(_attrHashTbl, 0, tblSize);
}
private string XmlDeclValue()
{
StringBuilder sb = new StringBuilder();
for (int i = 0; i < _attrCount; i++)
{
if (i > 0)
sb.Append(' ');
sb.Append(_attributes[i].name.localname);
sb.Append("=\"");
sb.Append(_attributes[i].val);
sb.Append('"');
}
return sb.ToString();
}
private string CDATAValue()
{
Debug.Assert(_stringValue == null, "this.stringValue == null");
Debug.Assert(_token == BinXmlToken.CData, "this.token == BinXmlToken.CData");
string value = GetString(_tokDataPos, _tokLen);
StringBuilder? sb = null;
while (PeekToken() == BinXmlToken.CData)
{
_pos++; // skip over token byte
sb ??= new StringBuilder(value.Length + value.Length / 2).Append(value);
sb.Append(ParseText());
}
if (sb != null)
value = sb.ToString();
_stringValue = value;
return value;
}
private void FinishCDATA()
{
while (true)
{
switch (PeekToken())
{
case BinXmlToken.CData:
// skip
_pos++;
ScanText(out _);
// try again
break;
case BinXmlToken.EndCData:
// done... on to next token...
_pos++;
return;
default:
throw new XmlException(SR.XmlBin_MissingEndCDATA);
}
}
}
private void FinishEndElement()
{
NamespaceDecl? nsdecls = _elementStack[_elemDepth].Clear();
this.PopNamespaces(nsdecls);
_elemDepth--;
}
private bool ReadDoc()
{
switch (_nodetype)
{
case XmlNodeType.CDATA:
FinishCDATA();
break;
case XmlNodeType.EndElement:
FinishEndElement();
break;
case XmlNodeType.Element:
if (_isEmpty)
{
FinishEndElement();
_isEmpty = false;
}
break;
}
Read:
// clear existing state
_nodetype = XmlNodeType.None;
_mark = -1;
if (_qnameOther.localname.Length != 0)
_qnameOther.Clear();
ClearAttributes();
_attrCount = 0;
_valueType = typeof(string);
_stringValue = null;
_hasTypedValue = false;
_token = NextToken();
switch (_token)
{
case BinXmlToken.EOF:
if (_elemDepth > 0)
throw new XmlException(SR.Xml_UnexpectedEOF1, (string[]?)null);
_state = ScanState.EOF;
return false;
case BinXmlToken.Element:
ImplReadElement();
break;
case BinXmlToken.EndElem:
ImplReadEndElement();
break;
case BinXmlToken.DocType:
ImplReadDoctype();
if (_dtdProcessing == DtdProcessing.Ignore)
goto Read;
// nested, don't report doctype
if (_prevNameInfo != null)
goto Read;
break;
case BinXmlToken.PI:
ImplReadPI();
if (_ignorePIs)
goto Read;
break;
case BinXmlToken.Comment:
ImplReadComment();
if (_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 == _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(_token);
if (XmlNodeType.Text == _nodetype)
CheckAllowContent();
else if (_ignoreWhitespace && !_xmlspacePreserve)
goto Read; // skip to next token
return true;
default:
throw CreateUnexpectedTokenException(_token);
}
return true;
}
private void ImplReadData(BinXmlToken tokenType)
{
Debug.Assert(_mark < 0);
_mark = _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:
_valueType = typeof(string);
_hasTypedValue = false;
break;
default:
_valueType = GetValueType(_token);
_hasTypedValue = true;
break;
}
_nodetype = ScanOverValue(_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 CreateNotSupportedException(SR.XmlBinary_ListsOfValuesNotSupported);
default:
break;
}
}
private void ImplReadElement()
{
if (3 != _docState || 9 != _docState)
{
switch (_docState)
{
case 0:
_docState = 9;
break;
case 1:
case 2:
_docState = 3;
break;
case -1:
throw CreateUnexpectedTokenException(_token);
default:
break;
}
}
_elemDepth++;
if (_elemDepth == _elementStack.Length)
GrowElements();
QName qname = _symbolTables.qnametable[ReadQNameRef()];
_qnameOther = _qnameElement = qname;
_elementStack[_elemDepth].Set(qname, _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...
_isEmpty = true;
}
else if (BinXmlToken.SQL_NVARCHAR == t)
{
if (_mark < 0)
_mark = _pos;
// skip over token byte
_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(_pos >= 3);
_pos -= 3; // jump back to start of NVarChar token
}
else
{
Debug.Assert(_pos >= 1);
_pos -= 1; // jump back to EndElem token
}
}
else
{
Debug.Assert(_pos >= 2);
_pos -= 2; // jump back to start of NVarChar token
}
}
_nodetype = XmlNodeType.Element;
_valueType = typeof(object);
_posAfterAttrs = _pos;
}
private void ImplReadEndElement()
{
if (_elemDepth == 0)
throw CreateXmlException(SR.Xml_UnexpectedEndTag);
int index = _elemDepth;
if (1 == index && 3 == _docState)
_docState = -1;
_qnameOther = _elementStack[index].name;
_xmlspacePreserve = _elementStack[index].xmlspacePreserve;
_nodetype = XmlNodeType.EndElement;
}
private void ImplReadDoctype()
{
if (_dtdProcessing == DtdProcessing.Prohibit)
throw CreateXmlException(SR.Xml_DtdIsProhibited);
// 0=>auto, 1=>doc/pre-dtd, 2=>doc/pre-elem, 3=>doc/instance -1=>doc/post-elem, 9=>frag
switch (_docState)
{
case 0: // 0=>auto
case 1: // 1=>doc/pre-dtd
break;
case 9: // 9=>frag
throw CreateXmlException(SR.Xml_DtdNotAllowedInFragment);
default: // 2=>doc/pre-elem, 3=>doc/instance -1=>doc/post-elem
throw CreateXmlException(SR.Xml_BadDTDLocation);
}
_docState = 2;
_qnameOther.localname = ParseText();
if (BinXmlToken.System == PeekToken())
{
_pos++;
_attributes[_attrCount++].Set(new QName(string.Empty, _xnt.Add("SYSTEM"), string.Empty), ParseText());
}
if (BinXmlToken.Public == PeekToken())
{
_pos++;
_attributes[_attrCount++].Set(new QName(string.Empty, _xnt.Add("PUBLIC"), string.Empty), ParseText());
}
if (BinXmlToken.Subset == PeekToken())
{
_pos++;
_mark = _pos;
_tokLen = ScanText(out _tokDataPos);
}
else
{
_tokLen = _tokDataPos = 0;
}
_nodetype = XmlNodeType.DocumentType;
_posAfterAttrs = _pos;
}
private void ImplReadPI()
{
_qnameOther.localname = _symbolTables.symtable[ReadNameRef()];
_mark = _pos;
_tokLen = ScanText(out _tokDataPos);
_nodetype = XmlNodeType.ProcessingInstruction;
}
private void ImplReadComment()
{
_nodetype = XmlNodeType.Comment;
_mark = _pos;
_tokLen = ScanText(out _tokDataPos);
}
private void ImplReadCDATA()
{
CheckAllowContent();
_nodetype = XmlNodeType.CDATA;
_mark = _pos;
_tokLen = ScanText(out _tokDataPos);
}
private void ImplReadNest()
{
CheckAllowContent();
// push current nametables
_prevNameInfo = new NestedBinXml(_symbolTables, _docState, _prevNameInfo);
_symbolTables.Init();
_docState = 0; // auto
}
private void ImplReadEndNest()
{
Debug.Assert(_prevNameInfo != null);
NestedBinXml nested = _prevNameInfo;
_symbolTables = nested.symbolTables;
_docState = nested.docState;
_prevNameInfo = nested.next;
}
private void ImplReadXmlText()
{
CheckAllowContent();
string xmltext = ParseText();
XmlNamespaceManager xnm = new XmlNamespaceManager(_xnt);
foreach (NamespaceDecl decl in _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 = _xnt;
settings.DtdProcessing = DtdProcessing.Prohibit;
if (0 != _elemDepth)
{
settings.ConformanceLevel = ConformanceLevel.Fragment;
}
settings.ReadOnly = true;
XmlParserContext xpc = new XmlParserContext(_xnt, xnm, this.XmlLang, this.XmlSpace);
_textXmlReader = new XmlTextReaderImpl(xmltext, xpc, settings);
if (!_textXmlReader.Read()
|| ((_textXmlReader.NodeType == XmlNodeType.XmlDeclaration)
&& !_textXmlReader.Read()))
{
_state = ScanState.Doc;
ReadDoc();
}
else
{
_state = ScanState.XmlText;
UpdateFromTextReader();
}
}
private void UpdateFromTextReader()
{
Debug.Assert(_textXmlReader != null);
XmlReader r = _textXmlReader;
_nodetype = r.NodeType;
_qnameOther.prefix = r.Prefix;
_qnameOther.localname = r.LocalName;
_qnameOther.namespaceUri = r.NamespaceURI;
_valueType = r.ValueType;
_isEmpty = r.IsEmptyElement;
}
private bool UpdateFromTextReader(bool needUpdate)
{
if (needUpdate)
UpdateFromTextReader();
return needUpdate;
}
private void CheckAllowContent()
{
switch (_docState)
{
case 0: // auto
_docState = 9;
break;
case 9: // conformance = fragment
case 3:
break;
default:
throw CreateXmlException(SR.Xml_InvalidRootData);
}
}
private static Type?[] GenerateTokenTypeMap()
{
Type?[] map = new Type[256];
map[(int)BinXmlToken.XSD_BOOLEAN] = typeof(bool);
map[(int)BinXmlToken.SQL_TINYINT] = typeof(byte);
map[(int)BinXmlToken.XSD_BYTE] = typeof(sbyte);
map[(int)BinXmlToken.SQL_SMALLINT] = typeof(short);
map[(int)BinXmlToken.XSD_UNSIGNEDSHORT] = typeof(ushort);
map[(int)BinXmlToken.XSD_UNSIGNEDINT] = typeof(uint);
map[(int)BinXmlToken.SQL_REAL] = typeof(float);
map[(int)BinXmlToken.SQL_FLOAT] = typeof(double);
map[(int)BinXmlToken.SQL_BIGINT] = typeof(long);
map[(int)BinXmlToken.XSD_UNSIGNEDLONG] = typeof(ulong);
map[(int)BinXmlToken.XSD_QNAME] = typeof(XmlQualifiedName);
Type TypeOfInt32 = typeof(int);
map[(int)BinXmlToken.SQL_BIT] = TypeOfInt32;
map[(int)BinXmlToken.SQL_INT] = TypeOfInt32;
Type TypeOfDecimal = typeof(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(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;
Type TypeOfString = typeof(string);
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;
return map;
}
private System.Type GetValueType(BinXmlToken token)
{
Type? t = s_tokenTypeMap[(int)token];
if (t == null)
throw CreateUnexpectedTokenException(token);
return t;
}
// helper method...
private void ReScanOverValue(BinXmlToken token)
{
ScanOverValue(token, true, false);
}
private XmlNodeType ScanOverValue(BinXmlToken token, bool attr, bool checkChars)
{
if (token == BinXmlToken.SQL_NVARCHAR)
{
if (_mark < 0)
_mark = _pos;
_tokLen = ParseMB32();
_tokDataPos = _pos;
checked { _pos += _tokLen * 2; }
Fill(-1);
// check chars (if this is the first pass and settings.CheckCharacters was set)
if (checkChars && _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);
}
}
private XmlNodeType ScanOverAnyValue(BinXmlToken token, bool attr, bool checkChars)
{
if (_mark < 0)
_mark = _pos;
checked
{
switch (token)
{
case BinXmlToken.SQL_BIT:
case BinXmlToken.SQL_TINYINT:
case BinXmlToken.XSD_BOOLEAN:
case BinXmlToken.XSD_BYTE:
_tokDataPos = _pos;
_tokLen = 1;
_pos += 1;
break;
case BinXmlToken.SQL_SMALLINT:
case BinXmlToken.XSD_UNSIGNEDSHORT:
_tokDataPos = _pos;
_tokLen = 2;
_pos += 2;
break;
case BinXmlToken.SQL_INT:
case BinXmlToken.XSD_UNSIGNEDINT:
case BinXmlToken.SQL_REAL:
case BinXmlToken.SQL_SMALLMONEY:
case BinXmlToken.SQL_SMALLDATETIME:
_tokDataPos = _pos;
_tokLen = 4;
_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:
_tokDataPos = _pos;
_tokLen = 8;
_pos += 8;
break;
case BinXmlToken.SQL_UUID:
_tokDataPos = _pos;
_tokLen = 16;
_pos += 16;
break;
case BinXmlToken.SQL_DECIMAL:
case BinXmlToken.SQL_NUMERIC:
case BinXmlToken.XSD_DECIMAL:
_tokDataPos = _pos;
_tokLen = ParseMB64();
_pos += _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:
_tokLen = ParseMB64();
_tokDataPos = _pos;
_pos += _tokLen;
break;
case BinXmlToken.SQL_CHAR:
case BinXmlToken.SQL_VARCHAR:
case BinXmlToken.SQL_TEXT:
_tokLen = ParseMB64();
_tokDataPos = _pos;
_pos += _tokLen;
if (checkChars && _checkCharacters)
{
// check for invalid chardata
Fill(-1);
string val = ValueAsString(token);
XmlConvert.VerifyCharData(val, ExceptionType.ArgumentException, ExceptionType.XmlException);
_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:
_tokDataPos = _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);
_tokDataPos = _pos;
_tokLen = GetXsdKatmaiTokenLength(token);
_pos += _tokLen;
break;
default:
throw CreateUnexpectedTokenException(token);
}
}
Fill(-1);
return XmlNodeType.Text;
}
private XmlNodeType CheckText(bool attr)
{
Debug.Assert(_checkCharacters, "this.checkCharacters");
// grab local copy (perf)
// Get the bytes for the current token. _tokDataPos is the beginning position,
// and _pos has advanced to the next token (1 past the end of this token).
ReadOnlySpan<byte> data = _data.AsSpan(_tokDataPos, _pos - _tokDataPos);
Debug.Assert(data.Length % 2 == 0, "Data size should not be odd");
if (!attr)
{
// scan if this is whitespace
while (true)
{
if (!BinaryPrimitives.TryReadUInt16LittleEndian(data, out ushort value))
return _xmlspacePreserve ? XmlNodeType.SignificantWhitespace : XmlNodeType.Whitespace;
if (value > byte.MaxValue || !XmlCharType.IsWhiteSpace((char)value))
break;
data = data.Slice(2); // we consumed one ANSI whitespace char
}
}
while (true)
{
char ch;
while (true)
{
if (!BinaryPrimitives.TryReadUInt16LittleEndian(data, out ushort value))
return XmlNodeType.Text;
data = data.Slice(2); // we consumed one char (possibly a high surrogate)
ch = (char)value;
if (!XmlCharType.IsCharData(ch))
break;
}
if (!XmlCharType.IsHighSurrogate(ch))
{
throw XmlConvert.CreateInvalidCharException(ch, '\0', ExceptionType.XmlException);
}
else
{
if (!BinaryPrimitives.TryReadUInt16LittleEndian(data, out ushort lowSurr))
{
throw CreateXmlException(SR.Xml_InvalidSurrogateMissingLowChar);
}
if (!XmlCharType.IsLowSurrogate((char)lowSurr))
{
throw XmlConvert.CreateInvalidSurrogatePairException(ch, (char)lowSurr);
}
data = data.Slice(2); //consumed a low surrogate char
}
}
}
private XmlNodeType CheckTextIsWS()
{
Debug.Assert(!_checkCharacters, "!this.checkCharacters");
byte[] data = _data;
// assert that size is an even number
Debug.Assert(0 == ((_pos - _tokDataPos) & 1), "Data size should not be odd");
for (int pos = _tokDataPos; pos < _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 (_xmlspacePreserve)
return XmlNodeType.SignificantWhitespace;
return XmlNodeType.Whitespace;
NonWSText:
return XmlNodeType.Text;
}
private void CheckValueTokenBounds()
{
if ((_end - _tokDataPos) < _tokLen)
throw CreateXmlException(SR.Xml_UnexpectedEOF1);
}
private 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 = _data[_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 = _data[_pos];
return 6 + XsdKatmaiTimeScaleToValueLength(scale);
default:
throw CreateUnexpectedTokenException(_token);
}
}
private static int XsdKatmaiTimeScaleToValueLength(byte scale)
{
if (scale > 7)
{
throw new XmlException(SR.SqlTypes_ArithOverflow, (string?)null);
}
return XsdKatmaiTimeScaleToValueLengthMap[scale];
}
private long ValueAsLong()
{
CheckValueTokenBounds();
switch (_token)
{
case BinXmlToken.SQL_BIT:
case BinXmlToken.SQL_TINYINT:
{
byte v = _data[_tokDataPos];
return v;
}
case BinXmlToken.XSD_BYTE:
{
sbyte v = unchecked((sbyte)_data[_tokDataPos]);
return v;
}
case BinXmlToken.SQL_SMALLINT:
return GetInt16(_tokDataPos);
case BinXmlToken.SQL_INT:
return GetInt32(_tokDataPos);
case BinXmlToken.SQL_BIGINT:
return GetInt64(_tokDataPos);
case BinXmlToken.XSD_UNSIGNEDSHORT:
return GetUInt16(_tokDataPos);
case BinXmlToken.XSD_UNSIGNEDINT:
return GetUInt32(_tokDataPos);
case BinXmlToken.XSD_UNSIGNEDLONG:
{
ulong v = GetUInt64(_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 CreateUnexpectedTokenException(_token);
}
}
private ulong ValueAsULong()
{
if (BinXmlToken.XSD_UNSIGNEDLONG == _token)
{
CheckValueTokenBounds();
return GetUInt64(_tokDataPos);
}
else
{
throw CreateUnexpectedTokenException(_token);
}
}
private 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(_tokDataPos));
case BinXmlToken.SQL_FLOAT:
return new decimal(GetDouble(_tokDataPos));
case BinXmlToken.SQL_SMALLMONEY:
{
BinXmlSqlMoney v = new BinXmlSqlMoney(GetInt32(_tokDataPos));
return v.ToDecimal();
}
case BinXmlToken.SQL_MONEY:
{
BinXmlSqlMoney v = new BinXmlSqlMoney(GetInt64(_tokDataPos));
return v.ToDecimal();
}
case BinXmlToken.XSD_DECIMAL:
case BinXmlToken.SQL_DECIMAL:
case BinXmlToken.SQL_NUMERIC:
{
BinXmlSqlDecimal v = new BinXmlSqlDecimal(_data, _tokDataPos, _token == BinXmlToken.XSD_DECIMAL);
return v.ToDecimal();
}
default:
throw CreateUnexpectedTokenException(_token);
}
}
private 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(_tokDataPos);
case BinXmlToken.SQL_FLOAT:
return GetDouble(_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 CreateUnexpectedTokenException(_token);
}
}
private DateTime ValueAsDateTime()
{
CheckValueTokenBounds();
switch (_token)
{
case BinXmlToken.SQL_DATETIME:
{
int pos = _tokDataPos;
int dateticks; uint timeticks;
dateticks = GetInt32(pos);
timeticks = GetUInt32(pos + 4);
return BinXmlDateTime.SqlDateTimeToDateTime(dateticks, timeticks);
}
case BinXmlToken.SQL_SMALLDATETIME:
{
int pos = _tokDataPos;
short dateticks; ushort timeticks;
dateticks = GetInt16(pos);
timeticks = GetUInt16(pos + 2);
return BinXmlDateTime.SqlSmallDateTimeToDateTime(dateticks, timeticks);
}
case BinXmlToken.XSD_TIME:
{
long time = GetInt64(_tokDataPos);
return BinXmlDateTime.XsdTimeToDateTime(time);
}
case BinXmlToken.XSD_DATE:
{
long time = GetInt64(_tokDataPos);
return BinXmlDateTime.XsdDateToDateTime(time);
}
case BinXmlToken.XSD_DATETIME:
{
long time = GetInt64(_tokDataPos);
return BinXmlDateTime.XsdDateTimeToDateTime(time);
}
case BinXmlToken.XSD_KATMAI_DATE:
return BinXmlDateTime.XsdKatmaiDateToDateTime(_data, _tokDataPos);
case BinXmlToken.XSD_KATMAI_DATETIME:
return BinXmlDateTime.XsdKatmaiDateTimeToDateTime(_data, _tokDataPos);
case BinXmlToken.XSD_KATMAI_TIME:
return BinXmlDateTime.XsdKatmaiTimeToDateTime(_data, _tokDataPos);
case BinXmlToken.XSD_KATMAI_DATEOFFSET:
return BinXmlDateTime.XsdKatmaiDateOffsetToDateTime(_data, _tokDataPos);
case BinXmlToken.XSD_KATMAI_DATETIMEOFFSET:
return BinXmlDateTime.XsdKatmaiDateTimeOffsetToDateTime(_data, _tokDataPos);
case BinXmlToken.XSD_KATMAI_TIMEOFFSET:
return BinXmlDateTime.XsdKatmaiTimeOffsetToDateTime(_data, _tokDataPos);
default:
throw CreateUnexpectedTokenException(_token);
}
}
private DateTimeOffset ValueAsDateTimeOffset()
{
CheckValueTokenBounds();
return _token switch
{
BinXmlToken.XSD_KATMAI_DATEOFFSET => BinXmlDateTime.XsdKatmaiDateOffsetToDateTimeOffset(_data, _tokDataPos),
BinXmlToken.XSD_KATMAI_DATETIMEOFFSET => BinXmlDateTime.XsdKatmaiDateTimeOffsetToDateTimeOffset(_data, _tokDataPos),
BinXmlToken.XSD_KATMAI_TIMEOFFSET => BinXmlDateTime.XsdKatmaiTimeOffsetToDateTimeOffset(_data, _tokDataPos),
_ => throw CreateUnexpectedTokenException(_token),
};
}
private string ValueAsDateTimeString()
{
CheckValueTokenBounds();
switch (_token)
{
case BinXmlToken.SQL_DATETIME:
{
int pos = _tokDataPos;
int dateticks; uint timeticks;
dateticks = GetInt32(pos);
timeticks = GetUInt32(pos + 4);
return BinXmlDateTime.SqlDateTimeToString(dateticks, timeticks);
}
case BinXmlToken.SQL_SMALLDATETIME:
{
int pos = _tokDataPos;
short dateticks; ushort timeticks;
dateticks = GetInt16(pos);
timeticks = GetUInt16(pos + 2);
return BinXmlDateTime.SqlSmallDateTimeToString(dateticks, timeticks);
}
case BinXmlToken.XSD_TIME:
{
long time = GetInt64(_tokDataPos);
return BinXmlDateTime.XsdTimeToString(time);
}
case BinXmlToken.XSD_DATE:
{
long time = GetInt64(_tokDataPos);
return BinXmlDateTime.XsdDateToString(time);
}
case BinXmlToken.XSD_DATETIME:
{
long time = GetInt64(_tokDataPos);
return BinXmlDateTime.XsdDateTimeToString(time);
}
case BinXmlToken.XSD_KATMAI_DATE:
return BinXmlDateTime.XsdKatmaiDateToString(_data, _tokDataPos);
case BinXmlToken.XSD_KATMAI_DATETIME:
return BinXmlDateTime.XsdKatmaiDateTimeToString(_data, _tokDataPos);
case BinXmlToken.XSD_KATMAI_TIME:
return BinXmlDateTime.XsdKatmaiTimeToString(_data, _tokDataPos);
case BinXmlToken.XSD_KATMAI_DATEOFFSET:
return BinXmlDateTime.XsdKatmaiDateOffsetToString(_data, _tokDataPos);
case BinXmlToken.XSD_KATMAI_DATETIMEOFFSET:
return BinXmlDateTime.XsdKatmaiDateTimeOffsetToString(_data, _tokDataPos);
case BinXmlToken.XSD_KATMAI_TIMEOFFSET:
return BinXmlDateTime.XsdKatmaiTimeOffsetToString(_data, _tokDataPos);
default:
throw CreateUnexpectedTokenException(_token);
}
}
private string ValueAsString(BinXmlToken token)
{
try
{
CheckValueTokenBounds();
switch (token)
{
case BinXmlToken.SQL_NCHAR:
case BinXmlToken.SQL_NVARCHAR:
case BinXmlToken.SQL_NTEXT:
return GetString(_tokDataPos, _tokLen);
case BinXmlToken.XSD_BOOLEAN:
{
if (0 == _data[_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(_tokDataPos));
case BinXmlToken.SQL_FLOAT:
return XmlConvert.ToString(GetDouble(_tokDataPos));
case BinXmlToken.SQL_UUID:
{
int a; short b, c;
int pos = _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(_tokDataPos));
return v.ToString();
}
case BinXmlToken.SQL_MONEY:
{
BinXmlSqlMoney v = new BinXmlSqlMoney(GetInt64(_tokDataPos));
return v.ToString();
}
case BinXmlToken.XSD_DECIMAL:
case BinXmlToken.SQL_DECIMAL:
case BinXmlToken.SQL_NUMERIC:
{
BinXmlSqlDecimal v = new BinXmlSqlDecimal(_data, _tokDataPos, token == BinXmlToken.XSD_DECIMAL);
return v.ToString();
}
case BinXmlToken.SQL_CHAR:
case BinXmlToken.SQL_VARCHAR:
case BinXmlToken.SQL_TEXT:
{
int pos = _tokDataPos;
int codepage = GetInt32(pos);
Encoding enc = System.Text.Encoding.GetEncoding(codepage);
return enc.GetString(_data, pos + 4, _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(_data, _tokDataPos, _tokLen);
}
case BinXmlToken.XSD_BINHEX:
return BinHexEncoder.Encode(_data, _tokDataPos, _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(_tokDataPos);
if (nameNum < 0 || nameNum >= _symbolTables.qnameCount)
throw new XmlException(SR.XmlBin_InvalidQNameID, string.Empty);
QName qname = _symbolTables.qnametable[nameNum];
if (qname.prefix.Length == 0)
return qname.localname;
else
return $"{qname.prefix}:{qname.localname}";
}
default:
throw CreateUnexpectedTokenException(_token);
}
}
catch
{
_state = ScanState.Error;
throw;
}
}
private object ValueAsObject(BinXmlToken token, bool returnInternalTypes)
{
CheckValueTokenBounds();
switch (token)
{
case BinXmlToken.SQL_NCHAR:
case BinXmlToken.SQL_NVARCHAR:
case BinXmlToken.SQL_NTEXT:
return GetString(_tokDataPos, _tokLen);
case BinXmlToken.XSD_BOOLEAN:
return (0 != _data[_tokDataPos]);
case BinXmlToken.SQL_BIT:
return (int)_data[_tokDataPos];
case BinXmlToken.SQL_TINYINT:
return _data[_tokDataPos];
case BinXmlToken.SQL_SMALLINT:
return GetInt16(_tokDataPos);
case BinXmlToken.SQL_INT:
return GetInt32(_tokDataPos);
case BinXmlToken.SQL_BIGINT:
return GetInt64(_tokDataPos);
case BinXmlToken.XSD_BYTE:
{
sbyte v = unchecked((sbyte)_data[_tokDataPos]);
return v;
}
case BinXmlToken.XSD_UNSIGNEDSHORT:
return GetUInt16(_tokDataPos);
case BinXmlToken.XSD_UNSIGNEDINT:
return GetUInt32(_tokDataPos);
case BinXmlToken.XSD_UNSIGNEDLONG:
return GetUInt64(_tokDataPos);
case BinXmlToken.SQL_REAL:
return GetSingle(_tokDataPos);
case BinXmlToken.SQL_FLOAT:
return GetDouble(_tokDataPos);
case BinXmlToken.SQL_UUID:
{
int a; short b, c;
int pos = _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(_tokDataPos));
if (returnInternalTypes)
return v;
else
return v.ToDecimal();
}
case BinXmlToken.SQL_MONEY:
{
BinXmlSqlMoney v = new BinXmlSqlMoney(GetInt64(_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(_data, _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 = _tokDataPos;
int codepage = GetInt32(pos);
Encoding enc = System.Text.Encoding.GetEncoding(codepage);
return enc.GetString(_data, pos + 4, _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[_tokLen];
Array.Copy(_data, _tokDataPos, data, 0, _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(_tokDataPos);
if (nameNum < 0 || nameNum >= _symbolTables.qnameCount)
throw new XmlException(SR.XmlBin_InvalidQNameID, string.Empty);
QName qname = _symbolTables.qnametable[nameNum];
return new XmlQualifiedName(qname.localname, qname.namespaceUri);
}
default:
throw CreateUnexpectedTokenException(_token);
}
}
private static XmlValueConverter GetValueConverter(XmlTypeCode typeCode)
{
XmlSchemaSimpleType xsst = DatatypeImplementation.GetSimpleTypeFromTypeCode(typeCode);
return xsst.ValueConverter;
}
private 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(_tokDataPos, _tokLen),
returnType, namespaceResolver);
break;
case BinXmlToken.XSD_BOOLEAN:
value = GetValueConverter(XmlTypeCode.Boolean).ChangeType(
(0 != _data[_tokDataPos]),
returnType, namespaceResolver);
break;
case BinXmlToken.SQL_BIT:
value = GetValueConverter(XmlTypeCode.NonNegativeInteger).ChangeType(
(int)_data[_tokDataPos],
returnType, namespaceResolver);
break;
case BinXmlToken.SQL_TINYINT:
value = GetValueConverter(XmlTypeCode.UnsignedByte).ChangeType(
_data[_tokDataPos],
returnType, namespaceResolver);
break;
case BinXmlToken.SQL_SMALLINT:
{
int v = GetInt16(_tokDataPos);
value = GetValueConverter(XmlTypeCode.Short).ChangeType(
v, returnType, namespaceResolver);
break;
}
case BinXmlToken.SQL_INT:
{
int v = GetInt32(_tokDataPos);
value = GetValueConverter(XmlTypeCode.Int).ChangeType(
v, returnType, namespaceResolver);
break;
}
case BinXmlToken.SQL_BIGINT:
{
long v = GetInt64(_tokDataPos);
value = GetValueConverter(XmlTypeCode.Long).ChangeType(
v, returnType, namespaceResolver);
break;
}
case BinXmlToken.XSD_BYTE:
{
value = GetValueConverter(XmlTypeCode.Byte).ChangeType(
(int)unchecked((sbyte)_data[_tokDataPos]),
returnType, namespaceResolver);
break;
}
case BinXmlToken.XSD_UNSIGNEDSHORT:
{
int v = GetUInt16(_tokDataPos);
value = GetValueConverter(XmlTypeCode.UnsignedShort).ChangeType(
v, returnType, namespaceResolver);
break;
}
case BinXmlToken.XSD_UNSIGNEDINT:
{
long v = GetUInt32(_tokDataPos);
value = GetValueConverter(XmlTypeCode.UnsignedInt).ChangeType(
v, returnType, namespaceResolver);
break;
}
case BinXmlToken.XSD_UNSIGNEDLONG:
{
decimal v = (decimal)GetUInt64(_tokDataPos);
value = GetValueConverter(XmlTypeCode.UnsignedLong).ChangeType(
v, returnType, namespaceResolver);
break;
}
case BinXmlToken.SQL_REAL:
{
float v = GetSingle(_tokDataPos);
value = GetValueConverter(XmlTypeCode.Float).ChangeType(
v, returnType, namespaceResolver);
break;
}
case BinXmlToken.SQL_FLOAT:
{
double v = GetDouble(_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(_tokDataPos))).ToDecimal(),
returnType, namespaceResolver);
break;
case BinXmlToken.SQL_MONEY:
value = GetValueConverter(XmlTypeCode.Decimal).ChangeType(
(new BinXmlSqlMoney(GetInt64(_tokDataPos))).ToDecimal(),
returnType, namespaceResolver);
break;
case BinXmlToken.XSD_DECIMAL:
case BinXmlToken.SQL_DECIMAL:
case BinXmlToken.SQL_NUMERIC:
value = GetValueConverter(XmlTypeCode.Decimal).ChangeType(
(new BinXmlSqlDecimal(_data, _tokDataPos, token == BinXmlToken.XSD_DECIMAL)).ToDecimal(),
returnType, namespaceResolver);
break;
case BinXmlToken.SQL_CHAR:
case BinXmlToken.SQL_VARCHAR:
case BinXmlToken.SQL_TEXT:
{
int pos = _tokDataPos;
int codepage = GetInt32(pos);
Encoding enc = System.Text.Encoding.GetEncoding(codepage);
value = GetValueConverter(XmlTypeCode.UntypedAtomic).ChangeType(
enc.GetString(_data, pos + 4, _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[_tokLen];
Array.Copy(_data, _tokDataPos, data, 0, _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(_tokDataPos);
if (nameNum < 0 || nameNum >= _symbolTables.qnameCount)
throw new XmlException(SR.XmlBin_InvalidQNameID, string.Empty);
QName qname = _symbolTables.qnametable[nameNum];
value = GetValueConverter(XmlTypeCode.QName).ChangeType(
new XmlQualifiedName(qname.localname, qname.namespaceUri),
returnType, namespaceResolver);
break;
}
default:
throw CreateUnexpectedTokenException(_token);
}
return value;
}
private short GetInt16(int pos) => BinaryPrimitives.ReadInt16LittleEndian(_data.AsSpan(pos));
private ushort GetUInt16(int pos) => BinaryPrimitives.ReadUInt16LittleEndian(_data.AsSpan(pos));
private int GetInt32(int pos) => BinaryPrimitives.ReadInt32LittleEndian(_data.AsSpan(pos));
private uint GetUInt32(int pos) => BinaryPrimitives.ReadUInt32LittleEndian(_data.AsSpan(pos));
private long GetInt64(int pos) => BinaryPrimitives.ReadInt64LittleEndian(_data.AsSpan(pos));
private ulong GetUInt64(int pos) => BinaryPrimitives.ReadUInt64LittleEndian(_data.AsSpan(pos));
private float GetSingle(int offset) => BinaryPrimitives.ReadSingleLittleEndian(_data.AsSpan(offset));
private double GetDouble(int offset) => BinaryPrimitives.ReadDoubleLittleEndian(_data.AsSpan(offset));
private XmlException CreateUnexpectedTokenException(BinXmlToken token)
{
System.Diagnostics.Debug.WriteLine($"Unhandled token: {token}");
return CreateXmlException(SR.XmlBinary_UnexpectedToken);
}
private XmlException CreateXmlException(string res)
{
_state = ScanState.Error;
return new XmlException(res, (string[]?)null);
}
private XmlException CreateXmlException(string res, string arg1, string arg2)
{
_state = ScanState.Error;
return new XmlException(res, new string[] { arg1, arg2 });
}
private NotSupportedException CreateNotSupportedException(string res)
{
_state = ScanState.Error;
return new NotSupportedException(res);
}
}
}
|