e79aa3c0ed
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
1425 lines
49 KiB
C#
1425 lines
49 KiB
C#
//------------------------------------------------------------
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//------------------------------------------------------------
|
|
namespace System.Xml
|
|
{
|
|
using System;
|
|
using System.Collections;
|
|
using System.Globalization;
|
|
using System.IO;
|
|
using System.Runtime;
|
|
using System.Runtime.Serialization;
|
|
using System.Security;
|
|
using System.Text;
|
|
|
|
class XmlBufferReader
|
|
{
|
|
XmlDictionaryReader reader;
|
|
Stream stream;
|
|
byte[] streamBuffer;
|
|
byte[] buffer;
|
|
int offsetMin;
|
|
int offsetMax;
|
|
IXmlDictionary dictionary;
|
|
XmlBinaryReaderSession session;
|
|
byte[] guid;
|
|
int offset;
|
|
const int maxBytesPerChar = 3;
|
|
char[] chars;
|
|
int windowOffset;
|
|
int windowOffsetMax;
|
|
ValueHandle listValue;
|
|
static byte[] emptyByteArray = new byte[0];
|
|
static XmlBufferReader empty = new XmlBufferReader(emptyByteArray);
|
|
|
|
public XmlBufferReader(XmlDictionaryReader reader)
|
|
{
|
|
this.reader = reader;
|
|
}
|
|
|
|
public XmlBufferReader(byte[] buffer)
|
|
{
|
|
this.reader = null;
|
|
this.buffer = buffer;
|
|
}
|
|
|
|
static public XmlBufferReader Empty
|
|
{
|
|
get
|
|
{
|
|
return empty;
|
|
}
|
|
}
|
|
|
|
public byte[] Buffer
|
|
{
|
|
get
|
|
{
|
|
return buffer;
|
|
}
|
|
}
|
|
|
|
public bool IsStreamed
|
|
{
|
|
get
|
|
{
|
|
return stream != null;
|
|
}
|
|
}
|
|
|
|
public void SetBuffer(Stream stream, IXmlDictionary dictionary, XmlBinaryReaderSession session)
|
|
{
|
|
if (streamBuffer == null)
|
|
{
|
|
streamBuffer = new byte[128];
|
|
}
|
|
SetBuffer(stream, streamBuffer, 0, 0, dictionary, session);
|
|
this.windowOffset = 0;
|
|
this.windowOffsetMax = streamBuffer.Length;
|
|
}
|
|
|
|
public void SetBuffer(byte[] buffer, int offset, int count, IXmlDictionary dictionary, XmlBinaryReaderSession session)
|
|
{
|
|
SetBuffer(null, buffer, offset, count, dictionary, session);
|
|
}
|
|
|
|
void SetBuffer(Stream stream, byte[] buffer, int offset, int count, IXmlDictionary dictionary, XmlBinaryReaderSession session)
|
|
{
|
|
this.stream = stream;
|
|
this.buffer = buffer;
|
|
this.offsetMin = offset;
|
|
this.offset = offset;
|
|
this.offsetMax = offset + count;
|
|
this.dictionary = dictionary;
|
|
this.session = session;
|
|
}
|
|
|
|
public void Close()
|
|
{
|
|
if (streamBuffer != null && streamBuffer.Length > 4096)
|
|
{
|
|
streamBuffer = null;
|
|
}
|
|
if (stream != null)
|
|
{
|
|
stream.Close();
|
|
this.stream = null;
|
|
}
|
|
this.buffer = emptyByteArray;
|
|
this.offset = 0;
|
|
this.offsetMax = 0;
|
|
this.windowOffset = 0;
|
|
this.windowOffsetMax = 0;
|
|
this.dictionary = null;
|
|
this.session = null;
|
|
}
|
|
|
|
public bool EndOfFile
|
|
{
|
|
get
|
|
{
|
|
return offset == offsetMax && !TryEnsureByte();
|
|
}
|
|
}
|
|
|
|
public byte GetByte()
|
|
{
|
|
int offset = this.offset;
|
|
if (offset < offsetMax)
|
|
return buffer[offset];
|
|
else
|
|
return GetByteHard();
|
|
}
|
|
|
|
public void SkipByte()
|
|
{
|
|
Advance(1);
|
|
}
|
|
|
|
byte GetByteHard()
|
|
{
|
|
EnsureByte();
|
|
return buffer[offset];
|
|
}
|
|
|
|
public byte[] GetBuffer(int count, out int offset)
|
|
{
|
|
offset = this.offset;
|
|
if (offset <= this.offsetMax - count)
|
|
return buffer;
|
|
return GetBufferHard(count, out offset);
|
|
}
|
|
|
|
public byte[] GetBuffer(int count, out int offset, out int offsetMax)
|
|
{
|
|
offset = this.offset;
|
|
if (offset <= this.offsetMax - count)
|
|
{
|
|
offsetMax = this.offset + count;
|
|
}
|
|
else
|
|
{
|
|
TryEnsureBytes(Math.Min(count, windowOffsetMax - offset));
|
|
offsetMax = this.offsetMax;
|
|
}
|
|
return buffer;
|
|
}
|
|
|
|
public byte[] GetBuffer(out int offset, out int offsetMax)
|
|
{
|
|
offset = this.offset;
|
|
offsetMax = this.offsetMax;
|
|
return buffer;
|
|
}
|
|
|
|
byte[] GetBufferHard(int count, out int offset)
|
|
{
|
|
offset = this.offset;
|
|
EnsureBytes(count);
|
|
return buffer;
|
|
}
|
|
|
|
void EnsureByte()
|
|
{
|
|
if (!TryEnsureByte())
|
|
XmlExceptionHelper.ThrowUnexpectedEndOfFile(reader);
|
|
}
|
|
|
|
bool TryEnsureByte()
|
|
{
|
|
if (stream == null)
|
|
return false;
|
|
if (offsetMax >= windowOffsetMax)
|
|
XmlExceptionHelper.ThrowMaxBytesPerReadExceeded(reader, windowOffsetMax - windowOffset);
|
|
if (offsetMax >= buffer.Length)
|
|
return TryEnsureBytes(1);
|
|
int b = stream.ReadByte();
|
|
if (b == -1)
|
|
return false;
|
|
buffer[offsetMax++] = (byte)b;
|
|
return true;
|
|
}
|
|
|
|
void EnsureBytes(int count)
|
|
{
|
|
if (!TryEnsureBytes(count))
|
|
XmlExceptionHelper.ThrowUnexpectedEndOfFile(reader);
|
|
}
|
|
|
|
bool TryEnsureBytes(int count)
|
|
{
|
|
if (stream == null)
|
|
return false;
|
|
if (offset > int.MaxValue - count)
|
|
XmlExceptionHelper.ThrowMaxBytesPerReadExceeded(reader, windowOffsetMax - windowOffset);
|
|
int newOffsetMax = offset + count;
|
|
if (newOffsetMax < offsetMax)
|
|
return true;
|
|
if (newOffsetMax > windowOffsetMax)
|
|
XmlExceptionHelper.ThrowMaxBytesPerReadExceeded(reader, windowOffsetMax - windowOffset);
|
|
if (newOffsetMax > buffer.Length)
|
|
{
|
|
byte[] newBuffer = new byte[Math.Max(newOffsetMax, buffer.Length * 2)];
|
|
System.Buffer.BlockCopy(this.buffer, 0, newBuffer, 0, offsetMax);
|
|
buffer = newBuffer;
|
|
streamBuffer = newBuffer;
|
|
}
|
|
int needed = newOffsetMax - offsetMax;
|
|
while (needed > 0)
|
|
{
|
|
int actual = stream.Read(buffer, offsetMax, needed);
|
|
if (actual == 0)
|
|
return false;
|
|
offsetMax += actual;
|
|
needed -= actual;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
#if NO
|
|
void ReadByte(byte b)
|
|
{
|
|
if (BufferReader.GetByte() != b)
|
|
XmlExceptionHelper.ThrowTokenExpected(this, ((char)b).ToString(), (char)BufferReader.GetByte());
|
|
}
|
|
#endif
|
|
public void Advance(int count)
|
|
{
|
|
Fx.Assert(this.offset + count <= offsetMax, "");
|
|
this.offset += count;
|
|
}
|
|
|
|
public void InsertBytes(byte[] buffer, int offset, int count)
|
|
{
|
|
Fx.Assert(stream != null, "");
|
|
if (offsetMax > buffer.Length - count)
|
|
{
|
|
byte[] newBuffer = new byte[offsetMax + count];
|
|
System.Buffer.BlockCopy(this.buffer, 0, newBuffer, 0, this.offsetMax);
|
|
this.buffer = newBuffer;
|
|
this.streamBuffer = newBuffer;
|
|
}
|
|
System.Buffer.BlockCopy(this.buffer, this.offset, this.buffer, this.offset + count, this.offsetMax - this.offset);
|
|
offsetMax += count;
|
|
System.Buffer.BlockCopy(buffer, offset, this.buffer, this.offset, count);
|
|
}
|
|
|
|
public void SetWindow(int windowOffset, int windowLength)
|
|
{
|
|
// [0...elementOffset-1][elementOffset..offset][offset..offsetMax-1][offsetMax..buffer.Length]
|
|
// ^--Elements, Attributes in scope
|
|
// ^-- The node just consumed
|
|
// ^--Data buffered, not consumed
|
|
// ^--Unused space
|
|
if (windowOffset > int.MaxValue - windowLength)
|
|
windowLength = int.MaxValue - windowOffset;
|
|
|
|
if (offset != windowOffset)
|
|
{
|
|
System.Buffer.BlockCopy(buffer, offset, buffer, windowOffset, offsetMax - offset);
|
|
offsetMax = windowOffset + (offsetMax - offset);
|
|
offset = windowOffset;
|
|
}
|
|
this.windowOffset = windowOffset;
|
|
this.windowOffsetMax = Math.Max(windowOffset + windowLength, offsetMax);
|
|
}
|
|
|
|
public int Offset
|
|
{
|
|
get
|
|
{
|
|
return offset;
|
|
}
|
|
set
|
|
{
|
|
Fx.Assert(value >= offsetMin && value <= offsetMax, "");
|
|
this.offset = value;
|
|
}
|
|
}
|
|
|
|
public int ReadBytes(int count)
|
|
{
|
|
Fx.Assert(count >= 0, "");
|
|
int offset = this.offset;
|
|
if (offset > offsetMax - count)
|
|
EnsureBytes(count);
|
|
this.offset += count;
|
|
return offset;
|
|
}
|
|
|
|
public int ReadMultiByteUInt31()
|
|
{
|
|
int i = GetByte();
|
|
Advance(1);
|
|
if ((i & 0x80) == 0)
|
|
return i;
|
|
i &= 0x7F;
|
|
|
|
int j = GetByte();
|
|
Advance(1);
|
|
i |= ((j & 0x7F) << 7);
|
|
if ((j & 0x80) == 0)
|
|
return i;
|
|
|
|
int k = GetByte();
|
|
Advance(1);
|
|
i |= ((k & 0x7F) << 14);
|
|
if ((k & 0x80) == 0)
|
|
return i;
|
|
|
|
int l = GetByte();
|
|
Advance(1);
|
|
i |= ((l & 0x7F) << 21);
|
|
if ((l & 0x80) == 0)
|
|
return i;
|
|
|
|
int m = GetByte();
|
|
Advance(1);
|
|
i |= (m << 28);
|
|
if ((m & 0xF8) != 0)
|
|
XmlExceptionHelper.ThrowInvalidBinaryFormat(reader);
|
|
|
|
return i;
|
|
}
|
|
|
|
public int ReadUInt8()
|
|
{
|
|
byte b = GetByte();
|
|
Advance(1);
|
|
return b;
|
|
}
|
|
|
|
public int ReadInt8()
|
|
{
|
|
return (sbyte)ReadUInt8();
|
|
}
|
|
|
|
public int ReadUInt16()
|
|
{
|
|
int offset;
|
|
byte[] buffer = GetBuffer(2, out offset);
|
|
int i = buffer[offset + 0] + (buffer[offset + 1] << 8);
|
|
Advance(2);
|
|
return i;
|
|
}
|
|
|
|
public int ReadInt16()
|
|
{
|
|
return (Int16)ReadUInt16();
|
|
}
|
|
|
|
public int ReadInt32()
|
|
{
|
|
int offset;
|
|
byte[] buffer = GetBuffer(4, out offset);
|
|
byte b1 = buffer[offset + 0];
|
|
byte b2 = buffer[offset + 1];
|
|
byte b3 = buffer[offset + 2];
|
|
byte b4 = buffer[offset + 3];
|
|
Advance(4);
|
|
return (((((b4 << 8) + b3) << 8) + b2) << 8) + b1;
|
|
}
|
|
|
|
public int ReadUInt31()
|
|
{
|
|
int i = ReadInt32();
|
|
if (i < 0)
|
|
XmlExceptionHelper.ThrowInvalidBinaryFormat(reader);
|
|
return i;
|
|
}
|
|
|
|
public long ReadInt64()
|
|
{
|
|
Int64 lo = (UInt32)ReadInt32();
|
|
Int64 hi = (UInt32)ReadInt32();
|
|
return (hi << 32) + lo;
|
|
}
|
|
|
|
[Fx.Tag.SecurityNote(Critical = "Contains unsafe code.",
|
|
Safe = "Unsafe code is effectively encapsulated, all inputs are validated.")]
|
|
[SecuritySafeCritical]
|
|
unsafe public float ReadSingle()
|
|
{
|
|
int offset;
|
|
byte[] buffer = GetBuffer(ValueHandleLength.Single, out offset);
|
|
float value;
|
|
byte* pb = (byte*)&value;
|
|
Fx.Assert(sizeof(float) == 4, "");
|
|
pb[0] = buffer[offset + 0];
|
|
pb[1] = buffer[offset + 1];
|
|
pb[2] = buffer[offset + 2];
|
|
pb[3] = buffer[offset + 3];
|
|
Advance(ValueHandleLength.Single);
|
|
return value;
|
|
}
|
|
|
|
[Fx.Tag.SecurityNote(Critical = "Contains unsafe code.",
|
|
Safe = "Unsafe code is effectively encapsulated, all inputs are validated.")]
|
|
[SecuritySafeCritical]
|
|
unsafe public double ReadDouble()
|
|
{
|
|
int offset;
|
|
byte[] buffer = GetBuffer(ValueHandleLength.Double, out offset);
|
|
double value;
|
|
byte* pb = (byte*)&value;
|
|
Fx.Assert(sizeof(double) == 8, "");
|
|
pb[0] = buffer[offset + 0];
|
|
pb[1] = buffer[offset + 1];
|
|
pb[2] = buffer[offset + 2];
|
|
pb[3] = buffer[offset + 3];
|
|
pb[4] = buffer[offset + 4];
|
|
pb[5] = buffer[offset + 5];
|
|
pb[6] = buffer[offset + 6];
|
|
pb[7] = buffer[offset + 7];
|
|
Advance(ValueHandleLength.Double);
|
|
return value;
|
|
}
|
|
|
|
[Fx.Tag.SecurityNote(Critical = "Contains unsafe code.",
|
|
Safe = "Unsafe code is effectively encapsulated, all inputs are validated.")]
|
|
[SecuritySafeCritical]
|
|
unsafe public decimal ReadDecimal()
|
|
{
|
|
const int SignMask = unchecked((int)0x80000000);
|
|
const int ScaleMask = 0x00FF0000;
|
|
|
|
int offset;
|
|
byte[] buffer = GetBuffer(ValueHandleLength.Decimal, out offset);
|
|
byte b1 = buffer[offset + 0];
|
|
byte b2 = buffer[offset + 1];
|
|
byte b3 = buffer[offset + 2];
|
|
byte b4 = buffer[offset + 3];
|
|
int flags = (((((b4 << 8) + b3) << 8) + b2) << 8) + b1;
|
|
|
|
//this logic mirrors the code in Decimal(int []) ctor.
|
|
if ((flags & ~(SignMask | ScaleMask)) == 0 && (flags & ScaleMask) <= (28 << 16))
|
|
{
|
|
decimal value;
|
|
byte* pb = (byte*)&value;
|
|
for (int i = 0; i < sizeof(decimal); i++)
|
|
pb[i] = buffer[offset + i];
|
|
|
|
Advance(ValueHandleLength.Decimal);
|
|
return value;
|
|
}
|
|
else
|
|
{
|
|
XmlExceptionHelper.ThrowInvalidBinaryFormat(this.reader);
|
|
}
|
|
|
|
//compiler doesn't know that XmlExceptionHelper.ThrowInvalidBinaryFormat always throws,
|
|
//so we have to have a return statement here even though we shouldn't hit this code path...
|
|
Fx.Assert("A decimal value should have been returned or an exception should have been thrown.");
|
|
return default(decimal);
|
|
}
|
|
|
|
public UniqueId ReadUniqueId()
|
|
{
|
|
int offset;
|
|
byte[] buffer = GetBuffer(ValueHandleLength.UniqueId, out offset);
|
|
UniqueId uniqueId = new UniqueId(buffer, offset);
|
|
Advance(ValueHandleLength.UniqueId);
|
|
return uniqueId;
|
|
}
|
|
|
|
public DateTime ReadDateTime()
|
|
{
|
|
long value = 0;
|
|
try
|
|
{
|
|
value = ReadInt64();
|
|
return DateTime.FromBinary(value);
|
|
}
|
|
catch (ArgumentException exception)
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value.ToString(CultureInfo.InvariantCulture), "DateTime", exception));
|
|
}
|
|
catch (FormatException exception)
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value.ToString(CultureInfo.InvariantCulture), "DateTime", exception));
|
|
}
|
|
catch (OverflowException exception)
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value.ToString(CultureInfo.InvariantCulture), "DateTime", exception));
|
|
}
|
|
}
|
|
|
|
public TimeSpan ReadTimeSpan()
|
|
{
|
|
long value = 0;
|
|
try
|
|
{
|
|
value = ReadInt64();
|
|
return TimeSpan.FromTicks(value);
|
|
}
|
|
catch (ArgumentException exception)
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value.ToString(CultureInfo.InvariantCulture), "TimeSpan", exception));
|
|
}
|
|
catch (FormatException exception)
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value.ToString(CultureInfo.InvariantCulture), "TimeSpan", exception));
|
|
}
|
|
catch (OverflowException exception)
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value.ToString(CultureInfo.InvariantCulture), "TimeSpan", exception));
|
|
}
|
|
}
|
|
|
|
public Guid ReadGuid()
|
|
{
|
|
int offset;
|
|
byte[] buffer = GetBuffer(ValueHandleLength.Guid, out offset);
|
|
Guid guid = GetGuid(offset);
|
|
Advance(ValueHandleLength.Guid);
|
|
return guid;
|
|
}
|
|
|
|
public string ReadUTF8String(int length)
|
|
{
|
|
int offset;
|
|
byte[] buffer = GetBuffer(length, out offset);
|
|
char[] chars = GetCharBuffer(length);
|
|
int charCount = GetChars(offset, length, chars);
|
|
string value = new string(chars, 0, charCount);
|
|
Advance(length);
|
|
return value;
|
|
}
|
|
|
|
[Fx.Tag.SecurityNote(Critical = "Contains unsafe code. Caller needs to validate arguments.")]
|
|
[SecurityCritical]
|
|
unsafe public void UnsafeReadArray(byte* dst, byte* dstMax)
|
|
{
|
|
UnsafeReadArray(dst, (int)(dstMax - dst));
|
|
}
|
|
|
|
[Fx.Tag.SecurityNote(Critical = "Contains unsafe code. Caller needs to validate arguments.")]
|
|
[SecurityCritical]
|
|
unsafe void UnsafeReadArray(byte* dst, int length)
|
|
{
|
|
if (stream != null)
|
|
{
|
|
const int chunk = 256;
|
|
while (length >= chunk)
|
|
{
|
|
byte[] _buffer = GetBuffer(chunk, out offset);
|
|
for (int i = 0; i < chunk; i++)
|
|
{
|
|
*dst++ = _buffer[offset + i];
|
|
}
|
|
Advance(chunk);
|
|
length -= chunk;
|
|
}
|
|
}
|
|
|
|
if (length > 0)
|
|
{
|
|
byte[] buffer = GetBuffer(length, out offset);
|
|
fixed (byte* _src = &buffer[offset])
|
|
{
|
|
byte* src = _src;
|
|
byte* dstMax = dst + length;
|
|
while (dst < dstMax)
|
|
{
|
|
*dst = *src;
|
|
dst++;
|
|
src++;
|
|
}
|
|
}
|
|
Advance(length);
|
|
}
|
|
}
|
|
|
|
char[] GetCharBuffer(int count)
|
|
{
|
|
if (count > 1024)
|
|
return new char[count];
|
|
if (chars == null || chars.Length < count)
|
|
chars = new char[count];
|
|
return chars;
|
|
}
|
|
|
|
int GetChars(int offset, int length, char[] chars)
|
|
{
|
|
byte[] buffer = this.buffer;
|
|
for (int i = 0; i < length; i++)
|
|
{
|
|
byte b = buffer[offset + i];
|
|
if (b >= 0x80)
|
|
return i + XmlConverter.ToChars(buffer, offset + i, length - i, chars, i);
|
|
chars[i] = (char)b;
|
|
}
|
|
return length;
|
|
}
|
|
|
|
int GetChars(int offset, int length, char[] chars, int charOffset)
|
|
{
|
|
byte[] buffer = this.buffer;
|
|
for (int i = 0; i < length; i++)
|
|
{
|
|
byte b = buffer[offset + i];
|
|
if (b >= 0x80)
|
|
return i + XmlConverter.ToChars(buffer, offset + i, length - i, chars, charOffset + i);
|
|
chars[charOffset + i] = (char)b;
|
|
}
|
|
return length;
|
|
}
|
|
|
|
public string GetString(int offset, int length)
|
|
{
|
|
char[] chars = GetCharBuffer(length);
|
|
int charCount = GetChars(offset, length, chars);
|
|
return new string(chars, 0, charCount);
|
|
}
|
|
|
|
public string GetUnicodeString(int offset, int length)
|
|
{
|
|
return XmlConverter.ToStringUnicode(buffer, offset, length);
|
|
}
|
|
|
|
public string GetString(int offset, int length, XmlNameTable nameTable)
|
|
{
|
|
char[] chars = GetCharBuffer(length);
|
|
int charCount = GetChars(offset, length, chars);
|
|
return nameTable.Add(chars, 0, charCount);
|
|
}
|
|
|
|
public int GetEscapedChars(int offset, int length, char[] chars)
|
|
{
|
|
byte[] buffer = this.buffer;
|
|
int charCount = 0;
|
|
int textOffset = offset;
|
|
int offsetMax = offset + length;
|
|
while (true)
|
|
{
|
|
while (offset < offsetMax && IsAttrChar(buffer[offset]))
|
|
offset++;
|
|
charCount += GetChars(textOffset, offset - textOffset, chars, charCount);
|
|
if (offset == offsetMax)
|
|
break;
|
|
textOffset = offset;
|
|
if (buffer[offset] == '&')
|
|
{
|
|
while (offset < offsetMax && buffer[offset] != ';')
|
|
offset++;
|
|
offset++;
|
|
int ch = GetCharEntity(textOffset, offset - textOffset);
|
|
textOffset = offset;
|
|
if (ch > char.MaxValue)
|
|
{
|
|
SurrogateChar surrogate = new SurrogateChar(ch);
|
|
chars[charCount++] = surrogate.HighChar;
|
|
chars[charCount++] = surrogate.LowChar;
|
|
}
|
|
else
|
|
{
|
|
chars[charCount++] = (char)ch;
|
|
}
|
|
}
|
|
else if (buffer[offset] == '\n' || buffer[offset] == '\t')
|
|
{
|
|
chars[charCount++] = ' ';
|
|
offset++;
|
|
textOffset = offset;
|
|
}
|
|
else // '\r'
|
|
{
|
|
chars[charCount++] = ' ';
|
|
offset++;
|
|
|
|
if (offset < offsetMax && buffer[offset] == '\n')
|
|
offset++;
|
|
|
|
textOffset = offset;
|
|
}
|
|
|
|
}
|
|
return charCount;
|
|
}
|
|
|
|
bool IsAttrChar(int ch)
|
|
{
|
|
switch (ch)
|
|
{
|
|
case '&':
|
|
case '\r':
|
|
case '\t':
|
|
case '\n':
|
|
return false;
|
|
|
|
default:
|
|
return true;
|
|
}
|
|
}
|
|
|
|
public string GetEscapedString(int offset, int length)
|
|
{
|
|
char[] chars = GetCharBuffer(length);
|
|
int charCount = GetEscapedChars(offset, length, chars);
|
|
return new string(chars, 0, charCount);
|
|
}
|
|
|
|
public string GetEscapedString(int offset, int length, XmlNameTable nameTable)
|
|
{
|
|
char[] chars = GetCharBuffer(length);
|
|
int charCount = GetEscapedChars(offset, length, chars);
|
|
return nameTable.Add(chars, 0, charCount);
|
|
}
|
|
|
|
int GetLessThanCharEntity(int offset, int length)
|
|
{
|
|
byte[] buffer = this.buffer;
|
|
if (length != 4 ||
|
|
buffer[offset + 1] != (byte)'l' ||
|
|
buffer[offset + 2] != (byte)'t')
|
|
{
|
|
XmlExceptionHelper.ThrowInvalidCharRef(reader);
|
|
}
|
|
return (int)'<';
|
|
}
|
|
|
|
int GetGreaterThanCharEntity(int offset, int length)
|
|
{
|
|
byte[] buffer = this.buffer;
|
|
if (length != 4 ||
|
|
buffer[offset + 1] != (byte)'g' ||
|
|
buffer[offset + 2] != (byte)'t')
|
|
{
|
|
XmlExceptionHelper.ThrowInvalidCharRef(reader);
|
|
}
|
|
return (int)'>';
|
|
}
|
|
|
|
int GetQuoteCharEntity(int offset, int length)
|
|
{
|
|
byte[] buffer = this.buffer;
|
|
if (length != 6 ||
|
|
buffer[offset + 1] != (byte)'q' ||
|
|
buffer[offset + 2] != (byte)'u' ||
|
|
buffer[offset + 3] != (byte)'o' ||
|
|
buffer[offset + 4] != (byte)'t')
|
|
{
|
|
XmlExceptionHelper.ThrowInvalidCharRef(reader);
|
|
}
|
|
return (int)'"';
|
|
}
|
|
|
|
int GetAmpersandCharEntity(int offset, int length)
|
|
{
|
|
byte[] buffer = this.buffer;
|
|
if (length != 5 ||
|
|
buffer[offset + 1] != (byte)'a' ||
|
|
buffer[offset + 2] != (byte)'m' ||
|
|
buffer[offset + 3] != (byte)'p')
|
|
{
|
|
XmlExceptionHelper.ThrowInvalidCharRef(reader);
|
|
}
|
|
return (int)'&';
|
|
}
|
|
|
|
int GetApostropheCharEntity(int offset, int length)
|
|
{
|
|
byte[] buffer = this.buffer;
|
|
if (length != 6 ||
|
|
buffer[offset + 1] != (byte)'a' ||
|
|
buffer[offset + 2] != (byte)'p' ||
|
|
buffer[offset + 3] != (byte)'o' ||
|
|
buffer[offset + 4] != (byte)'s')
|
|
{
|
|
XmlExceptionHelper.ThrowInvalidCharRef(reader);
|
|
}
|
|
return (int)'\'';
|
|
}
|
|
|
|
int GetDecimalCharEntity(int offset, int length)
|
|
{
|
|
byte[] buffer = this.buffer;
|
|
Fx.Assert(buffer[offset + 0] == '&', "");
|
|
Fx.Assert(buffer[offset + 1] == '#', "");
|
|
Fx.Assert(buffer[offset + length - 1] == ';', "");
|
|
int value = 0;
|
|
for (int i = 2; i < length - 1; i++)
|
|
{
|
|
byte ch = buffer[offset + i];
|
|
if (ch < (byte)'0' || ch > (byte)'9')
|
|
XmlExceptionHelper.ThrowInvalidCharRef(reader);
|
|
value = value * 10 + (ch - '0');
|
|
if (value > SurrogateChar.MaxValue)
|
|
XmlExceptionHelper.ThrowInvalidCharRef(reader);
|
|
}
|
|
return value;
|
|
}
|
|
|
|
int GetHexCharEntity(int offset, int length)
|
|
{
|
|
byte[] buffer = this.buffer;
|
|
Fx.Assert(buffer[offset + 0] == '&', "");
|
|
Fx.Assert(buffer[offset + 1] == '#', "");
|
|
Fx.Assert(buffer[offset + 2] == 'x', "");
|
|
Fx.Assert(buffer[offset + length - 1] == ';', "");
|
|
int value = 0;
|
|
for (int i = 3; i < length - 1; i++)
|
|
{
|
|
byte ch = buffer[offset + i];
|
|
int digit = 0;
|
|
if (ch >= '0' && ch <= '9')
|
|
digit = (ch - '0');
|
|
else if (ch >= 'a' && ch <= 'f')
|
|
digit = 10 + (ch - 'a');
|
|
else if (ch >= 'A' && ch <= 'F')
|
|
digit = 10 + (ch - 'A');
|
|
else
|
|
XmlExceptionHelper.ThrowInvalidCharRef(reader);
|
|
Fx.Assert(digit >= 0 && digit < 16, "");
|
|
value = value * 16 + digit;
|
|
if (value > SurrogateChar.MaxValue)
|
|
XmlExceptionHelper.ThrowInvalidCharRef(reader);
|
|
}
|
|
return value;
|
|
}
|
|
|
|
public int GetCharEntity(int offset, int length)
|
|
{
|
|
if (length < 3)
|
|
XmlExceptionHelper.ThrowInvalidCharRef(reader);
|
|
byte[] buffer = this.buffer;
|
|
Fx.Assert(buffer[offset] == '&', "");
|
|
Fx.Assert(buffer[offset + length - 1] == ';', "");
|
|
switch (buffer[offset + 1])
|
|
{
|
|
case (byte)'l':
|
|
return GetLessThanCharEntity(offset, length);
|
|
case (byte)'g':
|
|
return GetGreaterThanCharEntity(offset, length);
|
|
case (byte)'a':
|
|
if (buffer[offset + 2] == (byte)'m')
|
|
return GetAmpersandCharEntity(offset, length);
|
|
else
|
|
return GetApostropheCharEntity(offset, length);
|
|
case (byte)'q':
|
|
return GetQuoteCharEntity(offset, length);
|
|
case (byte)'#':
|
|
if (buffer[offset + 2] == (byte)'x')
|
|
return GetHexCharEntity(offset, length);
|
|
else
|
|
return GetDecimalCharEntity(offset, length);
|
|
default:
|
|
XmlExceptionHelper.ThrowInvalidCharRef(reader);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
public bool IsWhitespaceKey(int key)
|
|
{
|
|
string s = GetDictionaryString(key).Value;
|
|
for (int i = 0; i < s.Length; i++)
|
|
{
|
|
if (!XmlConverter.IsWhitespace(s[i]))
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public bool IsWhitespaceUTF8(int offset, int length)
|
|
{
|
|
byte[] buffer = this.buffer;
|
|
for (int i = 0; i < length; i++)
|
|
{
|
|
if (!XmlConverter.IsWhitespace((char)buffer[offset + i]))
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public bool IsWhitespaceUnicode(int offset, int length)
|
|
{
|
|
byte[] buffer = this.buffer;
|
|
for (int i = 0; i < length; i += sizeof(char))
|
|
{
|
|
char ch = (char)GetInt16(offset + i);
|
|
if (!XmlConverter.IsWhitespace(ch))
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public bool Equals2(int key1, int key2, XmlBufferReader bufferReader2)
|
|
{
|
|
// If the keys aren't from the same dictionary, they still might be the same
|
|
if (key1 == key2)
|
|
return true;
|
|
else
|
|
return GetDictionaryString(key1).Value == bufferReader2.GetDictionaryString(key2).Value;
|
|
}
|
|
|
|
public bool Equals2(int key1, XmlDictionaryString xmlString2)
|
|
{
|
|
if ((key1 & 1) == 0 && xmlString2.Dictionary == dictionary)
|
|
return xmlString2.Key == (key1 >> 1);
|
|
else
|
|
return GetDictionaryString(key1).Value == xmlString2.Value;
|
|
}
|
|
|
|
public bool Equals2(int offset1, int length1, byte[] buffer2)
|
|
{
|
|
int length2 = buffer2.Length;
|
|
if (length1 != length2)
|
|
return false;
|
|
byte[] buffer1 = this.buffer;
|
|
for (int i = 0; i < length1; i++)
|
|
{
|
|
if (buffer1[offset1 + i] != buffer2[i])
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public bool Equals2(int offset1, int length1, XmlBufferReader bufferReader2, int offset2, int length2)
|
|
{
|
|
if (length1 != length2)
|
|
return false;
|
|
byte[] buffer1 = this.buffer;
|
|
byte[] buffer2 = bufferReader2.buffer;
|
|
for (int i = 0; i < length1; i++)
|
|
{
|
|
if (buffer1[offset1 + i] != buffer2[offset2 + i])
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public bool Equals2(int offset1, int length1, int offset2, int length2)
|
|
{
|
|
if (length1 != length2)
|
|
return false;
|
|
if (offset1 == offset2)
|
|
return true;
|
|
byte[] buffer = this.buffer;
|
|
for (int i = 0; i < length1; i++)
|
|
{
|
|
if (buffer[offset1 + i] != buffer[offset2 + i])
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
[Fx.Tag.SecurityNote(Critical = "Contains unsafe code.",
|
|
Safe = "Unsafe code is effectively encapsulated, all inputs are validated.")]
|
|
[SecuritySafeCritical]
|
|
unsafe public bool Equals2(int offset1, int length1, string s2)
|
|
{
|
|
int byteLength = length1;
|
|
int charLength = s2.Length;
|
|
|
|
// N unicode chars will be represented in at least N bytes, but
|
|
// no more than N * 3 bytes. If the byte count falls outside of this
|
|
// range, then the strings cannot be equal.
|
|
if (byteLength < charLength || byteLength > charLength * maxBytesPerChar)
|
|
return false;
|
|
|
|
byte[] buffer = this.buffer;
|
|
if (length1 < 8)
|
|
{
|
|
int length = Math.Min(byteLength, charLength);
|
|
int offset = offset1;
|
|
for (int i = 0; i < length; i++)
|
|
{
|
|
byte b = buffer[offset + i];
|
|
if (b >= 0x80)
|
|
return XmlConverter.ToString(buffer, offset1, length1) == s2;
|
|
if (s2[i] != (char)b)
|
|
return false;
|
|
}
|
|
return byteLength == charLength;
|
|
}
|
|
else
|
|
{
|
|
int length = Math.Min(byteLength, charLength);
|
|
fixed (byte* _pb = &buffer[offset1])
|
|
{
|
|
byte* pb = _pb;
|
|
byte* pbMax = pb + length;
|
|
fixed (char* _pch = s2)
|
|
{
|
|
char* pch = _pch;
|
|
// Try to do the fast comparison in ascii space
|
|
int t = 0;
|
|
while (pb < pbMax && *pb < 0x80)
|
|
{
|
|
t = *pb - (byte)(*pch);
|
|
// The code generated is better if we break out then return
|
|
if (t != 0)
|
|
break;
|
|
pb++;
|
|
pch++;
|
|
}
|
|
if (t != 0)
|
|
return false;
|
|
if (pb == pbMax)
|
|
return (byteLength == charLength);
|
|
}
|
|
}
|
|
return XmlConverter.ToString(buffer, offset1, length1) == s2;
|
|
}
|
|
}
|
|
|
|
public int Compare(int offset1, int length1, int offset2, int length2)
|
|
{
|
|
byte[] buffer = this.buffer;
|
|
int length = Math.Min(length1, length2);
|
|
for (int i = 0; i < length; i++)
|
|
{
|
|
int s = buffer[offset1 + i] - buffer[offset2 + i];
|
|
if (s != 0)
|
|
return s;
|
|
}
|
|
return length1 - length2;
|
|
}
|
|
|
|
public byte GetByte(int offset)
|
|
{
|
|
return buffer[offset];
|
|
}
|
|
|
|
public int GetInt8(int offset)
|
|
{
|
|
return (sbyte)GetByte(offset);
|
|
}
|
|
|
|
public int GetInt16(int offset)
|
|
{
|
|
byte[] buffer = this.buffer;
|
|
return (Int16)(buffer[offset] + (buffer[offset + 1] << 8));
|
|
}
|
|
|
|
public int GetInt32(int offset)
|
|
{
|
|
byte[] buffer = this.buffer;
|
|
byte b1 = buffer[offset + 0];
|
|
byte b2 = buffer[offset + 1];
|
|
byte b3 = buffer[offset + 2];
|
|
byte b4 = buffer[offset + 3];
|
|
return (((((b4 << 8) + b3) << 8) + b2) << 8) + b1;
|
|
}
|
|
|
|
public long GetInt64(int offset)
|
|
{
|
|
byte[] buffer = this.buffer;
|
|
byte b1, b2, b3, b4;
|
|
b1 = buffer[offset + 0];
|
|
b2 = buffer[offset + 1];
|
|
b3 = buffer[offset + 2];
|
|
b4 = buffer[offset + 3];
|
|
Int64 lo = (UInt32)(((((b4 << 8) + b3) << 8) + b2) << 8) + b1;
|
|
b1 = buffer[offset + 4];
|
|
b2 = buffer[offset + 5];
|
|
b3 = buffer[offset + 6];
|
|
b4 = buffer[offset + 7];
|
|
Int64 hi = (UInt32)(((((b4 << 8) + b3) << 8) + b2) << 8) + b1;
|
|
return (hi << 32) + lo;
|
|
}
|
|
|
|
public ulong GetUInt64(int offset)
|
|
{
|
|
return (ulong)GetInt64(offset);
|
|
}
|
|
|
|
[Fx.Tag.SecurityNote(Critical = "Contains unsafe code.",
|
|
Safe = "Unsafe code is effectively encapsulated, all inputs are validated.")]
|
|
[SecuritySafeCritical]
|
|
unsafe public float GetSingle(int offset)
|
|
{
|
|
byte[] buffer = this.buffer;
|
|
float value;
|
|
byte* pb = (byte*)&value;
|
|
Fx.Assert(sizeof(float) == 4, "");
|
|
pb[0] = buffer[offset + 0];
|
|
pb[1] = buffer[offset + 1];
|
|
pb[2] = buffer[offset + 2];
|
|
pb[3] = buffer[offset + 3];
|
|
return value;
|
|
}
|
|
|
|
[Fx.Tag.SecurityNote(Critical = "Contains unsafe code.",
|
|
Safe = "Unsafe code is effectively encapsulated, all inputs are validated.")]
|
|
[SecuritySafeCritical]
|
|
unsafe public double GetDouble(int offset)
|
|
{
|
|
byte[] buffer = this.buffer;
|
|
double value;
|
|
byte* pb = (byte*)&value;
|
|
Fx.Assert(sizeof(double) == 8, "");
|
|
pb[0] = buffer[offset + 0];
|
|
pb[1] = buffer[offset + 1];
|
|
pb[2] = buffer[offset + 2];
|
|
pb[3] = buffer[offset + 3];
|
|
pb[4] = buffer[offset + 4];
|
|
pb[5] = buffer[offset + 5];
|
|
pb[6] = buffer[offset + 6];
|
|
pb[7] = buffer[offset + 7];
|
|
return value;
|
|
}
|
|
|
|
[Fx.Tag.SecurityNote(Critical = "Contains unsafe code.",
|
|
Safe = "Unsafe code is effectively encapsulated, all inputs are validated.")]
|
|
[SecuritySafeCritical]
|
|
public unsafe decimal GetDecimal(int offset)
|
|
{
|
|
const int SignMask = unchecked((int)0x80000000);
|
|
const int ScaleMask = 0x00FF0000;
|
|
|
|
byte[] buffer = this.buffer;
|
|
byte b1 = buffer[offset + 0];
|
|
byte b2 = buffer[offset + 1];
|
|
byte b3 = buffer[offset + 2];
|
|
byte b4 = buffer[offset + 3];
|
|
int flags = (((((b4 << 8) + b3) << 8) + b2) << 8) + b1;
|
|
|
|
//this logic mirrors the code in Decimal(int []) ctor.
|
|
if ((flags & ~(SignMask | ScaleMask)) == 0 && (flags & ScaleMask) <= (28 << 16))
|
|
{
|
|
decimal value;
|
|
byte* pb = (byte*)&value;
|
|
for (int i = 0; i < sizeof(decimal); i++)
|
|
pb[i] = buffer[offset + i];
|
|
return value;
|
|
}
|
|
else
|
|
{
|
|
XmlExceptionHelper.ThrowInvalidBinaryFormat(this.reader);
|
|
}
|
|
|
|
//compiler doesn't know that XmlExceptionHelper.ThrowInvalidBinaryFormat always throws,
|
|
//so we have to have a return statement here even though we shouldn't hit this code path...
|
|
Fx.Assert("A decimal value should have been returned or an exception should have been thrown.");
|
|
return default(decimal);
|
|
}
|
|
|
|
public UniqueId GetUniqueId(int offset)
|
|
{
|
|
return new UniqueId(this.buffer, offset);
|
|
}
|
|
|
|
public Guid GetGuid(int offset)
|
|
{
|
|
if (guid == null)
|
|
guid = new byte[16];
|
|
System.Buffer.BlockCopy(buffer, offset, guid, 0, guid.Length);
|
|
return new Guid(guid);
|
|
}
|
|
|
|
public void GetBase64(int srcOffset, byte[] buffer, int dstOffset, int count)
|
|
{
|
|
System.Buffer.BlockCopy(this.buffer, srcOffset, buffer, dstOffset, count);
|
|
}
|
|
|
|
public XmlBinaryNodeType GetNodeType()
|
|
{
|
|
return (XmlBinaryNodeType)GetByte();
|
|
}
|
|
|
|
public void SkipNodeType()
|
|
{
|
|
SkipByte();
|
|
}
|
|
|
|
public object[] GetList(int offset, int count)
|
|
{
|
|
int bufferOffset = this.Offset;
|
|
this.Offset = offset;
|
|
try
|
|
{
|
|
object[] objects = new object[count];
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
XmlBinaryNodeType nodeType = GetNodeType();
|
|
SkipNodeType();
|
|
Fx.Assert(nodeType != XmlBinaryNodeType.StartListText, "");
|
|
ReadValue(nodeType, listValue);
|
|
objects[i] = listValue.ToObject();
|
|
}
|
|
return objects;
|
|
}
|
|
finally
|
|
{
|
|
this.Offset = bufferOffset;
|
|
}
|
|
}
|
|
|
|
public XmlDictionaryString GetDictionaryString(int key)
|
|
{
|
|
IXmlDictionary keyDictionary;
|
|
if ((key & 1) != 0)
|
|
{
|
|
keyDictionary = session;
|
|
}
|
|
else
|
|
{
|
|
keyDictionary = dictionary;
|
|
}
|
|
XmlDictionaryString s;
|
|
if (!keyDictionary.TryLookup(key >> 1, out s))
|
|
XmlExceptionHelper.ThrowInvalidBinaryFormat(reader);
|
|
return s;
|
|
}
|
|
|
|
public int ReadDictionaryKey()
|
|
{
|
|
int key = ReadMultiByteUInt31();
|
|
if ((key & 1) != 0)
|
|
{
|
|
if (session == null)
|
|
XmlExceptionHelper.ThrowInvalidBinaryFormat(reader);
|
|
int sessionKey = (key >> 1);
|
|
XmlDictionaryString xmlString;
|
|
if (!session.TryLookup(sessionKey, out xmlString))
|
|
{
|
|
if (sessionKey < XmlDictionaryString.MinKey || sessionKey > XmlDictionaryString.MaxKey)
|
|
XmlExceptionHelper.ThrowXmlDictionaryStringIDOutOfRange(this.reader);
|
|
XmlExceptionHelper.ThrowXmlDictionaryStringIDUndefinedSession(this.reader, sessionKey);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (dictionary == null)
|
|
XmlExceptionHelper.ThrowInvalidBinaryFormat(reader);
|
|
int staticKey = (key >> 1);
|
|
XmlDictionaryString xmlString;
|
|
if (!dictionary.TryLookup(staticKey, out xmlString))
|
|
{
|
|
if (staticKey < XmlDictionaryString.MinKey || staticKey > XmlDictionaryString.MaxKey)
|
|
XmlExceptionHelper.ThrowXmlDictionaryStringIDOutOfRange(this.reader);
|
|
XmlExceptionHelper.ThrowXmlDictionaryStringIDUndefinedStatic(this.reader, staticKey);
|
|
}
|
|
}
|
|
|
|
return key;
|
|
}
|
|
|
|
public void ReadValue(XmlBinaryNodeType nodeType, ValueHandle value)
|
|
{
|
|
switch (nodeType)
|
|
{
|
|
case XmlBinaryNodeType.EmptyText:
|
|
value.SetValue(ValueHandleType.Empty);
|
|
break;
|
|
case XmlBinaryNodeType.ZeroText:
|
|
value.SetValue(ValueHandleType.Zero);
|
|
break;
|
|
case XmlBinaryNodeType.OneText:
|
|
value.SetValue(ValueHandleType.One);
|
|
break;
|
|
case XmlBinaryNodeType.TrueText:
|
|
value.SetValue(ValueHandleType.True);
|
|
break;
|
|
case XmlBinaryNodeType.FalseText:
|
|
value.SetValue(ValueHandleType.False);
|
|
break;
|
|
case XmlBinaryNodeType.BoolText:
|
|
value.SetValue(ReadUInt8() != 0 ? ValueHandleType.True : ValueHandleType.False);
|
|
break;
|
|
case XmlBinaryNodeType.Chars8Text:
|
|
ReadValue(value, ValueHandleType.UTF8, ReadUInt8());
|
|
break;
|
|
case XmlBinaryNodeType.Chars16Text:
|
|
ReadValue(value, ValueHandleType.UTF8, ReadUInt16());
|
|
break;
|
|
case XmlBinaryNodeType.Chars32Text:
|
|
ReadValue(value, ValueHandleType.UTF8, ReadUInt31());
|
|
break;
|
|
case XmlBinaryNodeType.UnicodeChars8Text:
|
|
ReadUnicodeValue(value, ReadUInt8());
|
|
break;
|
|
case XmlBinaryNodeType.UnicodeChars16Text:
|
|
ReadUnicodeValue(value, ReadUInt16());
|
|
break;
|
|
case XmlBinaryNodeType.UnicodeChars32Text:
|
|
ReadUnicodeValue(value, ReadUInt31());
|
|
break;
|
|
case XmlBinaryNodeType.Bytes8Text:
|
|
ReadValue(value, ValueHandleType.Base64, ReadUInt8());
|
|
break;
|
|
case XmlBinaryNodeType.Bytes16Text:
|
|
ReadValue(value, ValueHandleType.Base64, ReadUInt16());
|
|
break;
|
|
case XmlBinaryNodeType.Bytes32Text:
|
|
ReadValue(value, ValueHandleType.Base64, ReadUInt31());
|
|
break;
|
|
case XmlBinaryNodeType.DictionaryText:
|
|
value.SetDictionaryValue(ReadDictionaryKey());
|
|
break;
|
|
case XmlBinaryNodeType.UniqueIdText:
|
|
ReadValue(value, ValueHandleType.UniqueId, ValueHandleLength.UniqueId);
|
|
break;
|
|
case XmlBinaryNodeType.GuidText:
|
|
ReadValue(value, ValueHandleType.Guid, ValueHandleLength.Guid);
|
|
break;
|
|
case XmlBinaryNodeType.DecimalText:
|
|
ReadValue(value, ValueHandleType.Decimal, ValueHandleLength.Decimal);
|
|
break;
|
|
case XmlBinaryNodeType.Int8Text:
|
|
ReadValue(value, ValueHandleType.Int8, ValueHandleLength.Int8);
|
|
break;
|
|
case XmlBinaryNodeType.Int16Text:
|
|
ReadValue(value, ValueHandleType.Int16, ValueHandleLength.Int16);
|
|
break;
|
|
case XmlBinaryNodeType.Int32Text:
|
|
ReadValue(value, ValueHandleType.Int32, ValueHandleLength.Int32);
|
|
break;
|
|
case XmlBinaryNodeType.Int64Text:
|
|
ReadValue(value, ValueHandleType.Int64, ValueHandleLength.Int64);
|
|
break;
|
|
case XmlBinaryNodeType.UInt64Text:
|
|
ReadValue(value, ValueHandleType.UInt64, ValueHandleLength.UInt64);
|
|
break;
|
|
case XmlBinaryNodeType.FloatText:
|
|
ReadValue(value, ValueHandleType.Single, ValueHandleLength.Single);
|
|
break;
|
|
case XmlBinaryNodeType.DoubleText:
|
|
ReadValue(value, ValueHandleType.Double, ValueHandleLength.Double);
|
|
break;
|
|
case XmlBinaryNodeType.TimeSpanText:
|
|
ReadValue(value, ValueHandleType.TimeSpan, ValueHandleLength.TimeSpan);
|
|
break;
|
|
case XmlBinaryNodeType.DateTimeText:
|
|
ReadValue(value, ValueHandleType.DateTime, ValueHandleLength.DateTime);
|
|
break;
|
|
case XmlBinaryNodeType.StartListText:
|
|
ReadList(value);
|
|
break;
|
|
case XmlBinaryNodeType.QNameDictionaryText:
|
|
ReadQName(value);
|
|
break;
|
|
default:
|
|
XmlExceptionHelper.ThrowInvalidBinaryFormat(reader);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void ReadValue(ValueHandle value, ValueHandleType type, int length)
|
|
{
|
|
int offset = ReadBytes(length);
|
|
value.SetValue(type, offset, length);
|
|
}
|
|
|
|
void ReadUnicodeValue(ValueHandle value, int length)
|
|
{
|
|
if ((length & 1) != 0)
|
|
XmlExceptionHelper.ThrowInvalidBinaryFormat(reader);
|
|
ReadValue(value, ValueHandleType.Unicode, length);
|
|
}
|
|
|
|
void ReadList(ValueHandle value)
|
|
{
|
|
if (listValue == null)
|
|
{
|
|
listValue = new ValueHandle(this);
|
|
}
|
|
int count = 0;
|
|
int offset = this.Offset;
|
|
while (true)
|
|
{
|
|
XmlBinaryNodeType nodeType = GetNodeType();
|
|
SkipNodeType();
|
|
if (nodeType == XmlBinaryNodeType.StartListText)
|
|
XmlExceptionHelper.ThrowInvalidBinaryFormat(reader);
|
|
if (nodeType == XmlBinaryNodeType.EndListText)
|
|
break;
|
|
ReadValue(nodeType, listValue);
|
|
count++;
|
|
}
|
|
value.SetValue(ValueHandleType.List, offset, count);
|
|
}
|
|
|
|
public void ReadQName(ValueHandle value)
|
|
{
|
|
int prefix = ReadUInt8();
|
|
if (prefix >= 26)
|
|
XmlExceptionHelper.ThrowInvalidBinaryFormat(reader);
|
|
int key = ReadDictionaryKey();
|
|
value.SetQNameValue(prefix, key);
|
|
}
|
|
|
|
public int[] GetRows()
|
|
{
|
|
if (buffer == null)
|
|
{
|
|
return new int[1] { 0 };
|
|
}
|
|
|
|
ArrayList list = new ArrayList();
|
|
list.Add(offsetMin);
|
|
for (int i = offsetMin; i < offsetMax; i++)
|
|
{
|
|
if (buffer[i] == (byte)13 || buffer[i] == (byte)10)
|
|
{
|
|
if (i + 1 < offsetMax && buffer[i + 1] == (byte)10)
|
|
i++;
|
|
list.Add(i + 1);
|
|
}
|
|
}
|
|
return (int[])list.ToArray(typeof(int));
|
|
}
|
|
}
|
|
}
|