//------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. //------------------------------------------------------------ namespace System.Xml { using System; using System.IO; using System.Runtime; using System.Runtime.Serialization; using System.Security; 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); } class XmlBinaryReader : XmlBaseReader, IXmlBinaryReaderInitializer { bool isTextWithEndElement; bool buffered; ArrayState arrayState; int arrayCount; int maxBytesPerRead; XmlBinaryNodeType arrayNodeType; OnXmlDictionaryReaderClose onClose; public XmlBinaryReader() { } public void SetInput(byte[] buffer, int offset, int count, IXmlDictionary dictionary, XmlDictionaryReaderQuotas quotas, XmlBinaryReaderSession session, OnXmlDictionaryReaderClose onClose) { if (buffer == null) throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("buffer"); if (offset < 0) throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("offset", SR.GetString(SR.ValueMustBeNonNegative))); if (offset > buffer.Length) throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("offset", SR.GetString(SR.OffsetExceedsBufferSize, buffer.Length))); if (count < 0) throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("count", SR.GetString(SR.ValueMustBeNonNegative))); if (count > buffer.Length - offset) throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("count", SR.GetString(SR.SizeExceedsRemainingBufferSpace, buffer.Length - offset))); MoveToInitial(quotas, session, onClose); BufferReader.SetBuffer(buffer, offset, count, dictionary, session); this.buffered = true; } public void SetInput(Stream stream, IXmlDictionary dictionary, XmlDictionaryReaderQuotas quotas, XmlBinaryReaderSession session, OnXmlDictionaryReaderClose onClose) { if (stream == null) throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("stream"); MoveToInitial(quotas, session, onClose); BufferReader.SetBuffer(stream, dictionary, session); this.buffered = false; } void MoveToInitial(XmlDictionaryReaderQuotas quotas, XmlBinaryReaderSession session, OnXmlDictionaryReaderClose onClose) { MoveToInitial(quotas); this.maxBytesPerRead = quotas.MaxBytesPerRead; this.arrayState = ArrayState.None; this.onClose = onClose; this.isTextWithEndElement = false; } public override void Close() { base.Close(); OnXmlDictionaryReaderClose onClose = this.onClose; this.onClose = null; if (onClose != null) { try { onClose(this); } catch (Exception e) { if (Fx.IsFatal(e)) throw; throw DiagnosticUtility.ExceptionUtility.ThrowHelperCallback(e); } } } 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; } 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; } } void ReadTextWithEndElement() { ExitScope(); ReadNode(); } 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(); } bool ReadNode() { if (!buffered) BufferReader.SetWindow(ElementNode.BufferOffset, this.maxBytesPerRead); if (BufferReader.EndOfFile) { MoveToEndOfFile(); return false; } XmlBinaryNodeType nodeType; if (arrayState == ArrayState.None) { nodeType = GetNodeType(); SkipNodeType(); } else { Fx.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; } } void VerifyWhitespace() { if (!this.Node.Value.IsWhitespace()) XmlExceptionHelper.ThrowInvalidBinaryFormat(this); } void ReadAttributes() { XmlBinaryNodeType nodeType = GetNodeType(); if (nodeType < XmlBinaryNodeType.MinAttribute || nodeType > XmlBinaryNodeType.MaxAttribute) return; ReadAttributes2(); } 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); attributeNode = AddXmlnsAttribute(nameSpace); break; case XmlBinaryNodeType.ShortXmlnsAttribute: SkipNodeType(); nameSpace = AddNamespace(); nameSpace.Prefix.SetValue(PrefixHandleType.Empty); ReadName(nameSpace.Uri); attributeNode = AddXmlnsAttribute(nameSpace); break; case XmlBinaryNodeType.ShortDictionaryXmlnsAttribute: SkipNodeType(); nameSpace = AddNamespace(); nameSpace.Prefix.SetValue(PrefixHandleType.Empty); ReadDictionaryName(nameSpace.Uri); attributeNode = AddXmlnsAttribute(nameSpace); break; case XmlBinaryNodeType.DictionaryXmlnsAttribute: SkipNodeType(); nameSpace = AddNamespace(); ReadName(nameSpace.Prefix); ReadDictionaryName(nameSpace.Uri); attributeNode = 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) > this.maxBytesPerRead) XmlExceptionHelper.ThrowMaxBytesPerReadExceeded(this, this.maxBytesPerRead); ProcessAttributes(); return; } } } void ReadText(XmlTextNode textNode, ValueHandleType type, int length) { int offset = BufferReader.ReadBytes(length); textNode.Value.SetValue(type, offset, length); if (this.OutsideRootElement) VerifyWhitespace(); } void ReadBinaryText(XmlTextNode textNode, int length) { ReadText(textNode, ValueHandleType.Base64, length); } 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(this.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); } } 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); } } 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(this.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); } } void ReadPartialBinaryText(bool withEndElement, int length) { const int nodeLength = 5; int maxBytesPerRead = Math.Max(this.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); } } void InsertNode(XmlBinaryNodeType nodeType, int length) { byte[] buffer = new byte[5]; buffer[0] = (byte)nodeType; 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); } void ReadAttributeText(XmlAttributeTextNode textNode) { XmlBinaryNodeType nodeType = GetNodeType(); SkipNodeType(); BufferReader.ReadValue(nodeType, textNode.Value); } void ReadName(ValueHandle value) { int length = ReadMultiByteUInt31(); int offset = BufferReader.ReadBytes(length); value.SetValue(ValueHandleType.UTF8, offset, length); } void ReadName(StringHandle handle) { int length = ReadMultiByteUInt31(); int offset = BufferReader.ReadBytes(length); handle.SetValue(offset, length); } void ReadName(PrefixHandle prefix) { int length = ReadMultiByteUInt31(); int offset = BufferReader.ReadBytes(length); prefix.SetValue(offset, length); } void ReadDictionaryName(StringHandle s) { int key = ReadDictionaryKey(); s.SetValue(key); } XmlBinaryNodeType GetNodeType() { return BufferReader.GetNodeType(); } void SkipNodeType() { BufferReader.SkipNodeType(); } int ReadDictionaryKey() { return BufferReader.ReadDictionaryKey(); } int ReadMultiByteUInt31() { return BufferReader.ReadMultiByteUInt31(); } int ReadUInt8() { return BufferReader.ReadUInt8(); } int ReadUInt16() { return BufferReader.ReadUInt16(); } int ReadUInt31() { return BufferReader.ReadUInt31(); } 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; } } 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(); } void MoveToArrayElement() { arrayState = ArrayState.Element; MoveToNode(ElementNode); } void SkipArrayElements(int count) { arrayCount -= count; if (arrayCount == 0) { arrayState = ArrayState.None; ExitScope(); ReadNode(); } } public override bool IsStartArray(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(Int16); break; case XmlBinaryNodeType.Int32TextWithEndElement: type = typeof(Int32); break; case XmlBinaryNodeType.Int64TextWithEndElement: type = typeof(Int64); 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; } bool IsStartArray(string localName, string namespaceUri, XmlBinaryNodeType nodeType) { return IsStartElement(localName, namespaceUri) && arrayState == ArrayState.Element && arrayNodeType == nodeType && !Signing; } bool IsStartArray(XmlDictionaryString localName, XmlDictionaryString namespaceUri, XmlBinaryNodeType nodeType) { return IsStartElement(localName, namespaceUri) && arrayState == ArrayState.Element && arrayNodeType == nodeType && !Signing; } void CheckArray(Array array, int offset, int count) { if (array == null) throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("array")); if (offset < 0) throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("offset", SR.GetString(SR.ValueMustBeNonNegative))); if (offset > array.Length) throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("offset", SR.GetString(SR.OffsetExceedsBufferSize, array.Length))); if (count < 0) throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("count", SR.GetString(SR.ValueMustBeNonNegative))); if (count > array.Length - offset) throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("count", SR.GetString(SR.SizeExceedsRemainingBufferSpace, array.Length - offset))); } // bool [Fx.Tag.SecurityNote(Critical = "Contains unsafe code.", Safe = "Unsafe code is effectively encapsulated, all inputs are validated.")] [SecuritySafeCritical] unsafe int ReadArray(bool[] array, int offset, int count) { CheckArray(array, offset, count); int actual = Math.Min(count, arrayCount); fixed (bool* items = &array[offset]) { BufferReader.UnsafeReadArray((byte*)items, (byte*)&items[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); } // Int16 [Fx.Tag.SecurityNote(Critical = "Contains unsafe code.", Safe = "Unsafe code is effectively encapsulated, all inputs are validated.")] [SecuritySafeCritical] unsafe int ReadArray(Int16[] array, int offset, int count) { CheckArray(array, offset, count); int actual = Math.Min(count, arrayCount); fixed (Int16* items = &array[offset]) { BufferReader.UnsafeReadArray((byte*)items, (byte*)&items[actual]); } SkipArrayElements(actual); return actual; } public override int ReadArray(string localName, string namespaceUri, Int16[] array, int offset, int count) { if (IsStartArray(localName, namespaceUri, XmlBinaryNodeType.Int16TextWithEndElement) && BitConverter.IsLittleEndian) return ReadArray(array, offset, count); return base.ReadArray(localName, namespaceUri, array, offset, count); } public override int ReadArray(XmlDictionaryString localName, XmlDictionaryString namespaceUri, Int16[] array, int offset, int count) { if (IsStartArray(localName, namespaceUri, XmlBinaryNodeType.Int16TextWithEndElement) && BitConverter.IsLittleEndian) return ReadArray(array, offset, count); return base.ReadArray(localName, namespaceUri, array, offset, count); } // Int32 [Fx.Tag.SecurityNote(Critical = "Contains unsafe code.", Safe = "Unsafe code is effectively encapsulated, all inputs are validated.")] [SecuritySafeCritical] unsafe int ReadArray(Int32[] array, int offset, int count) { CheckArray(array, offset, count); int actual = Math.Min(count, arrayCount); fixed (Int32* items = &array[offset]) { BufferReader.UnsafeReadArray((byte*)items, (byte*)&items[actual]); } SkipArrayElements(actual); return actual; } public override int ReadArray(string localName, string namespaceUri, Int32[] array, int offset, int count) { if (IsStartArray(localName, namespaceUri, XmlBinaryNodeType.Int32TextWithEndElement) && BitConverter.IsLittleEndian) return ReadArray(array, offset, count); return base.ReadArray(localName, namespaceUri, array, offset, count); } public override int ReadArray(XmlDictionaryString localName, XmlDictionaryString namespaceUri, Int32[] array, int offset, int count) { if (IsStartArray(localName, namespaceUri, XmlBinaryNodeType.Int32TextWithEndElement) && BitConverter.IsLittleEndian) return ReadArray(array, offset, count); return base.ReadArray(localName, namespaceUri, array, offset, count); } // Int64 [Fx.Tag.SecurityNote(Critical = "Contains unsafe code.", Safe = "Unsafe code is effectively encapsulated, all inputs are validated.")] [SecuritySafeCritical] unsafe int ReadArray(Int64[] array, int offset, int count) { CheckArray(array, offset, count); int actual = Math.Min(count, arrayCount); fixed (Int64* items = &array[offset]) { BufferReader.UnsafeReadArray((byte*)items, (byte*)&items[actual]); } SkipArrayElements(actual); return actual; } public override int ReadArray(string localName, string namespaceUri, Int64[] array, int offset, int count) { if (IsStartArray(localName, namespaceUri, XmlBinaryNodeType.Int64TextWithEndElement) && BitConverter.IsLittleEndian) return ReadArray(array, offset, count); return base.ReadArray(localName, namespaceUri, array, offset, count); } public override int ReadArray(XmlDictionaryString localName, XmlDictionaryString namespaceUri, Int64[] array, int offset, int count) { if (IsStartArray(localName, namespaceUri, XmlBinaryNodeType.Int64TextWithEndElement) && BitConverter.IsLittleEndian) return ReadArray(array, offset, count); return base.ReadArray(localName, namespaceUri, array, offset, count); } // float [Fx.Tag.SecurityNote(Critical = "Contains unsafe code.", Safe = "Unsafe code is effectively encapsulated, all inputs are validated.")] [SecuritySafeCritical] unsafe int ReadArray(float[] array, int offset, int count) { CheckArray(array, offset, count); int actual = Math.Min(count, arrayCount); fixed (float* items = &array[offset]) { BufferReader.UnsafeReadArray((byte*)items, (byte*)&items[actual]); } SkipArrayElements(actual); return actual; } public override int ReadArray(string localName, string namespaceUri, float[] array, int offset, int count) { if (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 (IsStartArray(localName, namespaceUri, XmlBinaryNodeType.FloatTextWithEndElement)) return ReadArray(array, offset, count); return base.ReadArray(localName, namespaceUri, array, offset, count); } // double [Fx.Tag.SecurityNote(Critical = "Contains unsafe code.", Safe = "Unsafe code is effectively encapsulated, all inputs are validated.")] [SecuritySafeCritical] unsafe int ReadArray(double[] array, int offset, int count) { CheckArray(array, offset, count); int actual = Math.Min(count, arrayCount); fixed (double* items = &array[offset]) { BufferReader.UnsafeReadArray((byte*)items, (byte*)&items[actual]); } SkipArrayElements(actual); return actual; } public override int ReadArray(string localName, string namespaceUri, double[] array, int offset, int count) { if (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 (IsStartArray(localName, namespaceUri, XmlBinaryNodeType.DoubleTextWithEndElement)) return ReadArray(array, offset, count); return base.ReadArray(localName, namespaceUri, array, offset, count); } // decimal [Fx.Tag.SecurityNote(Critical = "Contains unsafe code.", Safe = "Unsafe code is effectively encapsulated, all inputs are validated.")] [SecuritySafeCritical] unsafe int ReadArray(decimal[] array, int offset, int count) { CheckArray(array, offset, count); int actual = Math.Min(count, arrayCount); fixed (decimal* items = &array[offset]) { BufferReader.UnsafeReadArray((byte*)items, (byte*)&items[actual]); } SkipArrayElements(actual); return actual; } public override int ReadArray(string localName, string namespaceUri, decimal[] array, int offset, int count) { if (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 (IsStartArray(localName, namespaceUri, XmlBinaryNodeType.DecimalTextWithEndElement)) return ReadArray(array, offset, count); return base.ReadArray(localName, namespaceUri, array, offset, count); } // DateTime int ReadArray(DateTime[] array, int offset, int count) { CheckArray(array, offset, count); int actual = Math.Min(count, arrayCount); for (int i = 0; i < actual; i++) { array[offset + i] = 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 int ReadArray(Guid[] array, int offset, int count) { CheckArray(array, offset, count); int actual = Math.Min(count, arrayCount); for (int i = 0; i < actual; i++) { array[offset + i] = 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 int ReadArray(TimeSpan[] array, int offset, int count) { CheckArray(array, offset, count); int actual = Math.Min(count, arrayCount); for (int i = 0; i < actual; i++) { array[offset + i] = 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); } enum ArrayState { None, Element, Content } protected override XmlSigningNodeWriter CreateSigningNodeWriter() { return new XmlSigningNodeWriter(false); } } }