|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
namespace System.Xml
{
public interface IXmlBinaryReaderInitializer
{
void SetInput(byte[] buffer, int offset, int count,
IXmlDictionary? dictionary,
XmlDictionaryReaderQuotas quotas,
XmlBinaryReaderSession? session,
OnXmlDictionaryReaderClose? onClose);
void SetInput(Stream stream,
IXmlDictionary? dictionary,
XmlDictionaryReaderQuotas quotas,
XmlBinaryReaderSession? session,
OnXmlDictionaryReaderClose? onClose);
}
internal sealed class XmlBinaryReader : XmlBaseReader, IXmlBinaryReaderInitializer
{
private bool _isTextWithEndElement;
private bool _buffered;
private ArrayState _arrayState;
private int _arrayCount;
private int _maxBytesPerRead;
private XmlBinaryNodeType _arrayNodeType;
private OnXmlDictionaryReaderClose? _onClose;
public XmlBinaryReader()
{
}
public void SetInput(byte[] buffer, int offset, int count,
IXmlDictionary? dictionary,
XmlDictionaryReaderQuotas quotas,
XmlBinaryReaderSession? session,
OnXmlDictionaryReaderClose? onClose)
{
ArgumentNullException.ThrowIfNull(buffer);
ArgumentOutOfRangeException.ThrowIfNegative(offset);
if (offset > buffer.Length)
throw new ArgumentOutOfRangeException(nameof(offset), SR.Format(SR.OffsetExceedsBufferSize, buffer.Length));
ArgumentOutOfRangeException.ThrowIfNegative(count);
if (count > buffer.Length - offset)
throw new ArgumentOutOfRangeException(nameof(count), SR.Format(SR.SizeExceedsRemainingBufferSpace, buffer.Length - offset));
MoveToInitial(quotas, onClose);
BufferReader.SetBuffer(buffer, offset, count, dictionary, session);
_buffered = true;
}
public void SetInput(Stream stream,
IXmlDictionary? dictionary,
XmlDictionaryReaderQuotas quotas,
XmlBinaryReaderSession? session,
OnXmlDictionaryReaderClose? onClose)
{
ArgumentNullException.ThrowIfNull(stream);
MoveToInitial(quotas, onClose);
BufferReader.SetBuffer(stream, dictionary, session);
_buffered = false;
}
private void MoveToInitial(XmlDictionaryReaderQuotas quotas, OnXmlDictionaryReaderClose? onClose)
{
MoveToInitial(quotas);
_maxBytesPerRead = quotas.MaxBytesPerRead;
_arrayState = ArrayState.None;
_onClose = onClose;
_isTextWithEndElement = false;
}
public override void Close()
{
base.Close();
OnXmlDictionaryReaderClose? onClose = _onClose;
_onClose = null;
onClose?.Invoke(this);
}
public override string ReadElementContentAsString()
{
if (this.Node.NodeType != XmlNodeType.Element)
MoveToStartElement();
if (!CanOptimizeReadElementContent())
return base.ReadElementContentAsString();
string value;
switch (GetNodeType())
{
case XmlBinaryNodeType.Chars8TextWithEndElement:
SkipNodeType();
value = BufferReader.ReadUTF8String(ReadUInt8());
ReadTextWithEndElement();
break;
case XmlBinaryNodeType.DictionaryTextWithEndElement:
SkipNodeType();
value = BufferReader.GetDictionaryString(ReadDictionaryKey()).Value;
ReadTextWithEndElement();
break;
default:
value = base.ReadElementContentAsString();
break;
}
if (value.Length > Quotas.MaxStringContentLength)
XmlExceptionHelper.ThrowMaxStringContentLengthExceeded(this, Quotas.MaxStringContentLength);
return value;
}
public override bool ReadElementContentAsBoolean()
{
if (this.Node.NodeType != XmlNodeType.Element)
MoveToStartElement();
if (!CanOptimizeReadElementContent())
return base.ReadElementContentAsBoolean();
bool value;
switch (GetNodeType())
{
case XmlBinaryNodeType.TrueTextWithEndElement:
SkipNodeType();
value = true;
ReadTextWithEndElement();
break;
case XmlBinaryNodeType.FalseTextWithEndElement:
SkipNodeType();
value = false;
ReadTextWithEndElement();
break;
case XmlBinaryNodeType.BoolTextWithEndElement:
SkipNodeType();
value = (BufferReader.ReadUInt8() != 0);
ReadTextWithEndElement();
break;
default:
value = base.ReadElementContentAsBoolean();
break;
}
return value;
}
public override int ReadElementContentAsInt()
{
if (this.Node.NodeType != XmlNodeType.Element)
MoveToStartElement();
if (!CanOptimizeReadElementContent())
return base.ReadElementContentAsInt();
int value;
switch (GetNodeType())
{
case XmlBinaryNodeType.ZeroTextWithEndElement:
SkipNodeType();
value = 0;
ReadTextWithEndElement();
break;
case XmlBinaryNodeType.OneTextWithEndElement:
SkipNodeType();
value = 1;
ReadTextWithEndElement();
break;
case XmlBinaryNodeType.Int8TextWithEndElement:
SkipNodeType();
value = BufferReader.ReadInt8();
ReadTextWithEndElement();
break;
case XmlBinaryNodeType.Int16TextWithEndElement:
SkipNodeType();
value = BufferReader.ReadInt16();
ReadTextWithEndElement();
break;
case XmlBinaryNodeType.Int32TextWithEndElement:
SkipNodeType();
value = BufferReader.ReadInt32();
ReadTextWithEndElement();
break;
default:
value = base.ReadElementContentAsInt();
break;
}
return value;
}
private bool CanOptimizeReadElementContent()
{
return (_arrayState == ArrayState.None && !Signing);
}
public override float ReadElementContentAsFloat()
{
if (this.Node.NodeType != XmlNodeType.Element)
MoveToStartElement();
if (CanOptimizeReadElementContent() && GetNodeType() == XmlBinaryNodeType.FloatTextWithEndElement)
{
SkipNodeType();
float value = BufferReader.ReadSingle();
ReadTextWithEndElement();
return value;
}
return base.ReadElementContentAsFloat();
}
public override double ReadElementContentAsDouble()
{
if (this.Node.NodeType != XmlNodeType.Element)
MoveToStartElement();
if (CanOptimizeReadElementContent() && GetNodeType() == XmlBinaryNodeType.DoubleTextWithEndElement)
{
SkipNodeType();
double value = BufferReader.ReadDouble();
ReadTextWithEndElement();
return value;
}
return base.ReadElementContentAsDouble();
}
public override decimal ReadElementContentAsDecimal()
{
if (this.Node.NodeType != XmlNodeType.Element)
MoveToStartElement();
if (CanOptimizeReadElementContent() && GetNodeType() == XmlBinaryNodeType.DecimalTextWithEndElement)
{
SkipNodeType();
decimal value = BufferReader.ReadDecimal();
ReadTextWithEndElement();
return value;
}
return base.ReadElementContentAsDecimal();
}
public override DateTime ReadElementContentAsDateTime()
{
if (this.Node.NodeType != XmlNodeType.Element)
MoveToStartElement();
if (CanOptimizeReadElementContent() && GetNodeType() == XmlBinaryNodeType.DateTimeTextWithEndElement)
{
SkipNodeType();
DateTime value = BufferReader.ReadDateTime();
ReadTextWithEndElement();
return value;
}
return base.ReadElementContentAsDateTime();
}
public override TimeSpan ReadElementContentAsTimeSpan()
{
if (this.Node.NodeType != XmlNodeType.Element)
MoveToStartElement();
if (CanOptimizeReadElementContent() && GetNodeType() == XmlBinaryNodeType.TimeSpanTextWithEndElement)
{
SkipNodeType();
TimeSpan value = BufferReader.ReadTimeSpan();
ReadTextWithEndElement();
return value;
}
return base.ReadElementContentAsTimeSpan();
}
public override Guid ReadElementContentAsGuid()
{
if (this.Node.NodeType != XmlNodeType.Element)
MoveToStartElement();
if (CanOptimizeReadElementContent() && GetNodeType() == XmlBinaryNodeType.GuidTextWithEndElement)
{
SkipNodeType();
Guid value = BufferReader.ReadGuid();
ReadTextWithEndElement();
return value;
}
return base.ReadElementContentAsGuid();
}
public override UniqueId ReadElementContentAsUniqueId()
{
if (this.Node.NodeType != XmlNodeType.Element)
MoveToStartElement();
if (CanOptimizeReadElementContent() && GetNodeType() == XmlBinaryNodeType.UniqueIdTextWithEndElement)
{
SkipNodeType();
UniqueId value = BufferReader.ReadUniqueId();
ReadTextWithEndElement();
return value;
}
return base.ReadElementContentAsUniqueId();
}
public override bool TryGetBase64ContentLength(out int length)
{
length = 0;
if (!_buffered)
return false;
if (_arrayState != ArrayState.None)
return false;
int totalLength;
if (!this.Node.Value.TryGetByteArrayLength(out totalLength))
return false;
int offset = BufferReader.Offset;
try
{
bool done = false;
while (!done && !BufferReader.EndOfFile)
{
XmlBinaryNodeType nodeType = GetNodeType();
SkipNodeType();
int actual;
switch (nodeType)
{
case XmlBinaryNodeType.Bytes8TextWithEndElement:
actual = BufferReader.ReadUInt8();
done = true;
break;
case XmlBinaryNodeType.Bytes16TextWithEndElement:
actual = BufferReader.ReadUInt16();
done = true;
break;
case XmlBinaryNodeType.Bytes32TextWithEndElement:
actual = BufferReader.ReadUInt31();
done = true;
break;
case XmlBinaryNodeType.EndElement:
actual = 0;
done = true;
break;
case XmlBinaryNodeType.Bytes8Text:
actual = BufferReader.ReadUInt8();
break;
case XmlBinaryNodeType.Bytes16Text:
actual = BufferReader.ReadUInt16();
break;
case XmlBinaryNodeType.Bytes32Text:
actual = BufferReader.ReadUInt31();
break;
default:
// Non-optimal or unexpected node - fallback
return false;
}
BufferReader.Advance(actual);
if (totalLength > int.MaxValue - actual)
return false;
totalLength += actual;
}
length = totalLength;
return true;
}
finally
{
BufferReader.Offset = offset;
}
}
private void ReadTextWithEndElement()
{
ExitScope();
ReadNode();
}
private XmlAtomicTextNode MoveToAtomicTextWithEndElement()
{
_isTextWithEndElement = true;
return MoveToAtomicText();
}
public override bool Read()
{
if (this.Node.ReadState == ReadState.Closed)
return false;
SignNode();
if (_isTextWithEndElement)
{
_isTextWithEndElement = false;
MoveToEndElement();
return true;
}
if (_arrayState == ArrayState.Content)
{
if (_arrayCount != 0)
{
MoveToArrayElement();
return true;
}
_arrayState = ArrayState.None;
}
if (this.Node.ExitScope)
{
ExitScope();
}
return ReadNode();
}
private bool ReadNode()
{
if (!_buffered)
BufferReader.SetWindow(ElementNode.BufferOffset, _maxBytesPerRead);
if (BufferReader.EndOfFile)
{
MoveToEndOfFile();
return false;
}
XmlBinaryNodeType nodeType;
if (_arrayState == ArrayState.None)
{
nodeType = GetNodeType();
SkipNodeType();
}
else
{
Debug.Assert(_arrayState == ArrayState.Element);
nodeType = _arrayNodeType;
_arrayCount--;
_arrayState = ArrayState.Content;
}
XmlElementNode elementNode;
PrefixHandleType prefix;
switch (nodeType)
{
case XmlBinaryNodeType.ShortElement:
elementNode = EnterScope();
elementNode.Prefix.SetValue(PrefixHandleType.Empty);
ReadName(elementNode.LocalName);
ReadAttributes();
elementNode.Namespace = LookupNamespace(PrefixHandleType.Empty);
elementNode.BufferOffset = BufferReader.Offset;
return true;
case XmlBinaryNodeType.Element:
elementNode = EnterScope();
ReadName(elementNode.Prefix);
ReadName(elementNode.LocalName);
ReadAttributes();
elementNode.Namespace = LookupNamespace(elementNode.Prefix);
elementNode.BufferOffset = BufferReader.Offset;
return true;
case XmlBinaryNodeType.ShortDictionaryElement:
elementNode = EnterScope();
elementNode.Prefix.SetValue(PrefixHandleType.Empty);
ReadDictionaryName(elementNode.LocalName);
ReadAttributes();
elementNode.Namespace = LookupNamespace(PrefixHandleType.Empty);
elementNode.BufferOffset = BufferReader.Offset;
return true;
case XmlBinaryNodeType.DictionaryElement:
elementNode = EnterScope();
ReadName(elementNode.Prefix);
ReadDictionaryName(elementNode.LocalName);
ReadAttributes();
elementNode.Namespace = LookupNamespace(elementNode.Prefix);
elementNode.BufferOffset = BufferReader.Offset;
return true;
case XmlBinaryNodeType.PrefixElementA:
case XmlBinaryNodeType.PrefixElementB:
case XmlBinaryNodeType.PrefixElementC:
case XmlBinaryNodeType.PrefixElementD:
case XmlBinaryNodeType.PrefixElementE:
case XmlBinaryNodeType.PrefixElementF:
case XmlBinaryNodeType.PrefixElementG:
case XmlBinaryNodeType.PrefixElementH:
case XmlBinaryNodeType.PrefixElementI:
case XmlBinaryNodeType.PrefixElementJ:
case XmlBinaryNodeType.PrefixElementK:
case XmlBinaryNodeType.PrefixElementL:
case XmlBinaryNodeType.PrefixElementM:
case XmlBinaryNodeType.PrefixElementN:
case XmlBinaryNodeType.PrefixElementO:
case XmlBinaryNodeType.PrefixElementP:
case XmlBinaryNodeType.PrefixElementQ:
case XmlBinaryNodeType.PrefixElementR:
case XmlBinaryNodeType.PrefixElementS:
case XmlBinaryNodeType.PrefixElementT:
case XmlBinaryNodeType.PrefixElementU:
case XmlBinaryNodeType.PrefixElementV:
case XmlBinaryNodeType.PrefixElementW:
case XmlBinaryNodeType.PrefixElementX:
case XmlBinaryNodeType.PrefixElementY:
case XmlBinaryNodeType.PrefixElementZ:
elementNode = EnterScope();
prefix = PrefixHandle.GetAlphaPrefix((int)nodeType - (int)XmlBinaryNodeType.PrefixElementA);
elementNode.Prefix.SetValue(prefix);
ReadName(elementNode.LocalName);
ReadAttributes();
elementNode.Namespace = LookupNamespace(prefix);
elementNode.BufferOffset = BufferReader.Offset;
return true;
case XmlBinaryNodeType.PrefixDictionaryElementA:
case XmlBinaryNodeType.PrefixDictionaryElementB:
case XmlBinaryNodeType.PrefixDictionaryElementC:
case XmlBinaryNodeType.PrefixDictionaryElementD:
case XmlBinaryNodeType.PrefixDictionaryElementE:
case XmlBinaryNodeType.PrefixDictionaryElementF:
case XmlBinaryNodeType.PrefixDictionaryElementG:
case XmlBinaryNodeType.PrefixDictionaryElementH:
case XmlBinaryNodeType.PrefixDictionaryElementI:
case XmlBinaryNodeType.PrefixDictionaryElementJ:
case XmlBinaryNodeType.PrefixDictionaryElementK:
case XmlBinaryNodeType.PrefixDictionaryElementL:
case XmlBinaryNodeType.PrefixDictionaryElementM:
case XmlBinaryNodeType.PrefixDictionaryElementN:
case XmlBinaryNodeType.PrefixDictionaryElementO:
case XmlBinaryNodeType.PrefixDictionaryElementP:
case XmlBinaryNodeType.PrefixDictionaryElementQ:
case XmlBinaryNodeType.PrefixDictionaryElementR:
case XmlBinaryNodeType.PrefixDictionaryElementS:
case XmlBinaryNodeType.PrefixDictionaryElementT:
case XmlBinaryNodeType.PrefixDictionaryElementU:
case XmlBinaryNodeType.PrefixDictionaryElementV:
case XmlBinaryNodeType.PrefixDictionaryElementW:
case XmlBinaryNodeType.PrefixDictionaryElementX:
case XmlBinaryNodeType.PrefixDictionaryElementY:
case XmlBinaryNodeType.PrefixDictionaryElementZ:
elementNode = EnterScope();
prefix = PrefixHandle.GetAlphaPrefix((int)nodeType - (int)XmlBinaryNodeType.PrefixDictionaryElementA);
elementNode.Prefix.SetValue(prefix);
ReadDictionaryName(elementNode.LocalName);
ReadAttributes();
elementNode.Namespace = LookupNamespace(prefix);
elementNode.BufferOffset = BufferReader.Offset;
return true;
case XmlBinaryNodeType.EndElement:
MoveToEndElement();
return true;
case XmlBinaryNodeType.Comment:
ReadName(MoveToComment().Value);
return true;
case XmlBinaryNodeType.EmptyTextWithEndElement:
MoveToAtomicTextWithEndElement().Value.SetValue(ValueHandleType.Empty);
if (this.OutsideRootElement)
VerifyWhitespace();
return true;
case XmlBinaryNodeType.ZeroTextWithEndElement:
MoveToAtomicTextWithEndElement().Value.SetValue(ValueHandleType.Zero);
if (this.OutsideRootElement)
VerifyWhitespace();
return true;
case XmlBinaryNodeType.OneTextWithEndElement:
MoveToAtomicTextWithEndElement().Value.SetValue(ValueHandleType.One);
if (this.OutsideRootElement)
VerifyWhitespace();
return true;
case XmlBinaryNodeType.TrueTextWithEndElement:
MoveToAtomicTextWithEndElement().Value.SetValue(ValueHandleType.True);
if (this.OutsideRootElement)
VerifyWhitespace();
return true;
case XmlBinaryNodeType.FalseTextWithEndElement:
MoveToAtomicTextWithEndElement().Value.SetValue(ValueHandleType.False);
if (this.OutsideRootElement)
VerifyWhitespace();
return true;
case XmlBinaryNodeType.BoolTextWithEndElement:
MoveToAtomicTextWithEndElement().Value.SetValue(ReadUInt8() != 0 ? ValueHandleType.True : ValueHandleType.False);
if (this.OutsideRootElement)
VerifyWhitespace();
return true;
case XmlBinaryNodeType.Chars8TextWithEndElement:
if (_buffered)
ReadText(MoveToAtomicTextWithEndElement(), ValueHandleType.UTF8, ReadUInt8());
else
ReadPartialUTF8Text(true, ReadUInt8());
return true;
case XmlBinaryNodeType.Chars8Text:
if (_buffered)
ReadText(MoveToComplexText(), ValueHandleType.UTF8, ReadUInt8());
else
ReadPartialUTF8Text(false, ReadUInt8());
return true;
case XmlBinaryNodeType.Chars16TextWithEndElement:
if (_buffered)
ReadText(MoveToAtomicTextWithEndElement(), ValueHandleType.UTF8, ReadUInt16());
else
ReadPartialUTF8Text(true, ReadUInt16());
return true;
case XmlBinaryNodeType.Chars16Text:
if (_buffered)
ReadText(MoveToComplexText(), ValueHandleType.UTF8, ReadUInt16());
else
ReadPartialUTF8Text(false, ReadUInt16());
return true;
case XmlBinaryNodeType.Chars32TextWithEndElement:
if (_buffered)
ReadText(MoveToAtomicTextWithEndElement(), ValueHandleType.UTF8, ReadUInt31());
else
ReadPartialUTF8Text(true, ReadUInt31());
return true;
case XmlBinaryNodeType.Chars32Text:
if (_buffered)
ReadText(MoveToComplexText(), ValueHandleType.UTF8, ReadUInt31());
else
ReadPartialUTF8Text(false, ReadUInt31());
return true;
case XmlBinaryNodeType.UnicodeChars8TextWithEndElement:
ReadUnicodeText(true, ReadUInt8());
return true;
case XmlBinaryNodeType.UnicodeChars8Text:
ReadUnicodeText(false, ReadUInt8());
return true;
case XmlBinaryNodeType.UnicodeChars16TextWithEndElement:
ReadUnicodeText(true, ReadUInt16());
return true;
case XmlBinaryNodeType.UnicodeChars16Text:
ReadUnicodeText(false, ReadUInt16());
return true;
case XmlBinaryNodeType.UnicodeChars32TextWithEndElement:
ReadUnicodeText(true, ReadUInt31());
return true;
case XmlBinaryNodeType.UnicodeChars32Text:
ReadUnicodeText(false, ReadUInt31());
return true;
case XmlBinaryNodeType.Bytes8TextWithEndElement:
if (_buffered)
ReadBinaryText(MoveToAtomicTextWithEndElement(), ReadUInt8());
else
ReadPartialBinaryText(true, ReadUInt8());
return true;
case XmlBinaryNodeType.Bytes8Text:
if (_buffered)
ReadBinaryText(MoveToComplexText(), ReadUInt8());
else
ReadPartialBinaryText(false, ReadUInt8());
return true;
case XmlBinaryNodeType.Bytes16TextWithEndElement:
if (_buffered)
ReadBinaryText(MoveToAtomicTextWithEndElement(), ReadUInt16());
else
ReadPartialBinaryText(true, ReadUInt16());
return true;
case XmlBinaryNodeType.Bytes16Text:
if (_buffered)
ReadBinaryText(MoveToComplexText(), ReadUInt16());
else
ReadPartialBinaryText(false, ReadUInt16());
return true;
case XmlBinaryNodeType.Bytes32TextWithEndElement:
if (_buffered)
ReadBinaryText(MoveToAtomicTextWithEndElement(), ReadUInt31());
else
ReadPartialBinaryText(true, ReadUInt31());
return true;
case XmlBinaryNodeType.Bytes32Text:
if (_buffered)
ReadBinaryText(MoveToComplexText(), ReadUInt31());
else
ReadPartialBinaryText(false, ReadUInt31());
return true;
case XmlBinaryNodeType.DictionaryTextWithEndElement:
MoveToAtomicTextWithEndElement().Value.SetDictionaryValue(ReadDictionaryKey());
return true;
case XmlBinaryNodeType.UniqueIdTextWithEndElement:
ReadText(MoveToAtomicTextWithEndElement(), ValueHandleType.UniqueId, ValueHandleLength.UniqueId);
return true;
case XmlBinaryNodeType.GuidTextWithEndElement:
ReadText(MoveToAtomicTextWithEndElement(), ValueHandleType.Guid, ValueHandleLength.Guid);
return true;
case XmlBinaryNodeType.DecimalTextWithEndElement:
ReadText(MoveToAtomicTextWithEndElement(), ValueHandleType.Decimal, ValueHandleLength.Decimal);
return true;
case XmlBinaryNodeType.Int8TextWithEndElement:
ReadText(MoveToAtomicTextWithEndElement(), ValueHandleType.Int8, ValueHandleLength.Int8);
return true;
case XmlBinaryNodeType.Int16TextWithEndElement:
ReadText(MoveToAtomicTextWithEndElement(), ValueHandleType.Int16, ValueHandleLength.Int16);
return true;
case XmlBinaryNodeType.Int32TextWithEndElement:
ReadText(MoveToAtomicTextWithEndElement(), ValueHandleType.Int32, ValueHandleLength.Int32);
return true;
case XmlBinaryNodeType.Int64TextWithEndElement:
ReadText(MoveToAtomicTextWithEndElement(), ValueHandleType.Int64, ValueHandleLength.Int64);
return true;
case XmlBinaryNodeType.UInt64TextWithEndElement:
ReadText(MoveToAtomicTextWithEndElement(), ValueHandleType.UInt64, ValueHandleLength.UInt64);
return true;
case XmlBinaryNodeType.FloatTextWithEndElement:
ReadText(MoveToAtomicTextWithEndElement(), ValueHandleType.Single, ValueHandleLength.Single);
return true;
case XmlBinaryNodeType.DoubleTextWithEndElement:
ReadText(MoveToAtomicTextWithEndElement(), ValueHandleType.Double, ValueHandleLength.Double);
return true;
case XmlBinaryNodeType.TimeSpanTextWithEndElement:
ReadText(MoveToAtomicTextWithEndElement(), ValueHandleType.TimeSpan, ValueHandleLength.TimeSpan);
return true;
case XmlBinaryNodeType.DateTimeTextWithEndElement:
ReadText(MoveToAtomicTextWithEndElement(), ValueHandleType.DateTime, ValueHandleLength.DateTime);
return true;
case XmlBinaryNodeType.QNameDictionaryTextWithEndElement:
BufferReader.ReadQName(MoveToAtomicTextWithEndElement().Value);
return true;
case XmlBinaryNodeType.Array:
ReadArray();
return true;
default:
BufferReader.ReadValue(nodeType, MoveToComplexText().Value);
return true;
}
}
private void VerifyWhitespace()
{
if (!this.Node.Value.IsWhitespace())
XmlExceptionHelper.ThrowInvalidBinaryFormat(this);
}
private void ReadAttributes()
{
XmlBinaryNodeType nodeType = GetNodeType();
if (nodeType < XmlBinaryNodeType.MinAttribute || nodeType > XmlBinaryNodeType.MaxAttribute)
return;
ReadAttributes2();
}
private void ReadAttributes2()
{
int startOffset = 0;
if (_buffered)
startOffset = BufferReader.Offset;
while (true)
{
XmlAttributeNode attributeNode;
Namespace nameSpace;
PrefixHandleType prefix;
XmlBinaryNodeType nodeType = GetNodeType();
switch (nodeType)
{
case XmlBinaryNodeType.ShortAttribute:
SkipNodeType();
attributeNode = AddAttribute();
attributeNode.Prefix.SetValue(PrefixHandleType.Empty);
ReadName(attributeNode.LocalName);
ReadAttributeText(attributeNode.AttributeText!);
break;
case XmlBinaryNodeType.Attribute:
SkipNodeType();
attributeNode = AddAttribute();
ReadName(attributeNode.Prefix);
ReadName(attributeNode.LocalName);
ReadAttributeText(attributeNode.AttributeText!);
FixXmlAttribute(attributeNode);
break;
case XmlBinaryNodeType.ShortDictionaryAttribute:
SkipNodeType();
attributeNode = AddAttribute();
attributeNode.Prefix.SetValue(PrefixHandleType.Empty);
ReadDictionaryName(attributeNode.LocalName);
ReadAttributeText(attributeNode.AttributeText!);
break;
case XmlBinaryNodeType.DictionaryAttribute:
SkipNodeType();
attributeNode = AddAttribute();
ReadName(attributeNode.Prefix);
ReadDictionaryName(attributeNode.LocalName);
ReadAttributeText(attributeNode.AttributeText!);
break;
case XmlBinaryNodeType.XmlnsAttribute:
SkipNodeType();
nameSpace = AddNamespace();
ReadName(nameSpace.Prefix);
ReadName(nameSpace.Uri);
AddXmlnsAttribute(nameSpace);
break;
case XmlBinaryNodeType.ShortXmlnsAttribute:
SkipNodeType();
nameSpace = AddNamespace();
nameSpace.Prefix.SetValue(PrefixHandleType.Empty);
ReadName(nameSpace.Uri);
AddXmlnsAttribute(nameSpace);
break;
case XmlBinaryNodeType.ShortDictionaryXmlnsAttribute:
SkipNodeType();
nameSpace = AddNamespace();
nameSpace.Prefix.SetValue(PrefixHandleType.Empty);
ReadDictionaryName(nameSpace.Uri);
AddXmlnsAttribute(nameSpace);
break;
case XmlBinaryNodeType.DictionaryXmlnsAttribute:
SkipNodeType();
nameSpace = AddNamespace();
ReadName(nameSpace.Prefix);
ReadDictionaryName(nameSpace.Uri);
AddXmlnsAttribute(nameSpace);
break;
case XmlBinaryNodeType.PrefixDictionaryAttributeA:
case XmlBinaryNodeType.PrefixDictionaryAttributeB:
case XmlBinaryNodeType.PrefixDictionaryAttributeC:
case XmlBinaryNodeType.PrefixDictionaryAttributeD:
case XmlBinaryNodeType.PrefixDictionaryAttributeE:
case XmlBinaryNodeType.PrefixDictionaryAttributeF:
case XmlBinaryNodeType.PrefixDictionaryAttributeG:
case XmlBinaryNodeType.PrefixDictionaryAttributeH:
case XmlBinaryNodeType.PrefixDictionaryAttributeI:
case XmlBinaryNodeType.PrefixDictionaryAttributeJ:
case XmlBinaryNodeType.PrefixDictionaryAttributeK:
case XmlBinaryNodeType.PrefixDictionaryAttributeL:
case XmlBinaryNodeType.PrefixDictionaryAttributeM:
case XmlBinaryNodeType.PrefixDictionaryAttributeN:
case XmlBinaryNodeType.PrefixDictionaryAttributeO:
case XmlBinaryNodeType.PrefixDictionaryAttributeP:
case XmlBinaryNodeType.PrefixDictionaryAttributeQ:
case XmlBinaryNodeType.PrefixDictionaryAttributeR:
case XmlBinaryNodeType.PrefixDictionaryAttributeS:
case XmlBinaryNodeType.PrefixDictionaryAttributeT:
case XmlBinaryNodeType.PrefixDictionaryAttributeU:
case XmlBinaryNodeType.PrefixDictionaryAttributeV:
case XmlBinaryNodeType.PrefixDictionaryAttributeW:
case XmlBinaryNodeType.PrefixDictionaryAttributeX:
case XmlBinaryNodeType.PrefixDictionaryAttributeY:
case XmlBinaryNodeType.PrefixDictionaryAttributeZ:
SkipNodeType();
attributeNode = AddAttribute();
prefix = PrefixHandle.GetAlphaPrefix((int)nodeType - (int)XmlBinaryNodeType.PrefixDictionaryAttributeA);
attributeNode.Prefix.SetValue(prefix);
ReadDictionaryName(attributeNode.LocalName);
ReadAttributeText(attributeNode.AttributeText!);
break;
case XmlBinaryNodeType.PrefixAttributeA:
case XmlBinaryNodeType.PrefixAttributeB:
case XmlBinaryNodeType.PrefixAttributeC:
case XmlBinaryNodeType.PrefixAttributeD:
case XmlBinaryNodeType.PrefixAttributeE:
case XmlBinaryNodeType.PrefixAttributeF:
case XmlBinaryNodeType.PrefixAttributeG:
case XmlBinaryNodeType.PrefixAttributeH:
case XmlBinaryNodeType.PrefixAttributeI:
case XmlBinaryNodeType.PrefixAttributeJ:
case XmlBinaryNodeType.PrefixAttributeK:
case XmlBinaryNodeType.PrefixAttributeL:
case XmlBinaryNodeType.PrefixAttributeM:
case XmlBinaryNodeType.PrefixAttributeN:
case XmlBinaryNodeType.PrefixAttributeO:
case XmlBinaryNodeType.PrefixAttributeP:
case XmlBinaryNodeType.PrefixAttributeQ:
case XmlBinaryNodeType.PrefixAttributeR:
case XmlBinaryNodeType.PrefixAttributeS:
case XmlBinaryNodeType.PrefixAttributeT:
case XmlBinaryNodeType.PrefixAttributeU:
case XmlBinaryNodeType.PrefixAttributeV:
case XmlBinaryNodeType.PrefixAttributeW:
case XmlBinaryNodeType.PrefixAttributeX:
case XmlBinaryNodeType.PrefixAttributeY:
case XmlBinaryNodeType.PrefixAttributeZ:
SkipNodeType();
attributeNode = AddAttribute();
prefix = PrefixHandle.GetAlphaPrefix((int)nodeType - (int)XmlBinaryNodeType.PrefixAttributeA);
attributeNode.Prefix.SetValue(prefix);
ReadName(attributeNode.LocalName);
ReadAttributeText(attributeNode.AttributeText!);
break;
default:
if (_buffered && (BufferReader.Offset - startOffset) > _maxBytesPerRead)
XmlExceptionHelper.ThrowMaxBytesPerReadExceeded(this, _maxBytesPerRead);
ProcessAttributes();
return;
}
}
}
private void ReadText(XmlTextNode textNode, ValueHandleType type, int length)
{
int offset = BufferReader.ReadBytes(length);
textNode.Value.SetValue(type, offset, length);
if (this.OutsideRootElement)
VerifyWhitespace();
}
private void ReadBinaryText(XmlTextNode textNode, int length)
{
ReadText(textNode, ValueHandleType.Base64, length);
}
private void ReadPartialUTF8Text(bool withEndElement, int length)
{
// The maxBytesPerRead includes the quota for the XmlBinaryNodeType.TextNode, so we need
// to account for that.
const int maxTextNodeLength = 5;
int maxLength = Math.Max(_maxBytesPerRead - maxTextNodeLength, 0);
if (length <= maxLength)
{
if (withEndElement)
ReadText(MoveToAtomicTextWithEndElement(), ValueHandleType.UTF8, length);
else
ReadText(MoveToComplexText(), ValueHandleType.UTF8, length);
}
else
{
// We also need to make sure we have enough room to insert a new XmlBinaryNodeType.TextNode
// for the split data.
int actual = Math.Max(maxLength - maxTextNodeLength, 0);
int offset = BufferReader.ReadBytes(actual);
// We need to make sure we don't split a utf8 character, so scan backwards for a
// character boundary. We'll actually always push off at least one character since
// although we find the character boundary, we don't bother to figure out if we have
// all the bytes that comprise the character.
int i;
for (i = offset + actual - 1; i >= offset; i--)
{
byte b = BufferReader.GetByte(i);
// The first byte of UTF8 character sequence has either the high bit off, or the
// two high bits set.
if ((b & 0x80) == 0 || (b & 0xC0) == 0xC0)
break;
}
// Move any split characters so we can insert the node
int byteCount = (offset + actual - i);
// Include the split characters in the count
BufferReader.Offset = BufferReader.Offset - byteCount;
actual -= byteCount;
MoveToComplexText().Value.SetValue(ValueHandleType.UTF8, offset, actual);
if (this.OutsideRootElement)
VerifyWhitespace();
XmlBinaryNodeType nodeType = (withEndElement ? XmlBinaryNodeType.Chars32TextWithEndElement : XmlBinaryNodeType.Chars32Text);
InsertNode(nodeType, length - actual);
}
}
private void ReadUnicodeText(bool withEndElement, int length)
{
if ((length & 1) != 0)
XmlExceptionHelper.ThrowInvalidBinaryFormat(this);
if (_buffered)
{
if (withEndElement)
{
ReadText(MoveToAtomicTextWithEndElement(), ValueHandleType.Unicode, length);
}
else
{
ReadText(MoveToComplexText(), ValueHandleType.Unicode, length);
}
}
else
{
ReadPartialUnicodeText(withEndElement, length);
}
}
private void ReadPartialUnicodeText(bool withEndElement, int length)
{
// The maxBytesPerRead includes the quota for the XmlBinaryNodeType.TextNode, so we need
// to account for that.
const int maxTextNodeLength = 5;
int maxLength = Math.Max(_maxBytesPerRead - maxTextNodeLength, 0);
if (length <= maxLength)
{
if (withEndElement)
ReadText(MoveToAtomicTextWithEndElement(), ValueHandleType.Unicode, length);
else
ReadText(MoveToComplexText(), ValueHandleType.Unicode, length);
}
else
{
// We also need to make sure we have enough room to insert a new XmlBinaryNodeType.TextNode
// for the split data.
int actual = Math.Max(maxLength - maxTextNodeLength, 0);
// Make sure we break on a char boundary
if ((actual & 1) != 0)
actual--;
int offset = BufferReader.ReadBytes(actual);
// We need to make sure we don't split a Unicode surrogate character
int byteCount = 0;
char ch = (char)BufferReader.GetInt16(offset + actual - sizeof(char));
// If the last char is a high surrogate char, then move back
if (ch >= 0xD800 && ch < 0xDC00)
byteCount = sizeof(char);
// Include the split characters in the count
BufferReader.Offset = BufferReader.Offset - byteCount;
actual -= byteCount;
MoveToComplexText().Value.SetValue(ValueHandleType.Unicode, offset, actual);
if (this.OutsideRootElement)
VerifyWhitespace();
XmlBinaryNodeType nodeType = (withEndElement ? XmlBinaryNodeType.UnicodeChars32TextWithEndElement : XmlBinaryNodeType.UnicodeChars32Text);
InsertNode(nodeType, length - actual);
}
}
private void ReadPartialBinaryText(bool withEndElement, int length)
{
const int nodeLength = 5;
int maxBytesPerRead = Math.Max(_maxBytesPerRead - nodeLength, 0);
if (length <= maxBytesPerRead)
{
if (withEndElement)
ReadText(MoveToAtomicTextWithEndElement(), ValueHandleType.Base64, length);
else
ReadText(MoveToComplexText(), ValueHandleType.Base64, length);
}
else
{
int actual = maxBytesPerRead;
if (actual > 3)
actual -= (actual % 3);
ReadText(MoveToComplexText(), ValueHandleType.Base64, actual);
XmlBinaryNodeType nodeType = (withEndElement ? XmlBinaryNodeType.Bytes32TextWithEndElement : XmlBinaryNodeType.Bytes32Text);
InsertNode(nodeType, length - actual);
}
}
private void InsertNode(XmlBinaryNodeType nodeType, int length)
{
byte[] buffer = new byte[5];
buffer[0] = (byte)nodeType;
unchecked
{
buffer[1] = (byte)length;
length >>= 8;
buffer[2] = (byte)length;
length >>= 8;
buffer[3] = (byte)length;
}
length >>= 8;
buffer[4] = (byte)length;
BufferReader.InsertBytes(buffer, 0, buffer.Length);
}
private void ReadAttributeText(XmlAttributeTextNode textNode)
{
XmlBinaryNodeType nodeType = GetNodeType();
SkipNodeType();
BufferReader.ReadValue(nodeType, textNode.Value);
}
private void ReadName(ValueHandle value)
{
int length = ReadMultiByteUInt31();
int offset = BufferReader.ReadBytes(length);
value.SetValue(ValueHandleType.UTF8, offset, length);
}
private void ReadName(StringHandle handle)
{
int length = ReadMultiByteUInt31();
int offset = BufferReader.ReadBytes(length);
handle.SetValue(offset, length);
}
private void ReadName(PrefixHandle prefix)
{
int length = ReadMultiByteUInt31();
int offset = BufferReader.ReadBytes(length);
prefix.SetValue(offset, length);
}
private void ReadDictionaryName(StringHandle s)
{
int key = ReadDictionaryKey();
s.SetValue(key);
}
private XmlBinaryNodeType GetNodeType()
{
return BufferReader.GetNodeType();
}
private void SkipNodeType()
{
BufferReader.SkipNodeType();
}
private int ReadDictionaryKey()
{
return BufferReader.ReadDictionaryKey();
}
private int ReadMultiByteUInt31()
{
return BufferReader.ReadMultiByteUInt31();
}
private int ReadUInt8()
{
return BufferReader.ReadUInt8();
}
private int ReadUInt16()
{
return BufferReader.ReadUInt16();
}
private int ReadUInt31()
{
return BufferReader.ReadUInt31();
}
private static bool IsValidArrayType(XmlBinaryNodeType nodeType)
{
switch (nodeType)
{
case XmlBinaryNodeType.BoolTextWithEndElement:
case XmlBinaryNodeType.Int16TextWithEndElement:
case XmlBinaryNodeType.Int32TextWithEndElement:
case XmlBinaryNodeType.Int64TextWithEndElement:
case XmlBinaryNodeType.FloatTextWithEndElement:
case XmlBinaryNodeType.DoubleTextWithEndElement:
case XmlBinaryNodeType.DecimalTextWithEndElement:
case XmlBinaryNodeType.DateTimeTextWithEndElement:
case XmlBinaryNodeType.TimeSpanTextWithEndElement:
case XmlBinaryNodeType.GuidTextWithEndElement:
return true;
default:
return false;
}
}
private void ReadArray()
{
if (GetNodeType() == XmlBinaryNodeType.Array) // Prevent recursion
XmlExceptionHelper.ThrowInvalidBinaryFormat(this);
ReadNode(); // ReadStartElement
if (this.Node.NodeType != XmlNodeType.Element)
XmlExceptionHelper.ThrowInvalidBinaryFormat(this);
if (GetNodeType() == XmlBinaryNodeType.Array) // Prevent recursion
XmlExceptionHelper.ThrowInvalidBinaryFormat(this);
ReadNode(); // ReadEndElement
if (this.Node.NodeType != XmlNodeType.EndElement)
XmlExceptionHelper.ThrowInvalidBinaryFormat(this);
_arrayState = ArrayState.Element;
_arrayNodeType = GetNodeType();
if (!IsValidArrayType(_arrayNodeType))
XmlExceptionHelper.ThrowInvalidBinaryFormat(this);
SkipNodeType();
_arrayCount = ReadMultiByteUInt31();
if (_arrayCount == 0)
XmlExceptionHelper.ThrowInvalidBinaryFormat(this);
MoveToArrayElement();
}
private void MoveToArrayElement()
{
_arrayState = ArrayState.Element;
MoveToNode(ElementNode);
}
private void SkipArrayElements(int count)
{
_arrayCount -= count;
if (_arrayCount == 0)
{
_arrayState = ArrayState.None;
ExitScope();
ReadNode();
}
}
public override bool IsStartArray([NotNullWhen(true)] out Type? type)
{
type = null;
if (_arrayState != ArrayState.Element)
return false;
switch (_arrayNodeType)
{
case XmlBinaryNodeType.BoolTextWithEndElement:
type = typeof(bool);
break;
case XmlBinaryNodeType.Int16TextWithEndElement:
type = typeof(short);
break;
case XmlBinaryNodeType.Int32TextWithEndElement:
type = typeof(int);
break;
case XmlBinaryNodeType.Int64TextWithEndElement:
type = typeof(long);
break;
case XmlBinaryNodeType.FloatTextWithEndElement:
type = typeof(float);
break;
case XmlBinaryNodeType.DoubleTextWithEndElement:
type = typeof(double);
break;
case XmlBinaryNodeType.DecimalTextWithEndElement:
type = typeof(decimal);
break;
case XmlBinaryNodeType.DateTimeTextWithEndElement:
type = typeof(DateTime);
break;
case XmlBinaryNodeType.GuidTextWithEndElement:
type = typeof(Guid);
break;
case XmlBinaryNodeType.TimeSpanTextWithEndElement:
type = typeof(TimeSpan);
break;
case XmlBinaryNodeType.UniqueIdTextWithEndElement:
type = typeof(UniqueId);
break;
default:
return false;
}
return true;
}
public override bool TryGetArrayLength(out int count)
{
count = 0;
if (!_buffered)
return false;
if (_arrayState != ArrayState.Element)
return false;
count = _arrayCount;
return true;
}
private bool IsStartArray(string localName, string namespaceUri, XmlBinaryNodeType nodeType)
{
return IsStartElement(localName, namespaceUri) && _arrayState == ArrayState.Element && _arrayNodeType == nodeType && !Signing;
}
private bool IsStartArray(XmlDictionaryString localName, XmlDictionaryString namespaceUri, XmlBinaryNodeType nodeType)
{
return IsStartElement(localName, namespaceUri) && _arrayState == ArrayState.Element && _arrayNodeType == nodeType && !Signing;
}
private static void CheckArray(Array array, int offset, int count)
{
ArgumentNullException.ThrowIfNull(array);
ArgumentOutOfRangeException.ThrowIfNegative(offset);
if (offset > array.Length)
throw new ArgumentOutOfRangeException(nameof(offset), SR.Format(SR.OffsetExceedsBufferSize, array.Length));
ArgumentOutOfRangeException.ThrowIfNegative(count);
if (count > array.Length - offset)
throw new ArgumentOutOfRangeException(nameof(count), SR.Format(SR.SizeExceedsRemainingBufferSpace, array.Length - offset));
}
private unsafe int ReadArray(bool[] array, int offset, int count)
{
CheckArray(array, offset, count);
int actual = Math.Min(count, _arrayCount);
BufferReader.ReadRawArrayBytes(array.AsSpan(offset, actual));
SkipArrayElements(actual);
return actual;
}
public override int ReadArray(string localName, string namespaceUri, bool[] array, int offset, int count)
{
if (IsStartArray(localName, namespaceUri, XmlBinaryNodeType.BoolTextWithEndElement))
return ReadArray(array, offset, count);
return base.ReadArray(localName, namespaceUri, array, offset, count);
}
public override int ReadArray(XmlDictionaryString localName, XmlDictionaryString namespaceUri, bool[] array, int offset, int count)
{
if (IsStartArray(localName, namespaceUri, XmlBinaryNodeType.BoolTextWithEndElement))
return ReadArray(array, offset, count);
return base.ReadArray(localName, namespaceUri, array, offset, count);
}
private unsafe int ReadArray(short[] array, int offset, int count)
{
CheckArray(array, offset, count);
int actual = Math.Min(count, _arrayCount);
BufferReader.ReadRawArrayBytes(array.AsSpan(offset, actual));
SkipArrayElements(actual);
return actual;
}
public override int ReadArray(string localName, string namespaceUri, short[] array, int offset, int count)
{
if (BitConverter.IsLittleEndian && IsStartArray(localName, namespaceUri, XmlBinaryNodeType.Int16TextWithEndElement))
return ReadArray(array, offset, count);
return base.ReadArray(localName, namespaceUri, array, offset, count);
}
public override int ReadArray(XmlDictionaryString localName, XmlDictionaryString namespaceUri, short[] array, int offset, int count)
{
if (BitConverter.IsLittleEndian && IsStartArray(localName, namespaceUri, XmlBinaryNodeType.Int16TextWithEndElement))
return ReadArray(array, offset, count);
return base.ReadArray(localName, namespaceUri, array, offset, count);
}
private unsafe int ReadArray(int[] array, int offset, int count)
{
CheckArray(array, offset, count);
int actual = Math.Min(count, _arrayCount);
BufferReader.ReadRawArrayBytes(array.AsSpan(offset, actual));
SkipArrayElements(actual);
return actual;
}
public override int ReadArray(string localName, string namespaceUri, int[] array, int offset, int count)
{
if (BitConverter.IsLittleEndian && IsStartArray(localName, namespaceUri, XmlBinaryNodeType.Int32TextWithEndElement))
return ReadArray(array, offset, count);
return base.ReadArray(localName, namespaceUri, array, offset, count);
}
public override int ReadArray(XmlDictionaryString localName, XmlDictionaryString namespaceUri, int[] array, int offset, int count)
{
if (BitConverter.IsLittleEndian && IsStartArray(localName, namespaceUri, XmlBinaryNodeType.Int32TextWithEndElement))
return ReadArray(array, offset, count);
return base.ReadArray(localName, namespaceUri, array, offset, count);
}
private unsafe int ReadArray(long[] array, int offset, int count)
{
CheckArray(array, offset, count);
int actual = Math.Min(count, _arrayCount);
BufferReader.ReadRawArrayBytes(array.AsSpan(offset, actual));
SkipArrayElements(actual);
return actual;
}
public override int ReadArray(string localName, string namespaceUri, long[] array, int offset, int count)
{
if (BitConverter.IsLittleEndian && IsStartArray(localName, namespaceUri, XmlBinaryNodeType.Int64TextWithEndElement))
return ReadArray(array, offset, count);
return base.ReadArray(localName, namespaceUri, array, offset, count);
}
public override int ReadArray(XmlDictionaryString localName, XmlDictionaryString namespaceUri, long[] array, int offset, int count)
{
if (BitConverter.IsLittleEndian && IsStartArray(localName, namespaceUri, XmlBinaryNodeType.Int64TextWithEndElement))
return ReadArray(array, offset, count);
return base.ReadArray(localName, namespaceUri, array, offset, count);
}
private unsafe int ReadArray(float[] array, int offset, int count)
{
CheckArray(array, offset, count);
int actual = Math.Min(count, _arrayCount);
BufferReader.ReadRawArrayBytes(array.AsSpan(offset, actual));
SkipArrayElements(actual);
return actual;
}
public override int ReadArray(string localName, string namespaceUri, float[] array, int offset, int count)
{
if (BitConverter.IsLittleEndian && IsStartArray(localName, namespaceUri, XmlBinaryNodeType.FloatTextWithEndElement))
return ReadArray(array, offset, count);
return base.ReadArray(localName, namespaceUri, array, offset, count);
}
public override int ReadArray(XmlDictionaryString localName, XmlDictionaryString namespaceUri, float[] array, int offset, int count)
{
if (BitConverter.IsLittleEndian && IsStartArray(localName, namespaceUri, XmlBinaryNodeType.FloatTextWithEndElement))
return ReadArray(array, offset, count);
return base.ReadArray(localName, namespaceUri, array, offset, count);
}
private unsafe int ReadArray(double[] array, int offset, int count)
{
CheckArray(array, offset, count);
int actual = Math.Min(count, _arrayCount);
BufferReader.ReadRawArrayBytes(array.AsSpan(offset, actual));
SkipArrayElements(actual);
return actual;
}
public override int ReadArray(string localName, string namespaceUri, double[] array, int offset, int count)
{
if (BitConverter.IsLittleEndian && IsStartArray(localName, namespaceUri, XmlBinaryNodeType.DoubleTextWithEndElement))
return ReadArray(array, offset, count);
return base.ReadArray(localName, namespaceUri, array, offset, count);
}
public override int ReadArray(XmlDictionaryString localName, XmlDictionaryString namespaceUri, double[] array, int offset, int count)
{
if (BitConverter.IsLittleEndian && IsStartArray(localName, namespaceUri, XmlBinaryNodeType.DoubleTextWithEndElement))
return ReadArray(array, offset, count);
return base.ReadArray(localName, namespaceUri, array, offset, count);
}
private unsafe int ReadArray(decimal[] array, int offset, int count)
{
CheckArray(array, offset, count);
int actual = Math.Min(count, _arrayCount);
BufferReader.ReadRawArrayBytes(array.AsSpan(offset, actual));
SkipArrayElements(actual);
return actual;
}
public override int ReadArray(string localName, string namespaceUri, decimal[] array, int offset, int count)
{
if (BitConverter.IsLittleEndian && IsStartArray(localName, namespaceUri, XmlBinaryNodeType.DecimalTextWithEndElement))
return ReadArray(array, offset, count);
return base.ReadArray(localName, namespaceUri, array, offset, count);
}
public override int ReadArray(XmlDictionaryString localName, XmlDictionaryString namespaceUri, decimal[] array, int offset, int count)
{
if (BitConverter.IsLittleEndian && IsStartArray(localName, namespaceUri, XmlBinaryNodeType.DecimalTextWithEndElement))
return ReadArray(array, offset, count);
return base.ReadArray(localName, namespaceUri, array, offset, count);
}
// DateTime
private int ReadArray(DateTime[] array, int offset, int count)
{
CheckArray(array, offset, count);
int actual = Math.Min(count, _arrayCount);
// Try to read in whole array, but don't fail if not possible
BufferReader.GetBuffer(actual * ValueHandleLength.DateTime, out _, out _);
foreach (ref DateTime item in array.AsSpan(offset, actual))
{
item = BufferReader.ReadDateTime();
}
SkipArrayElements(actual);
return actual;
}
public override int ReadArray(string localName, string namespaceUri, DateTime[] array, int offset, int count)
{
if (IsStartArray(localName, namespaceUri, XmlBinaryNodeType.DateTimeTextWithEndElement))
return ReadArray(array, offset, count);
return base.ReadArray(localName, namespaceUri, array, offset, count);
}
public override int ReadArray(XmlDictionaryString localName, XmlDictionaryString namespaceUri, DateTime[] array, int offset, int count)
{
if (IsStartArray(localName, namespaceUri, XmlBinaryNodeType.DateTimeTextWithEndElement))
return ReadArray(array, offset, count);
return base.ReadArray(localName, namespaceUri, array, offset, count);
}
// Guid
private int ReadArray(Guid[] array, int offset, int count)
{
CheckArray(array, offset, count);
int actual = Math.Min(count, _arrayCount);
if (BitConverter.IsLittleEndian)
{
BufferReader.ReadRawArrayBytes(array.AsSpan(offset, actual));
}
else
{
// Try to read in whole array, but don't fail if not possible
BufferReader.GetBuffer(actual * ValueHandleLength.Guid, out _, out _);
foreach (ref Guid item in array.AsSpan(offset, actual))
{
item = BufferReader.ReadGuid();
}
}
SkipArrayElements(actual);
return actual;
}
public override int ReadArray(string localName, string namespaceUri, Guid[] array, int offset, int count)
{
if (IsStartArray(localName, namespaceUri, XmlBinaryNodeType.GuidTextWithEndElement))
return ReadArray(array, offset, count);
return base.ReadArray(localName, namespaceUri, array, offset, count);
}
public override int ReadArray(XmlDictionaryString localName, XmlDictionaryString namespaceUri, Guid[] array, int offset, int count)
{
if (IsStartArray(localName, namespaceUri, XmlBinaryNodeType.GuidTextWithEndElement))
return ReadArray(array, offset, count);
return base.ReadArray(localName, namespaceUri, array, offset, count);
}
// TimeSpan
private int ReadArray(TimeSpan[] array, int offset, int count)
{
CheckArray(array, offset, count);
int actual = Math.Min(count, _arrayCount);
// Try to read in whole array, but don't fail if not possible
BufferReader.GetBuffer(actual * ValueHandleLength.TimeSpan, out _, out _);
foreach (ref TimeSpan item in array.AsSpan(offset, actual))
{
item = BufferReader.ReadTimeSpan();
}
SkipArrayElements(actual);
return actual;
}
public override int ReadArray(string localName, string namespaceUri, TimeSpan[] array, int offset, int count)
{
if (IsStartArray(localName, namespaceUri, XmlBinaryNodeType.TimeSpanTextWithEndElement))
return ReadArray(array, offset, count);
return base.ReadArray(localName, namespaceUri, array, offset, count);
}
public override int ReadArray(XmlDictionaryString localName, XmlDictionaryString namespaceUri, TimeSpan[] array, int offset, int count)
{
if (IsStartArray(localName, namespaceUri, XmlBinaryNodeType.TimeSpanTextWithEndElement))
return ReadArray(array, offset, count);
return base.ReadArray(localName, namespaceUri, array, offset, count);
}
private enum ArrayState
{
None,
Element,
Content
}
protected override XmlSigningNodeWriter CreateSigningNodeWriter()
{
return new XmlSigningNodeWriter(false);
}
}
}
|