1 //------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation.  All rights reserved.
3 //------------------------------------------------------------
4 namespace System.Xml
5 {
6     using System;
7     using System.Collections;
8     using System.Globalization;
9     using System.IO;
10     using System.Runtime;
11     using System.Runtime.Serialization;
12     using System.Security;
13     using System.Text;
14 
15     class XmlBufferReader
16     {
17         XmlDictionaryReader reader;
18         Stream stream;
19         byte[] streamBuffer;
20         byte[] buffer;
21         int offsetMin;
22         int offsetMax;
23         IXmlDictionary dictionary;
24         XmlBinaryReaderSession session;
25         byte[] guid;
26         int offset;
27         const int maxBytesPerChar = 3;
28         char[] chars;
29         int windowOffset;
30         int windowOffsetMax;
31         ValueHandle listValue;
32         static byte[] emptyByteArray = new byte[0];
33         static XmlBufferReader empty = new XmlBufferReader(emptyByteArray);
34 
XmlBufferReader(XmlDictionaryReader reader)35         public XmlBufferReader(XmlDictionaryReader reader)
36         {
37             this.reader = reader;
38         }
39 
XmlBufferReader(byte[] buffer)40         public XmlBufferReader(byte[] buffer)
41         {
42             this.reader = null;
43             this.buffer = buffer;
44         }
45 
46         static public XmlBufferReader Empty
47         {
48             get
49             {
50                 return empty;
51             }
52         }
53 
54         public byte[] Buffer
55         {
56             get
57             {
58                 return buffer;
59             }
60         }
61 
62         public bool IsStreamed
63         {
64             get
65             {
66                 return stream != null;
67             }
68         }
69 
SetBuffer(Stream stream, IXmlDictionary dictionary, XmlBinaryReaderSession session)70         public void SetBuffer(Stream stream, IXmlDictionary dictionary, XmlBinaryReaderSession session)
71         {
72             if (streamBuffer == null)
73             {
74                 streamBuffer = new byte[128];
75             }
76             SetBuffer(stream, streamBuffer, 0, 0, dictionary, session);
77             this.windowOffset = 0;
78             this.windowOffsetMax = streamBuffer.Length;
79         }
80 
SetBuffer(byte[] buffer, int offset, int count, IXmlDictionary dictionary, XmlBinaryReaderSession session)81         public void SetBuffer(byte[] buffer, int offset, int count, IXmlDictionary dictionary, XmlBinaryReaderSession session)
82         {
83             SetBuffer(null, buffer, offset, count, dictionary, session);
84         }
85 
SetBuffer(Stream stream, byte[] buffer, int offset, int count, IXmlDictionary dictionary, XmlBinaryReaderSession session)86         void SetBuffer(Stream stream, byte[] buffer, int offset, int count, IXmlDictionary dictionary, XmlBinaryReaderSession session)
87         {
88             this.stream = stream;
89             this.buffer = buffer;
90             this.offsetMin = offset;
91             this.offset = offset;
92             this.offsetMax = offset + count;
93             this.dictionary = dictionary;
94             this.session = session;
95         }
96 
Close()97         public void Close()
98         {
99             if (streamBuffer != null && streamBuffer.Length > 4096)
100             {
101                 streamBuffer = null;
102             }
103             if (stream != null)
104             {
105                 stream.Close();
106                 this.stream = null;
107             }
108             this.buffer = emptyByteArray;
109             this.offset = 0;
110             this.offsetMax = 0;
111             this.windowOffset = 0;
112             this.windowOffsetMax = 0;
113             this.dictionary = null;
114             this.session = null;
115         }
116 
117         public bool EndOfFile
118         {
119             get
120             {
121                 return offset == offsetMax && !TryEnsureByte();
122             }
123         }
124 
GetByte()125         public byte GetByte()
126         {
127             int offset = this.offset;
128             if (offset < offsetMax)
129                 return buffer[offset];
130             else
131                 return GetByteHard();
132         }
133 
SkipByte()134         public void SkipByte()
135         {
136             Advance(1);
137         }
138 
GetByteHard()139         byte GetByteHard()
140         {
141             EnsureByte();
142             return buffer[offset];
143         }
144 
GetBuffer(int count, out int offset)145         public byte[] GetBuffer(int count, out int offset)
146         {
147             offset = this.offset;
148             if (offset <= this.offsetMax - count)
149                 return buffer;
150             return GetBufferHard(count, out offset);
151         }
152 
GetBuffer(int count, out int offset, out int offsetMax)153         public byte[] GetBuffer(int count, out int offset, out int offsetMax)
154         {
155             offset = this.offset;
156             if (offset <= this.offsetMax - count)
157             {
158                 offsetMax = this.offset + count;
159             }
160             else
161             {
162                 TryEnsureBytes(Math.Min(count, windowOffsetMax - offset));
163                 offsetMax = this.offsetMax;
164             }
165             return buffer;
166         }
167 
GetBuffer(out int offset, out int offsetMax)168         public byte[] GetBuffer(out int offset, out int offsetMax)
169         {
170             offset = this.offset;
171             offsetMax = this.offsetMax;
172             return buffer;
173         }
174 
GetBufferHard(int count, out int offset)175         byte[] GetBufferHard(int count, out int offset)
176         {
177             offset = this.offset;
178             EnsureBytes(count);
179             return buffer;
180         }
181 
EnsureByte()182         void EnsureByte()
183         {
184             if (!TryEnsureByte())
185                 XmlExceptionHelper.ThrowUnexpectedEndOfFile(reader);
186         }
187 
TryEnsureByte()188         bool TryEnsureByte()
189         {
190             if (stream == null)
191                 return false;
192             if (offsetMax >= windowOffsetMax)
193                 XmlExceptionHelper.ThrowMaxBytesPerReadExceeded(reader, windowOffsetMax - windowOffset);
194             if (offsetMax >= buffer.Length)
195                 return TryEnsureBytes(1);
196             int b = stream.ReadByte();
197             if (b == -1)
198                 return false;
199             buffer[offsetMax++] = (byte)b;
200             return true;
201         }
202 
EnsureBytes(int count)203         void EnsureBytes(int count)
204         {
205             if (!TryEnsureBytes(count))
206                 XmlExceptionHelper.ThrowUnexpectedEndOfFile(reader);
207         }
208 
TryEnsureBytes(int count)209         bool TryEnsureBytes(int count)
210         {
211             if (stream == null)
212                 return false;
213             if (offset > int.MaxValue - count)
214                 XmlExceptionHelper.ThrowMaxBytesPerReadExceeded(reader, windowOffsetMax - windowOffset);
215             int newOffsetMax = offset + count;
216             if (newOffsetMax < offsetMax)
217                 return true;
218             if (newOffsetMax > windowOffsetMax)
219                 XmlExceptionHelper.ThrowMaxBytesPerReadExceeded(reader, windowOffsetMax - windowOffset);
220             if (newOffsetMax > buffer.Length)
221             {
222                 byte[] newBuffer = new byte[Math.Max(newOffsetMax, buffer.Length * 2)];
223                 System.Buffer.BlockCopy(this.buffer, 0, newBuffer, 0, offsetMax);
224                 buffer = newBuffer;
225                 streamBuffer = newBuffer;
226             }
227             int needed = newOffsetMax - offsetMax;
228             while (needed > 0)
229             {
230                 int actual = stream.Read(buffer, offsetMax, needed);
231                 if (actual == 0)
232                     return false;
233                 offsetMax += actual;
234                 needed -= actual;
235             }
236             return true;
237         }
238 
239 #if NO
ReadByte(byte b)240         void ReadByte(byte b)
241         {
242             if (BufferReader.GetByte() != b)
243                 XmlExceptionHelper.ThrowTokenExpected(this, ((char)b).ToString(), (char)BufferReader.GetByte());
244         }
245 #endif
Advance(int count)246         public void Advance(int count)
247         {
248             Fx.Assert(this.offset + count <= offsetMax, "");
249             this.offset += count;
250         }
251 
InsertBytes(byte[] buffer, int offset, int count)252         public void InsertBytes(byte[] buffer, int offset, int count)
253         {
254             Fx.Assert(stream != null, "");
255             if (offsetMax > buffer.Length - count)
256             {
257                 byte[] newBuffer = new byte[offsetMax + count];
258                 System.Buffer.BlockCopy(this.buffer, 0, newBuffer, 0, this.offsetMax);
259                 this.buffer = newBuffer;
260                 this.streamBuffer = newBuffer;
261             }
262             System.Buffer.BlockCopy(this.buffer, this.offset, this.buffer, this.offset + count, this.offsetMax - this.offset);
263             offsetMax += count;
264             System.Buffer.BlockCopy(buffer, offset, this.buffer, this.offset, count);
265         }
266 
SetWindow(int windowOffset, int windowLength)267         public void SetWindow(int windowOffset, int windowLength)
268         {
269             // [0...elementOffset-1][elementOffset..offset][offset..offsetMax-1][offsetMax..buffer.Length]
270             // ^--Elements, Attributes in scope
271             //                      ^-- The node just consumed
272             //                                             ^--Data buffered, not consumed
273             //                                                                  ^--Unused space
274             if (windowOffset > int.MaxValue - windowLength)
275                 windowLength = int.MaxValue - windowOffset;
276 
277             if (offset != windowOffset)
278             {
279                 System.Buffer.BlockCopy(buffer, offset, buffer, windowOffset, offsetMax - offset);
280                 offsetMax = windowOffset + (offsetMax - offset);
281                 offset = windowOffset;
282             }
283             this.windowOffset = windowOffset;
284             this.windowOffsetMax = Math.Max(windowOffset + windowLength, offsetMax);
285         }
286 
287         public int Offset
288         {
289             get
290             {
291                 return offset;
292             }
293             set
294             {
295                 Fx.Assert(value >= offsetMin && value <= offsetMax, "");
296                 this.offset = value;
297             }
298         }
299 
ReadBytes(int count)300         public int ReadBytes(int count)
301         {
302             Fx.Assert(count >= 0, "");
303             int offset = this.offset;
304             if (offset > offsetMax - count)
305                 EnsureBytes(count);
306             this.offset += count;
307             return offset;
308         }
309 
ReadMultiByteUInt31()310         public int ReadMultiByteUInt31()
311         {
312             int i = GetByte();
313             Advance(1);
314             if ((i & 0x80) == 0)
315                 return i;
316             i &= 0x7F;
317 
318             int j = GetByte();
319             Advance(1);
320             i |= ((j & 0x7F) << 7);
321             if ((j & 0x80) == 0)
322                 return i;
323 
324             int k = GetByte();
325             Advance(1);
326             i |= ((k & 0x7F) << 14);
327             if ((k & 0x80) == 0)
328                 return i;
329 
330             int l = GetByte();
331             Advance(1);
332             i |= ((l & 0x7F) << 21);
333             if ((l & 0x80) == 0)
334                 return i;
335 
336             int m = GetByte();
337             Advance(1);
338             i |= (m << 28);
339             if ((m & 0xF8) != 0)
340                 XmlExceptionHelper.ThrowInvalidBinaryFormat(reader);
341 
342             return i;
343         }
344 
ReadUInt8()345         public int ReadUInt8()
346         {
347             byte b = GetByte();
348             Advance(1);
349             return b;
350         }
351 
ReadInt8()352         public int ReadInt8()
353         {
354             return (sbyte)ReadUInt8();
355         }
356 
ReadUInt16()357         public int ReadUInt16()
358         {
359             int offset;
360             byte[] buffer = GetBuffer(2, out offset);
361             int i = buffer[offset + 0] + (buffer[offset + 1] << 8);
362             Advance(2);
363             return i;
364         }
365 
ReadInt16()366         public int ReadInt16()
367         {
368             return (Int16)ReadUInt16();
369         }
370 
ReadInt32()371         public int ReadInt32()
372         {
373             int offset;
374             byte[] buffer = GetBuffer(4, out offset);
375             byte b1 = buffer[offset + 0];
376             byte b2 = buffer[offset + 1];
377             byte b3 = buffer[offset + 2];
378             byte b4 = buffer[offset + 3];
379             Advance(4);
380             return (((((b4 << 8) + b3) << 8) + b2) << 8) + b1;
381         }
382 
ReadUInt31()383         public int ReadUInt31()
384         {
385             int i = ReadInt32();
386             if (i < 0)
387                 XmlExceptionHelper.ThrowInvalidBinaryFormat(reader);
388             return i;
389         }
390 
ReadInt64()391         public long ReadInt64()
392         {
393             Int64 lo = (UInt32)ReadInt32();
394             Int64 hi = (UInt32)ReadInt32();
395             return (hi << 32) + lo;
396         }
397 
398         [Fx.Tag.SecurityNote(Critical = "Contains unsafe code.",
399             Safe = "Unsafe code is effectively encapsulated, all inputs are validated.")]
400         [SecuritySafeCritical]
ReadSingle()401         unsafe public float ReadSingle()
402         {
403             int offset;
404             byte[] buffer = GetBuffer(ValueHandleLength.Single, out offset);
405             float value;
406             byte* pb = (byte*)&value;
407             Fx.Assert(sizeof(float) == 4, "");
408             pb[0] = buffer[offset + 0];
409             pb[1] = buffer[offset + 1];
410             pb[2] = buffer[offset + 2];
411             pb[3] = buffer[offset + 3];
412             Advance(ValueHandleLength.Single);
413             return value;
414         }
415 
416         [Fx.Tag.SecurityNote(Critical = "Contains unsafe code.",
417             Safe = "Unsafe code is effectively encapsulated, all inputs are validated.")]
418         [SecuritySafeCritical]
ReadDouble()419         unsafe public double ReadDouble()
420         {
421             int offset;
422             byte[] buffer = GetBuffer(ValueHandleLength.Double, out offset);
423             double value;
424             byte* pb = (byte*)&value;
425             Fx.Assert(sizeof(double) == 8, "");
426             pb[0] = buffer[offset + 0];
427             pb[1] = buffer[offset + 1];
428             pb[2] = buffer[offset + 2];
429             pb[3] = buffer[offset + 3];
430             pb[4] = buffer[offset + 4];
431             pb[5] = buffer[offset + 5];
432             pb[6] = buffer[offset + 6];
433             pb[7] = buffer[offset + 7];
434             Advance(ValueHandleLength.Double);
435             return value;
436         }
437 
438         [Fx.Tag.SecurityNote(Critical = "Contains unsafe code.",
439             Safe = "Unsafe code is effectively encapsulated, all inputs are validated.")]
440         [SecuritySafeCritical]
ReadDecimal()441         unsafe public decimal ReadDecimal()
442         {
443             const int SignMask = unchecked((int)0x80000000);
444             const int ScaleMask = 0x00FF0000;
445 
446             int offset;
447             byte[] buffer = GetBuffer(ValueHandleLength.Decimal, out offset);
448             byte b1 = buffer[offset + 0];
449             byte b2 = buffer[offset + 1];
450             byte b3 = buffer[offset + 2];
451             byte b4 = buffer[offset + 3];
452             int flags = (((((b4 << 8) + b3) << 8) + b2) << 8) + b1;
453 
454             //this logic mirrors the code in Decimal(int []) ctor.
455             if ((flags & ~(SignMask | ScaleMask)) == 0 && (flags & ScaleMask) <= (28 << 16))
456             {
457                 decimal value;
458                 byte* pb = (byte*)&value;
459                 for (int i = 0; i < sizeof(decimal); i++)
460                     pb[i] = buffer[offset + i];
461 
462                 Advance(ValueHandleLength.Decimal);
463                 return value;
464             }
465             else
466             {
467                 XmlExceptionHelper.ThrowInvalidBinaryFormat(this.reader);
468             }
469 
470             //compiler doesn't know that XmlExceptionHelper.ThrowInvalidBinaryFormat always throws,
471             //so we have to have a return statement here even though we shouldn't hit this code path...
472             Fx.Assert("A decimal value should have been returned or an exception should have been thrown.");
473             return default(decimal);
474         }
475 
ReadUniqueId()476         public UniqueId ReadUniqueId()
477         {
478             int offset;
479             byte[] buffer = GetBuffer(ValueHandleLength.UniqueId, out offset);
480             UniqueId uniqueId = new UniqueId(buffer, offset);
481             Advance(ValueHandleLength.UniqueId);
482             return uniqueId;
483         }
484 
ReadDateTime()485         public DateTime ReadDateTime()
486         {
487             long value = 0;
488             try
489             {
490                 value = ReadInt64();
491                 return DateTime.FromBinary(value);
492             }
493             catch (ArgumentException exception)
494             {
495                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value.ToString(CultureInfo.InvariantCulture), "DateTime", exception));
496             }
497             catch (FormatException exception)
498             {
499                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value.ToString(CultureInfo.InvariantCulture), "DateTime", exception));
500             }
501             catch (OverflowException exception)
502             {
503                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value.ToString(CultureInfo.InvariantCulture), "DateTime", exception));
504             }
505         }
506 
ReadTimeSpan()507         public TimeSpan ReadTimeSpan()
508         {
509             long value = 0;
510             try
511             {
512                 value = ReadInt64();
513                 return TimeSpan.FromTicks(value);
514             }
515             catch (ArgumentException exception)
516             {
517                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value.ToString(CultureInfo.InvariantCulture), "TimeSpan", exception));
518             }
519             catch (FormatException exception)
520             {
521                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value.ToString(CultureInfo.InvariantCulture), "TimeSpan", exception));
522             }
523             catch (OverflowException exception)
524             {
525                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value.ToString(CultureInfo.InvariantCulture), "TimeSpan", exception));
526             }
527         }
528 
ReadGuid()529         public Guid ReadGuid()
530         {
531             int offset;
532             byte[] buffer = GetBuffer(ValueHandleLength.Guid, out offset);
533             Guid guid = GetGuid(offset);
534             Advance(ValueHandleLength.Guid);
535             return guid;
536         }
537 
ReadUTF8String(int length)538         public string ReadUTF8String(int length)
539         {
540             int offset;
541             byte[] buffer = GetBuffer(length, out offset);
542             char[] chars = GetCharBuffer(length);
543             int charCount = GetChars(offset, length, chars);
544             string value = new string(chars, 0, charCount);
545             Advance(length);
546             return value;
547         }
548 
549         [Fx.Tag.SecurityNote(Critical = "Contains unsafe code. Caller needs to validate arguments.")]
550         [SecurityCritical]
UnsafeReadArray(byte* dst, byte* dstMax)551         unsafe public void UnsafeReadArray(byte* dst, byte* dstMax)
552         {
553             UnsafeReadArray(dst, (int)(dstMax - dst));
554         }
555 
556         [Fx.Tag.SecurityNote(Critical = "Contains unsafe code. Caller needs to validate arguments.")]
557         [SecurityCritical]
UnsafeReadArray(byte* dst, int length)558         unsafe void UnsafeReadArray(byte* dst, int length)
559         {
560             if (stream != null)
561             {
562                 const int chunk = 256;
563                 while (length >= chunk)
564                 {
565                     byte[] _buffer = GetBuffer(chunk, out offset);
566                     for (int i = 0; i < chunk; i++)
567                     {
568                         *dst++ = _buffer[offset + i];
569                     }
570                     Advance(chunk);
571                     length -= chunk;
572                 }
573             }
574 
575             if (length > 0)
576             {
577                 byte[] buffer = GetBuffer(length, out offset);
578                 fixed (byte* _src = &buffer[offset])
579                 {
580                     byte* src = _src;
581                     byte* dstMax = dst + length;
582                     while (dst < dstMax)
583                     {
584                         *dst = *src;
585                         dst++;
586                         src++;
587                     }
588                 }
589                 Advance(length);
590             }
591         }
592 
GetCharBuffer(int count)593         char[] GetCharBuffer(int count)
594         {
595             if (count > 1024)
596                 return new char[count];
597             if (chars == null || chars.Length < count)
598                 chars = new char[count];
599             return chars;
600         }
601 
GetChars(int offset, int length, char[] chars)602         int GetChars(int offset, int length, char[] chars)
603         {
604             byte[] buffer = this.buffer;
605             for (int i = 0; i < length; i++)
606             {
607                 byte b = buffer[offset + i];
608                 if (b >= 0x80)
609                     return i + XmlConverter.ToChars(buffer, offset + i, length - i, chars, i);
610                 chars[i] = (char)b;
611             }
612             return length;
613         }
614 
GetChars(int offset, int length, char[] chars, int charOffset)615         int GetChars(int offset, int length, char[] chars, int charOffset)
616         {
617             byte[] buffer = this.buffer;
618             for (int i = 0; i < length; i++)
619             {
620                 byte b = buffer[offset + i];
621                 if (b >= 0x80)
622                     return i + XmlConverter.ToChars(buffer, offset + i, length - i, chars, charOffset + i);
623                 chars[charOffset + i] = (char)b;
624             }
625             return length;
626         }
627 
GetString(int offset, int length)628         public string GetString(int offset, int length)
629         {
630             char[] chars = GetCharBuffer(length);
631             int charCount = GetChars(offset, length, chars);
632             return new string(chars, 0, charCount);
633         }
634 
GetUnicodeString(int offset, int length)635         public string GetUnicodeString(int offset, int length)
636         {
637             return XmlConverter.ToStringUnicode(buffer, offset, length);
638         }
639 
GetString(int offset, int length, XmlNameTable nameTable)640         public string GetString(int offset, int length, XmlNameTable nameTable)
641         {
642             char[] chars = GetCharBuffer(length);
643             int charCount = GetChars(offset, length, chars);
644             return nameTable.Add(chars, 0, charCount);
645         }
646 
GetEscapedChars(int offset, int length, char[] chars)647         public int GetEscapedChars(int offset, int length, char[] chars)
648         {
649             byte[] buffer = this.buffer;
650             int charCount = 0;
651             int textOffset = offset;
652             int offsetMax = offset + length;
653             while (true)
654             {
655                 while (offset < offsetMax && IsAttrChar(buffer[offset]))
656                     offset++;
657                 charCount += GetChars(textOffset, offset - textOffset, chars, charCount);
658                 if (offset == offsetMax)
659                     break;
660                 textOffset = offset;
661                 if (buffer[offset] == '&')
662                 {
663                     while (offset < offsetMax && buffer[offset] != ';')
664                         offset++;
665                     offset++;
666                     int ch = GetCharEntity(textOffset, offset - textOffset);
667                     textOffset = offset;
668                     if (ch > char.MaxValue)
669                     {
670                         SurrogateChar surrogate = new SurrogateChar(ch);
671                         chars[charCount++] = surrogate.HighChar;
672                         chars[charCount++] = surrogate.LowChar;
673                     }
674                     else
675                     {
676                         chars[charCount++] = (char)ch;
677                     }
678                 }
679                 else if (buffer[offset] == '\n' || buffer[offset] == '\t')
680                 {
681                     chars[charCount++] = ' ';
682                     offset++;
683                     textOffset = offset;
684                 }
685                 else // '\r'
686                 {
687                     chars[charCount++] = ' ';
688                     offset++;
689 
690                     if (offset < offsetMax && buffer[offset] == '\n')
691                         offset++;
692 
693                     textOffset = offset;
694                 }
695 
696             }
697             return charCount;
698         }
699 
IsAttrChar(int ch)700         bool IsAttrChar(int ch)
701         {
702             switch (ch)
703             {
704                 case '&':
705                 case '\r':
706                 case '\t':
707                 case '\n':
708                     return false;
709 
710                 default:
711                     return true;
712             }
713         }
714 
GetEscapedString(int offset, int length)715         public string GetEscapedString(int offset, int length)
716         {
717             char[] chars = GetCharBuffer(length);
718             int charCount = GetEscapedChars(offset, length, chars);
719             return new string(chars, 0, charCount);
720         }
721 
GetEscapedString(int offset, int length, XmlNameTable nameTable)722         public string GetEscapedString(int offset, int length, XmlNameTable nameTable)
723         {
724             char[] chars = GetCharBuffer(length);
725             int charCount = GetEscapedChars(offset, length, chars);
726             return nameTable.Add(chars, 0, charCount);
727         }
728 
GetLessThanCharEntity(int offset, int length)729         int GetLessThanCharEntity(int offset, int length)
730         {
731             byte[] buffer = this.buffer;
732             if (length != 4 ||
733                 buffer[offset + 1] != (byte)'l' ||
734                 buffer[offset + 2] != (byte)'t')
735             {
736                 XmlExceptionHelper.ThrowInvalidCharRef(reader);
737             }
738             return (int)'<';
739         }
740 
GetGreaterThanCharEntity(int offset, int length)741         int GetGreaterThanCharEntity(int offset, int length)
742         {
743             byte[] buffer = this.buffer;
744             if (length != 4 ||
745                 buffer[offset + 1] != (byte)'g' ||
746                 buffer[offset + 2] != (byte)'t')
747             {
748                 XmlExceptionHelper.ThrowInvalidCharRef(reader);
749             }
750             return (int)'>';
751         }
752 
GetQuoteCharEntity(int offset, int length)753         int GetQuoteCharEntity(int offset, int length)
754         {
755             byte[] buffer = this.buffer;
756             if (length != 6 ||
757                 buffer[offset + 1] != (byte)'q' ||
758                 buffer[offset + 2] != (byte)'u' ||
759                 buffer[offset + 3] != (byte)'o' ||
760                 buffer[offset + 4] != (byte)'t')
761             {
762                 XmlExceptionHelper.ThrowInvalidCharRef(reader);
763             }
764             return (int)'"';
765         }
766 
GetAmpersandCharEntity(int offset, int length)767         int GetAmpersandCharEntity(int offset, int length)
768         {
769             byte[] buffer = this.buffer;
770             if (length != 5 ||
771                 buffer[offset + 1] != (byte)'a' ||
772                 buffer[offset + 2] != (byte)'m' ||
773                 buffer[offset + 3] != (byte)'p')
774             {
775                 XmlExceptionHelper.ThrowInvalidCharRef(reader);
776             }
777             return (int)'&';
778         }
779 
GetApostropheCharEntity(int offset, int length)780         int GetApostropheCharEntity(int offset, int length)
781         {
782             byte[] buffer = this.buffer;
783             if (length != 6 ||
784                 buffer[offset + 1] != (byte)'a' ||
785                 buffer[offset + 2] != (byte)'p' ||
786                 buffer[offset + 3] != (byte)'o' ||
787                 buffer[offset + 4] != (byte)'s')
788             {
789                 XmlExceptionHelper.ThrowInvalidCharRef(reader);
790             }
791             return (int)'\'';
792         }
793 
GetDecimalCharEntity(int offset, int length)794         int GetDecimalCharEntity(int offset, int length)
795         {
796             byte[] buffer = this.buffer;
797             Fx.Assert(buffer[offset + 0] == '&', "");
798             Fx.Assert(buffer[offset + 1] == '#', "");
799             Fx.Assert(buffer[offset + length - 1] == ';', "");
800             int value = 0;
801             for (int i = 2; i < length - 1; i++)
802             {
803                 byte ch = buffer[offset + i];
804                 if (ch < (byte)'0' || ch > (byte)'9')
805                     XmlExceptionHelper.ThrowInvalidCharRef(reader);
806                 value = value * 10 + (ch - '0');
807                 if (value > SurrogateChar.MaxValue)
808                     XmlExceptionHelper.ThrowInvalidCharRef(reader);
809             }
810             return value;
811         }
812 
GetHexCharEntity(int offset, int length)813         int GetHexCharEntity(int offset, int length)
814         {
815             byte[] buffer = this.buffer;
816             Fx.Assert(buffer[offset + 0] == '&', "");
817             Fx.Assert(buffer[offset + 1] == '#', "");
818             Fx.Assert(buffer[offset + 2] == 'x', "");
819             Fx.Assert(buffer[offset + length - 1] == ';', "");
820             int value = 0;
821             for (int i = 3; i < length - 1; i++)
822             {
823                 byte ch = buffer[offset + i];
824                 int digit = 0;
825                 if (ch >= '0' && ch <= '9')
826                     digit = (ch - '0');
827                 else if (ch >= 'a' && ch <= 'f')
828                     digit = 10 + (ch - 'a');
829                 else if (ch >= 'A' && ch <= 'F')
830                     digit = 10 + (ch - 'A');
831                 else
832                     XmlExceptionHelper.ThrowInvalidCharRef(reader);
833                 Fx.Assert(digit >= 0 && digit < 16, "");
834                 value = value * 16 + digit;
835                 if (value > SurrogateChar.MaxValue)
836                     XmlExceptionHelper.ThrowInvalidCharRef(reader);
837             }
838             return value;
839         }
840 
GetCharEntity(int offset, int length)841         public int GetCharEntity(int offset, int length)
842         {
843             if (length < 3)
844                 XmlExceptionHelper.ThrowInvalidCharRef(reader);
845             byte[] buffer = this.buffer;
846             Fx.Assert(buffer[offset] == '&', "");
847             Fx.Assert(buffer[offset + length - 1] == ';', "");
848             switch (buffer[offset + 1])
849             {
850                 case (byte)'l':
851                     return GetLessThanCharEntity(offset, length);
852                 case (byte)'g':
853                     return GetGreaterThanCharEntity(offset, length);
854                 case (byte)'a':
855                     if (buffer[offset + 2] == (byte)'m')
856                         return GetAmpersandCharEntity(offset, length);
857                     else
858                         return GetApostropheCharEntity(offset, length);
859                 case (byte)'q':
860                     return GetQuoteCharEntity(offset, length);
861                 case (byte)'#':
862                     if (buffer[offset + 2] == (byte)'x')
863                         return GetHexCharEntity(offset, length);
864                     else
865                         return GetDecimalCharEntity(offset, length);
866                 default:
867                     XmlExceptionHelper.ThrowInvalidCharRef(reader);
868                     return 0;
869             }
870         }
871 
IsWhitespaceKey(int key)872         public bool IsWhitespaceKey(int key)
873         {
874             string s = GetDictionaryString(key).Value;
875             for (int i = 0; i < s.Length; i++)
876             {
877                 if (!XmlConverter.IsWhitespace(s[i]))
878                     return false;
879             }
880             return true;
881         }
882 
IsWhitespaceUTF8(int offset, int length)883         public bool IsWhitespaceUTF8(int offset, int length)
884         {
885             byte[] buffer = this.buffer;
886             for (int i = 0; i < length; i++)
887             {
888                 if (!XmlConverter.IsWhitespace((char)buffer[offset + i]))
889                     return false;
890             }
891             return true;
892         }
893 
IsWhitespaceUnicode(int offset, int length)894         public bool IsWhitespaceUnicode(int offset, int length)
895         {
896             byte[] buffer = this.buffer;
897             for (int i = 0; i < length; i += sizeof(char))
898             {
899                 char ch = (char)GetInt16(offset + i);
900                 if (!XmlConverter.IsWhitespace(ch))
901                     return false;
902             }
903             return true;
904         }
905 
Equals2(int key1, int key2, XmlBufferReader bufferReader2)906         public bool Equals2(int key1, int key2, XmlBufferReader bufferReader2)
907         {
908             // If the keys aren't from the same dictionary, they still might be the same
909             if (key1 == key2)
910                 return true;
911             else
912                 return GetDictionaryString(key1).Value == bufferReader2.GetDictionaryString(key2).Value;
913         }
914 
Equals2(int key1, XmlDictionaryString xmlString2)915         public bool Equals2(int key1, XmlDictionaryString xmlString2)
916         {
917             if ((key1 & 1) == 0 && xmlString2.Dictionary == dictionary)
918                 return xmlString2.Key == (key1 >> 1);
919             else
920                 return GetDictionaryString(key1).Value == xmlString2.Value;
921         }
922 
Equals2(int offset1, int length1, byte[] buffer2)923         public bool Equals2(int offset1, int length1, byte[] buffer2)
924         {
925             int length2 = buffer2.Length;
926             if (length1 != length2)
927                 return false;
928             byte[] buffer1 = this.buffer;
929             for (int i = 0; i < length1; i++)
930             {
931                 if (buffer1[offset1 + i] != buffer2[i])
932                     return false;
933             }
934             return true;
935         }
936 
Equals2(int offset1, int length1, XmlBufferReader bufferReader2, int offset2, int length2)937         public bool Equals2(int offset1, int length1, XmlBufferReader bufferReader2, int offset2, int length2)
938         {
939             if (length1 != length2)
940                 return false;
941             byte[] buffer1 = this.buffer;
942             byte[] buffer2 = bufferReader2.buffer;
943             for (int i = 0; i < length1; i++)
944             {
945                 if (buffer1[offset1 + i] != buffer2[offset2 + i])
946                     return false;
947             }
948             return true;
949         }
950 
Equals2(int offset1, int length1, int offset2, int length2)951         public bool Equals2(int offset1, int length1, int offset2, int length2)
952         {
953             if (length1 != length2)
954                 return false;
955             if (offset1 == offset2)
956                 return true;
957             byte[] buffer = this.buffer;
958             for (int i = 0; i < length1; i++)
959             {
960                 if (buffer[offset1 + i] != buffer[offset2 + i])
961                     return false;
962             }
963             return true;
964         }
965 
966         [Fx.Tag.SecurityNote(Critical = "Contains unsafe code.",
967             Safe = "Unsafe code is effectively encapsulated, all inputs are validated.")]
968         [SecuritySafeCritical]
Equals2(int offset1, int length1, string s2)969         unsafe public bool Equals2(int offset1, int length1, string s2)
970         {
971             int byteLength = length1;
972             int charLength = s2.Length;
973 
974             // N unicode chars will be represented in at least N bytes, but
975             // no more than N * 3 bytes.  If the byte count falls outside of this
976             // range, then the strings cannot be equal.
977             if (byteLength < charLength || byteLength > charLength * maxBytesPerChar)
978                 return false;
979 
980             byte[] buffer = this.buffer;
981             if (length1 < 8)
982             {
983                 int length = Math.Min(byteLength, charLength);
984                 int offset = offset1;
985                 for (int i = 0; i < length; i++)
986                 {
987                     byte b = buffer[offset + i];
988                     if (b >= 0x80)
989                         return XmlConverter.ToString(buffer, offset1, length1) == s2;
990                     if (s2[i] != (char)b)
991                         return false;
992                 }
993                 return byteLength == charLength;
994             }
995             else
996             {
997                 int length = Math.Min(byteLength, charLength);
998                 fixed (byte* _pb = &buffer[offset1])
999                 {
1000                     byte* pb = _pb;
1001                     byte* pbMax = pb + length;
1002                     fixed (char* _pch = s2)
1003                     {
1004                         char* pch = _pch;
1005                         // Try to do the fast comparison in ascii space
1006                         int t = 0;
1007                         while (pb < pbMax && *pb < 0x80)
1008                         {
1009                             t = *pb - (byte)(*pch);
1010                             // The code generated is better if we break out then return
1011                             if (t != 0)
1012                                 break;
1013                             pb++;
1014                             pch++;
1015                         }
1016                         if (t != 0)
1017                             return false;
1018                         if (pb == pbMax)
1019                             return (byteLength == charLength);
1020                     }
1021                 }
1022                 return XmlConverter.ToString(buffer, offset1, length1) == s2;
1023             }
1024         }
1025 
Compare(int offset1, int length1, int offset2, int length2)1026         public int Compare(int offset1, int length1, int offset2, int length2)
1027         {
1028             byte[] buffer = this.buffer;
1029             int length = Math.Min(length1, length2);
1030             for (int i = 0; i < length; i++)
1031             {
1032                 int s = buffer[offset1 + i] - buffer[offset2 + i];
1033                 if (s != 0)
1034                     return s;
1035             }
1036             return length1 - length2;
1037         }
1038 
GetByte(int offset)1039         public byte GetByte(int offset)
1040         {
1041             return buffer[offset];
1042         }
1043 
GetInt8(int offset)1044         public int GetInt8(int offset)
1045         {
1046             return (sbyte)GetByte(offset);
1047         }
1048 
GetInt16(int offset)1049         public int GetInt16(int offset)
1050         {
1051             byte[] buffer = this.buffer;
1052             return (Int16)(buffer[offset] + (buffer[offset + 1] << 8));
1053         }
1054 
GetInt32(int offset)1055         public int GetInt32(int offset)
1056         {
1057             byte[] buffer = this.buffer;
1058             byte b1 = buffer[offset + 0];
1059             byte b2 = buffer[offset + 1];
1060             byte b3 = buffer[offset + 2];
1061             byte b4 = buffer[offset + 3];
1062             return (((((b4 << 8) + b3) << 8) + b2) << 8) + b1;
1063         }
1064 
GetInt64(int offset)1065         public long GetInt64(int offset)
1066         {
1067             byte[] buffer = this.buffer;
1068             byte b1, b2, b3, b4;
1069             b1 = buffer[offset + 0];
1070             b2 = buffer[offset + 1];
1071             b3 = buffer[offset + 2];
1072             b4 = buffer[offset + 3];
1073             Int64 lo = (UInt32)(((((b4 << 8) + b3) << 8) + b2) << 8) + b1;
1074             b1 = buffer[offset + 4];
1075             b2 = buffer[offset + 5];
1076             b3 = buffer[offset + 6];
1077             b4 = buffer[offset + 7];
1078             Int64 hi = (UInt32)(((((b4 << 8) + b3) << 8) + b2) << 8) + b1;
1079             return (hi << 32) + lo;
1080         }
1081 
GetUInt64(int offset)1082         public ulong GetUInt64(int offset)
1083         {
1084             return (ulong)GetInt64(offset);
1085         }
1086 
1087         [Fx.Tag.SecurityNote(Critical = "Contains unsafe code.",
1088             Safe = "Unsafe code is effectively encapsulated, all inputs are validated.")]
1089         [SecuritySafeCritical]
GetSingle(int offset)1090         unsafe public float GetSingle(int offset)
1091         {
1092             byte[] buffer = this.buffer;
1093             float value;
1094             byte* pb = (byte*)&value;
1095             Fx.Assert(sizeof(float) == 4, "");
1096             pb[0] = buffer[offset + 0];
1097             pb[1] = buffer[offset + 1];
1098             pb[2] = buffer[offset + 2];
1099             pb[3] = buffer[offset + 3];
1100             return value;
1101         }
1102 
1103         [Fx.Tag.SecurityNote(Critical = "Contains unsafe code.",
1104             Safe = "Unsafe code is effectively encapsulated, all inputs are validated.")]
1105         [SecuritySafeCritical]
GetDouble(int offset)1106         unsafe public double GetDouble(int offset)
1107         {
1108             byte[] buffer = this.buffer;
1109             double value;
1110             byte* pb = (byte*)&value;
1111             Fx.Assert(sizeof(double) == 8, "");
1112             pb[0] = buffer[offset + 0];
1113             pb[1] = buffer[offset + 1];
1114             pb[2] = buffer[offset + 2];
1115             pb[3] = buffer[offset + 3];
1116             pb[4] = buffer[offset + 4];
1117             pb[5] = buffer[offset + 5];
1118             pb[6] = buffer[offset + 6];
1119             pb[7] = buffer[offset + 7];
1120             return value;
1121         }
1122 
1123         [Fx.Tag.SecurityNote(Critical = "Contains unsafe code.",
1124             Safe = "Unsafe code is effectively encapsulated, all inputs are validated.")]
1125         [SecuritySafeCritical]
GetDecimal(int offset)1126         public unsafe decimal GetDecimal(int offset)
1127         {
1128             const int SignMask = unchecked((int)0x80000000);
1129             const int ScaleMask = 0x00FF0000;
1130 
1131             byte[] buffer = this.buffer;
1132             byte b1 = buffer[offset + 0];
1133             byte b2 = buffer[offset + 1];
1134             byte b3 = buffer[offset + 2];
1135             byte b4 = buffer[offset + 3];
1136             int flags = (((((b4 << 8) + b3) << 8) + b2) << 8) + b1;
1137 
1138             //this logic mirrors the code in Decimal(int []) ctor.
1139             if ((flags & ~(SignMask | ScaleMask)) == 0 && (flags & ScaleMask) <= (28 << 16))
1140             {
1141                 decimal value;
1142                 byte* pb = (byte*)&value;
1143                 for (int i = 0; i < sizeof(decimal); i++)
1144                     pb[i] = buffer[offset + i];
1145                 return value;
1146             }
1147             else
1148             {
1149                 XmlExceptionHelper.ThrowInvalidBinaryFormat(this.reader);
1150             }
1151 
1152             //compiler doesn't know that XmlExceptionHelper.ThrowInvalidBinaryFormat always throws,
1153             //so we have to have a return statement here even though we shouldn't hit this code path...
1154             Fx.Assert("A decimal value should have been returned or an exception should have been thrown.");
1155             return default(decimal);
1156         }
1157 
GetUniqueId(int offset)1158         public UniqueId GetUniqueId(int offset)
1159         {
1160             return new UniqueId(this.buffer, offset);
1161         }
1162 
GetGuid(int offset)1163         public Guid GetGuid(int offset)
1164         {
1165             if (guid == null)
1166                 guid = new byte[16];
1167             System.Buffer.BlockCopy(buffer, offset, guid, 0, guid.Length);
1168             return new Guid(guid);
1169         }
1170 
GetBase64(int srcOffset, byte[] buffer, int dstOffset, int count)1171         public void GetBase64(int srcOffset, byte[] buffer, int dstOffset, int count)
1172         {
1173             System.Buffer.BlockCopy(this.buffer, srcOffset, buffer, dstOffset, count);
1174         }
1175 
GetNodeType()1176         public XmlBinaryNodeType GetNodeType()
1177         {
1178             return (XmlBinaryNodeType)GetByte();
1179         }
1180 
SkipNodeType()1181         public void SkipNodeType()
1182         {
1183             SkipByte();
1184         }
1185 
GetList(int offset, int count)1186         public object[] GetList(int offset, int count)
1187         {
1188             int bufferOffset = this.Offset;
1189             this.Offset = offset;
1190             try
1191             {
1192                 object[] objects = new object[count];
1193                 for (int i = 0; i < count; i++)
1194                 {
1195                     XmlBinaryNodeType nodeType = GetNodeType();
1196                     SkipNodeType();
1197                     Fx.Assert(nodeType != XmlBinaryNodeType.StartListText, "");
1198                     ReadValue(nodeType, listValue);
1199                     objects[i] = listValue.ToObject();
1200                 }
1201                 return objects;
1202             }
1203             finally
1204             {
1205                 this.Offset = bufferOffset;
1206             }
1207         }
1208 
GetDictionaryString(int key)1209         public XmlDictionaryString GetDictionaryString(int key)
1210         {
1211             IXmlDictionary keyDictionary;
1212             if ((key & 1) != 0)
1213             {
1214                 keyDictionary = session;
1215             }
1216             else
1217             {
1218                 keyDictionary = dictionary;
1219             }
1220             XmlDictionaryString s;
1221             if (!keyDictionary.TryLookup(key >> 1, out s))
1222                 XmlExceptionHelper.ThrowInvalidBinaryFormat(reader);
1223             return s;
1224         }
1225 
ReadDictionaryKey()1226         public int ReadDictionaryKey()
1227         {
1228             int key = ReadMultiByteUInt31();
1229             if ((key & 1) != 0)
1230             {
1231                 if (session == null)
1232                     XmlExceptionHelper.ThrowInvalidBinaryFormat(reader);
1233                 int sessionKey = (key >> 1);
1234                 XmlDictionaryString xmlString;
1235                 if (!session.TryLookup(sessionKey, out xmlString))
1236                 {
1237                     if (sessionKey < XmlDictionaryString.MinKey || sessionKey > XmlDictionaryString.MaxKey)
1238                         XmlExceptionHelper.ThrowXmlDictionaryStringIDOutOfRange(this.reader);
1239                     XmlExceptionHelper.ThrowXmlDictionaryStringIDUndefinedSession(this.reader, sessionKey);
1240                 }
1241             }
1242             else
1243             {
1244                 if (dictionary == null)
1245                     XmlExceptionHelper.ThrowInvalidBinaryFormat(reader);
1246                 int staticKey = (key >> 1);
1247                 XmlDictionaryString xmlString;
1248                 if (!dictionary.TryLookup(staticKey, out xmlString))
1249                 {
1250                     if (staticKey < XmlDictionaryString.MinKey || staticKey > XmlDictionaryString.MaxKey)
1251                         XmlExceptionHelper.ThrowXmlDictionaryStringIDOutOfRange(this.reader);
1252                     XmlExceptionHelper.ThrowXmlDictionaryStringIDUndefinedStatic(this.reader, staticKey);
1253                 }
1254             }
1255 
1256             return key;
1257         }
1258 
ReadValue(XmlBinaryNodeType nodeType, ValueHandle value)1259         public void ReadValue(XmlBinaryNodeType nodeType, ValueHandle value)
1260         {
1261             switch (nodeType)
1262             {
1263                 case XmlBinaryNodeType.EmptyText:
1264                     value.SetValue(ValueHandleType.Empty);
1265                     break;
1266                 case XmlBinaryNodeType.ZeroText:
1267                     value.SetValue(ValueHandleType.Zero);
1268                     break;
1269                 case XmlBinaryNodeType.OneText:
1270                     value.SetValue(ValueHandleType.One);
1271                     break;
1272                 case XmlBinaryNodeType.TrueText:
1273                     value.SetValue(ValueHandleType.True);
1274                     break;
1275                 case XmlBinaryNodeType.FalseText:
1276                     value.SetValue(ValueHandleType.False);
1277                     break;
1278                 case XmlBinaryNodeType.BoolText:
1279                     value.SetValue(ReadUInt8() != 0 ? ValueHandleType.True : ValueHandleType.False);
1280                     break;
1281                 case XmlBinaryNodeType.Chars8Text:
1282                     ReadValue(value, ValueHandleType.UTF8, ReadUInt8());
1283                     break;
1284                 case XmlBinaryNodeType.Chars16Text:
1285                     ReadValue(value, ValueHandleType.UTF8, ReadUInt16());
1286                     break;
1287                 case XmlBinaryNodeType.Chars32Text:
1288                     ReadValue(value, ValueHandleType.UTF8, ReadUInt31());
1289                     break;
1290                 case XmlBinaryNodeType.UnicodeChars8Text:
1291                     ReadUnicodeValue(value, ReadUInt8());
1292                     break;
1293                 case XmlBinaryNodeType.UnicodeChars16Text:
1294                     ReadUnicodeValue(value, ReadUInt16());
1295                     break;
1296                 case XmlBinaryNodeType.UnicodeChars32Text:
1297                     ReadUnicodeValue(value, ReadUInt31());
1298                     break;
1299                 case XmlBinaryNodeType.Bytes8Text:
1300                     ReadValue(value, ValueHandleType.Base64, ReadUInt8());
1301                     break;
1302                 case XmlBinaryNodeType.Bytes16Text:
1303                     ReadValue(value, ValueHandleType.Base64, ReadUInt16());
1304                     break;
1305                 case XmlBinaryNodeType.Bytes32Text:
1306                     ReadValue(value, ValueHandleType.Base64, ReadUInt31());
1307                     break;
1308                 case XmlBinaryNodeType.DictionaryText:
1309                     value.SetDictionaryValue(ReadDictionaryKey());
1310                     break;
1311                 case XmlBinaryNodeType.UniqueIdText:
1312                     ReadValue(value, ValueHandleType.UniqueId, ValueHandleLength.UniqueId);
1313                     break;
1314                 case XmlBinaryNodeType.GuidText:
1315                     ReadValue(value, ValueHandleType.Guid, ValueHandleLength.Guid);
1316                     break;
1317                 case XmlBinaryNodeType.DecimalText:
1318                     ReadValue(value, ValueHandleType.Decimal, ValueHandleLength.Decimal);
1319                     break;
1320                 case XmlBinaryNodeType.Int8Text:
1321                     ReadValue(value, ValueHandleType.Int8, ValueHandleLength.Int8);
1322                     break;
1323                 case XmlBinaryNodeType.Int16Text:
1324                     ReadValue(value, ValueHandleType.Int16, ValueHandleLength.Int16);
1325                     break;
1326                 case XmlBinaryNodeType.Int32Text:
1327                     ReadValue(value, ValueHandleType.Int32, ValueHandleLength.Int32);
1328                     break;
1329                 case XmlBinaryNodeType.Int64Text:
1330                     ReadValue(value, ValueHandleType.Int64, ValueHandleLength.Int64);
1331                     break;
1332                 case XmlBinaryNodeType.UInt64Text:
1333                     ReadValue(value, ValueHandleType.UInt64, ValueHandleLength.UInt64);
1334                     break;
1335                 case XmlBinaryNodeType.FloatText:
1336                     ReadValue(value, ValueHandleType.Single, ValueHandleLength.Single);
1337                     break;
1338                 case XmlBinaryNodeType.DoubleText:
1339                     ReadValue(value, ValueHandleType.Double, ValueHandleLength.Double);
1340                     break;
1341                 case XmlBinaryNodeType.TimeSpanText:
1342                     ReadValue(value, ValueHandleType.TimeSpan, ValueHandleLength.TimeSpan);
1343                     break;
1344                 case XmlBinaryNodeType.DateTimeText:
1345                     ReadValue(value, ValueHandleType.DateTime, ValueHandleLength.DateTime);
1346                     break;
1347                 case XmlBinaryNodeType.StartListText:
1348                     ReadList(value);
1349                     break;
1350                 case XmlBinaryNodeType.QNameDictionaryText:
1351                     ReadQName(value);
1352                     break;
1353                 default:
1354                     XmlExceptionHelper.ThrowInvalidBinaryFormat(reader);
1355                     break;
1356             }
1357         }
1358 
ReadValue(ValueHandle value, ValueHandleType type, int length)1359         void ReadValue(ValueHandle value, ValueHandleType type, int length)
1360         {
1361             int offset = ReadBytes(length);
1362             value.SetValue(type, offset, length);
1363         }
1364 
ReadUnicodeValue(ValueHandle value, int length)1365         void ReadUnicodeValue(ValueHandle value, int length)
1366         {
1367             if ((length & 1) != 0)
1368                 XmlExceptionHelper.ThrowInvalidBinaryFormat(reader);
1369             ReadValue(value, ValueHandleType.Unicode, length);
1370         }
1371 
ReadList(ValueHandle value)1372         void ReadList(ValueHandle value)
1373         {
1374             if (listValue == null)
1375             {
1376                 listValue = new ValueHandle(this);
1377             }
1378             int count = 0;
1379             int offset = this.Offset;
1380             while (true)
1381             {
1382                 XmlBinaryNodeType nodeType = GetNodeType();
1383                 SkipNodeType();
1384                 if (nodeType == XmlBinaryNodeType.StartListText)
1385                     XmlExceptionHelper.ThrowInvalidBinaryFormat(reader);
1386                 if (nodeType == XmlBinaryNodeType.EndListText)
1387                     break;
1388                 ReadValue(nodeType, listValue);
1389                 count++;
1390             }
1391             value.SetValue(ValueHandleType.List, offset, count);
1392         }
1393 
ReadQName(ValueHandle value)1394         public void ReadQName(ValueHandle value)
1395         {
1396             int prefix = ReadUInt8();
1397             if (prefix >= 26)
1398                 XmlExceptionHelper.ThrowInvalidBinaryFormat(reader);
1399             int key = ReadDictionaryKey();
1400             value.SetQNameValue(prefix, key);
1401         }
1402 
GetRows()1403         public int[] GetRows()
1404         {
1405             if (buffer == null)
1406             {
1407                 return new int[1] { 0 };
1408             }
1409 
1410             ArrayList list = new ArrayList();
1411             list.Add(offsetMin);
1412             for (int i = offsetMin; i < offsetMax; i++)
1413             {
1414                 if (buffer[i] == (byte)13 || buffer[i] == (byte)10)
1415                 {
1416                     if (i + 1 < offsetMax && buffer[i + 1] == (byte)10)
1417                         i++;
1418                     list.Add(i + 1);
1419                 }
1420             }
1421             return (int[])list.ToArray(typeof(int));
1422         }
1423     }
1424 }
1425