1 #region License
2 // Copyright (c) 2007 James Newton-King
3 //
4 // Permission is hereby granted, free of charge, to any person
5 // obtaining a copy of this software and associated documentation
6 // files (the "Software"), to deal in the Software without
7 // restriction, including without limitation the rights to use,
8 // copy, modify, merge, publish, distribute, sublicense, and/or sell
9 // copies of the Software, and to permit persons to whom the
10 // Software is furnished to do so, subject to the following
11 // conditions:
12 //
13 // The above copyright notice and this permission notice shall be
14 // included in all copies or substantial portions of the Software.
15 //
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
18 // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20 // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21 // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 // OTHER DEALINGS IN THE SOFTWARE.
24 #endregion
25 
26 using System;
27 using System.Collections.Generic;
28 using System.Globalization;
29 using System.Text;
30 using System.IO;
31 using Newtonsoft.Json.Utilities;
32 using Newtonsoft.Json.Linq;
33 
34 namespace Newtonsoft.Json.Bson
35 {
36   /// <summary>
37   /// Represents a reader that provides fast, non-cached, forward-only access to serialized Json data.
38   /// </summary>
39   public class BsonReader : JsonReader
40   {
41     private const int MaxCharBytesSize = 128;
42     private static readonly byte[] SeqRange1 = new byte[] {0, 127}; // range of 1-byte sequence
43     private static readonly byte[] SeqRange2 = new byte[] {194, 223}; // range of 2-byte sequence
44     private static readonly byte[] SeqRange3 = new byte[] {224, 239}; // range of 3-byte sequence
45     private static readonly byte[] SeqRange4 = new byte[] {240, 244}; // range of 4-byte sequence
46 
47     private readonly BinaryReader _reader;
48     private readonly List<ContainerContext> _stack;
49 
50     private byte[] _byteBuffer;
51     private char[] _charBuffer;
52 
53     private BsonType _currentElementType;
54     private BsonReaderState _bsonReaderState;
55     private ContainerContext _currentContext;
56 
57     private bool _readRootValueAsArray;
58     private bool _jsonNet35BinaryCompatibility;
59     private DateTimeKind _dateTimeKindHandling;
60 
61     private enum BsonReaderState
62     {
63       Normal,
64       ReferenceStart,
65       ReferenceRef,
66       ReferenceId,
67       CodeWScopeStart,
68       CodeWScopeCode,
69       CodeWScopeScope,
70       CodeWScopeScopeObject,
71       CodeWScopeScopeEnd
72     }
73 
74     private class ContainerContext
75     {
76       public readonly BsonType Type;
77       public int Length;
78       public int Position;
79 
ContainerContext(BsonType type)80       public ContainerContext(BsonType type)
81       {
82         Type = type;
83       }
84     }
85 
86     /// <summary>
87     /// Gets or sets a value indicating whether binary data reading should compatible with incorrect Json.NET 3.5 written binary.
88     /// </summary>
89     /// <value>
90     /// 	<c>true</c> if binary data reading will be compatible with incorrect Json.NET 3.5 written binary; otherwise, <c>false</c>.
91     /// </value>
92     public bool JsonNet35BinaryCompatibility
93     {
94       get { return _jsonNet35BinaryCompatibility; }
95       set { _jsonNet35BinaryCompatibility = value; }
96     }
97 
98     /// <summary>
99     /// Gets or sets a value indicating whether the root object will be read as a JSON array.
100     /// </summary>
101     /// <value>
102     /// 	<c>true</c> if the root object will be read as a JSON array; otherwise, <c>false</c>.
103     /// </value>
104     public bool ReadRootValueAsArray
105     {
106       get { return _readRootValueAsArray; }
107       set { _readRootValueAsArray = value; }
108     }
109 
110     /// <summary>
111     /// Gets or sets the <see cref="DateTimeKind" /> used when reading <see cref="DateTime"/> values from BSON.
112     /// </summary>
113     /// <value>The <see cref="DateTimeKind" /> used when reading <see cref="DateTime"/> values from BSON.</value>
114     public DateTimeKind DateTimeKindHandling
115     {
116       get { return _dateTimeKindHandling; }
117       set { _dateTimeKindHandling = value; }
118     }
119 
120     /// <summary>
121     /// Initializes a new instance of the <see cref="BsonReader"/> class.
122     /// </summary>
123     /// <param name="stream">The stream.</param>
BsonReader(Stream stream)124     public BsonReader(Stream stream)
125       : this(stream, false, DateTimeKind.Local)
126     {
127     }
128 
129     /// <summary>
130     /// Initializes a new instance of the <see cref="BsonReader"/> class.
131     /// </summary>
132     /// <param name="reader">The reader.</param>
BsonReader(BinaryReader reader)133     public BsonReader(BinaryReader reader)
134       : this(reader, false, DateTimeKind.Local)
135     {
136     }
137 
138     /// <summary>
139     /// Initializes a new instance of the <see cref="BsonReader"/> class.
140     /// </summary>
141     /// <param name="stream">The stream.</param>
142     /// <param name="readRootValueAsArray">if set to <c>true</c> the root object will be read as a JSON array.</param>
143     /// <param name="dateTimeKindHandling">The <see cref="DateTimeKind" /> used when reading <see cref="DateTime"/> values from BSON.</param>
BsonReader(Stream stream, bool readRootValueAsArray, DateTimeKind dateTimeKindHandling)144     public BsonReader(Stream stream, bool readRootValueAsArray, DateTimeKind dateTimeKindHandling)
145     {
146       ValidationUtils.ArgumentNotNull(stream, "stream");
147       _reader = new BinaryReader(stream);
148       _stack = new List<ContainerContext>();
149       _readRootValueAsArray = readRootValueAsArray;
150       _dateTimeKindHandling = dateTimeKindHandling;
151     }
152 
153     /// <summary>
154     /// Initializes a new instance of the <see cref="BsonReader"/> class.
155     /// </summary>
156     /// <param name="reader">The reader.</param>
157     /// <param name="readRootValueAsArray">if set to <c>true</c> the root object will be read as a JSON array.</param>
158     /// <param name="dateTimeKindHandling">The <see cref="DateTimeKind" /> used when reading <see cref="DateTime"/> values from BSON.</param>
BsonReader(BinaryReader reader, bool readRootValueAsArray, DateTimeKind dateTimeKindHandling)159     public BsonReader(BinaryReader reader, bool readRootValueAsArray, DateTimeKind dateTimeKindHandling)
160     {
161       ValidationUtils.ArgumentNotNull(reader, "reader");
162       _reader = reader;
163       _stack = new List<ContainerContext>();
164       _readRootValueAsArray = readRootValueAsArray;
165       _dateTimeKindHandling = dateTimeKindHandling;
166     }
167 
ReadElement()168     private string ReadElement()
169     {
170       _currentElementType = ReadType();
171       string elementName = ReadString();
172       return elementName;
173     }
174 
175     /// <summary>
176     /// Reads the next JSON token from the stream as a <see cref="T:Byte[]"/>.
177     /// </summary>
178     /// <returns>
179     /// A <see cref="T:Byte[]"/> or a null reference if the next JSON token is null. This method will return <c>null</c> at the end of an array.
180     /// </returns>
ReadAsBytes()181     public override byte[] ReadAsBytes()
182     {
183       return ReadAsBytesInternal();
184     }
185 
186     /// <summary>
187     /// Reads the next JSON token from the stream as a <see cref="Nullable{Decimal}"/>.
188     /// </summary>
189     /// <returns>A <see cref="Nullable{Decimal}"/>. This method will return <c>null</c> at the end of an array.</returns>
ReadAsDecimal()190     public override decimal? ReadAsDecimal()
191     {
192       return ReadAsDecimalInternal();
193     }
194 
195     /// <summary>
196     /// Reads the next JSON token from the stream as a <see cref="Nullable{Int32}"/>.
197     /// </summary>
198     /// <returns>A <see cref="Nullable{Int32}"/>. This method will return <c>null</c> at the end of an array.</returns>
ReadAsInt32()199     public override int? ReadAsInt32()
200     {
201       return ReadAsInt32Internal();
202     }
203 
204     /// <summary>
205     /// Reads the next JSON token from the stream as a <see cref="String"/>.
206     /// </summary>
207     /// <returns>A <see cref="String"/>. This method will return <c>null</c> at the end of an array.</returns>
ReadAsString()208     public override string ReadAsString()
209     {
210       return ReadAsStringInternal();
211     }
212 
213     /// <summary>
214     /// Reads the next JSON token from the stream as a <see cref="Nullable{DateTime}"/>.
215     /// </summary>
216     /// <returns>A <see cref="String"/>. This method will return <c>null</c> at the end of an array.</returns>
ReadAsDateTime()217     public override DateTime? ReadAsDateTime()
218     {
219       return ReadAsDateTimeInternal();
220     }
221 
222 #if !NET20
223     /// <summary>
224     /// Reads the next JSON token from the stream as a <see cref="Nullable{DateTimeOffset}"/>.
225     /// </summary>
226     /// <returns>
227     /// A <see cref="Nullable{DateTimeOffset}"/>. This method will return <c>null</c> at the end of an array.
228     /// </returns>
ReadAsDateTimeOffset()229     public override DateTimeOffset? ReadAsDateTimeOffset()
230     {
231       return ReadAsDateTimeOffsetInternal();
232     }
233 #endif
234 
235     /// <summary>
236     /// Reads the next JSON token from the stream.
237     /// </summary>
238     /// <returns>
239     /// true if the next token was read successfully; false if there are no more tokens to read.
240     /// </returns>
Read()241     public override bool Read()
242     {
243       _readType = Json.ReadType.Read;
244 
245       return ReadInternal();
246     }
247 
ReadInternal()248     internal override bool ReadInternal()
249     {
250       try
251       {
252         bool success;
253 
254         switch (_bsonReaderState)
255         {
256           case BsonReaderState.Normal:
257             success = ReadNormal();
258             break;
259           case BsonReaderState.ReferenceStart:
260           case BsonReaderState.ReferenceRef:
261           case BsonReaderState.ReferenceId:
262             success = ReadReference();
263             break;
264           case BsonReaderState.CodeWScopeStart:
265           case BsonReaderState.CodeWScopeCode:
266           case BsonReaderState.CodeWScopeScope:
267           case BsonReaderState.CodeWScopeScopeObject:
268           case BsonReaderState.CodeWScopeScopeEnd:
269             success = ReadCodeWScope();
270             break;
271           default:
272             throw JsonReaderException.Create(this, "Unexpected state: {0}".FormatWith(CultureInfo.InvariantCulture, _bsonReaderState));
273         }
274 
275         if (!success)
276         {
277           SetToken(JsonToken.None);
278           return false;
279         }
280 
281         return true;
282       }
283       catch (EndOfStreamException)
284       {
285         SetToken(JsonToken.None);
286         return false;
287       }
288     }
289 
290     /// <summary>
291     /// Changes the <see cref="JsonReader.State"/> to Closed.
292     /// </summary>
Close()293     public override void Close()
294     {
295       base.Close();
296 
297       if (CloseInput && _reader != null)
298 #if !(NETFX_CORE || PORTABLE)
299         _reader.Close();
300 #else
301         _reader.Dispose();
302 #endif
303     }
304 
ReadCodeWScope()305     private bool ReadCodeWScope()
306     {
307       switch (_bsonReaderState)
308       {
309         case BsonReaderState.CodeWScopeStart:
310           SetToken(JsonToken.PropertyName, "$code");
311           _bsonReaderState = BsonReaderState.CodeWScopeCode;
312           return true;
313         case BsonReaderState.CodeWScopeCode:
314           // total CodeWScope size - not used
315           ReadInt32();
316 
317           SetToken(JsonToken.String, ReadLengthString());
318           _bsonReaderState = BsonReaderState.CodeWScopeScope;
319           return true;
320         case BsonReaderState.CodeWScopeScope:
321           if (CurrentState == State.PostValue)
322           {
323             SetToken(JsonToken.PropertyName, "$scope");
324             return true;
325           }
326           else
327           {
328             SetToken(JsonToken.StartObject);
329             _bsonReaderState = BsonReaderState.CodeWScopeScopeObject;
330 
331             ContainerContext newContext = new ContainerContext(BsonType.Object);
332             PushContext(newContext);
333             newContext.Length = ReadInt32();
334 
335             return true;
336           }
337         case BsonReaderState.CodeWScopeScopeObject:
338           bool result = ReadNormal();
339           if (result && TokenType == JsonToken.EndObject)
340             _bsonReaderState = BsonReaderState.CodeWScopeScopeEnd;
341 
342           return result;
343         case BsonReaderState.CodeWScopeScopeEnd:
344           SetToken(JsonToken.EndObject);
345           _bsonReaderState = BsonReaderState.Normal;
346           return true;
347         default:
348           throw new ArgumentOutOfRangeException();
349       }
350     }
351 
ReadReference()352     private bool ReadReference()
353     {
354       switch (CurrentState)
355       {
356         case State.ObjectStart:
357           {
358             SetToken(JsonToken.PropertyName, "$ref");
359             _bsonReaderState = BsonReaderState.ReferenceRef;
360             return true;
361           }
362         case State.Property:
363           {
364             if (_bsonReaderState == BsonReaderState.ReferenceRef)
365             {
366               SetToken(JsonToken.String, ReadLengthString());
367               return true;
368             }
369             else if (_bsonReaderState == BsonReaderState.ReferenceId)
370             {
371               SetToken(JsonToken.Bytes, ReadBytes(12));
372               return true;
373             }
374             else
375             {
376               throw JsonReaderException.Create(this, "Unexpected state when reading BSON reference: " + _bsonReaderState);
377             }
378           }
379         case State.PostValue:
380           {
381             if (_bsonReaderState == BsonReaderState.ReferenceRef)
382             {
383               SetToken(JsonToken.PropertyName, "$id");
384               _bsonReaderState = BsonReaderState.ReferenceId;
385               return true;
386             }
387             else if (_bsonReaderState == BsonReaderState.ReferenceId)
388             {
389               SetToken(JsonToken.EndObject);
390               _bsonReaderState = BsonReaderState.Normal;
391               return true;
392             }
393             else
394             {
395               throw JsonReaderException.Create(this, "Unexpected state when reading BSON reference: " + _bsonReaderState);
396             }
397           }
398         default:
399           throw JsonReaderException.Create(this, "Unexpected state when reading BSON reference: " + CurrentState);
400       }
401     }
402 
ReadNormal()403     private bool ReadNormal()
404     {
405       switch (CurrentState)
406       {
407         case State.Start:
408           {
409             JsonToken token = (!_readRootValueAsArray) ? JsonToken.StartObject : JsonToken.StartArray;
410             BsonType type = (!_readRootValueAsArray) ? BsonType.Object : BsonType.Array;
411 
412             SetToken(token);
413             ContainerContext newContext = new ContainerContext(type);
414             PushContext(newContext);
415             newContext.Length = ReadInt32();
416             return true;
417           }
418         case State.Complete:
419         case State.Closed:
420           return false;
421         case State.Property:
422           {
423             ReadType(_currentElementType);
424             return true;
425           }
426         case State.ObjectStart:
427         case State.ArrayStart:
428         case State.PostValue:
429           ContainerContext context = _currentContext;
430           if (context == null)
431             return false;
432 
433           int lengthMinusEnd = context.Length - 1;
434 
435           if (context.Position < lengthMinusEnd)
436           {
437             if (context.Type == BsonType.Array)
438             {
439               ReadElement();
440               ReadType(_currentElementType);
441               return true;
442             }
443             else
444             {
445               SetToken(JsonToken.PropertyName, ReadElement());
446               return true;
447             }
448           }
449           else if (context.Position == lengthMinusEnd)
450           {
451             if (ReadByte() != 0)
452               throw JsonReaderException.Create(this, "Unexpected end of object byte value.");
453 
454             PopContext();
455             if (_currentContext != null)
456               MovePosition(context.Length);
457 
458             JsonToken endToken = (context.Type == BsonType.Object) ? JsonToken.EndObject : JsonToken.EndArray;
459             SetToken(endToken);
460             return true;
461           }
462           else
463           {
464             throw JsonReaderException.Create(this, "Read past end of current container context.");
465           }
466         case State.ConstructorStart:
467           break;
468         case State.Constructor:
469           break;
470         case State.Error:
471           break;
472         case State.Finished:
473           break;
474         default:
475           throw new ArgumentOutOfRangeException();
476       }
477 
478       return false;
479     }
480 
PopContext()481     private void PopContext()
482     {
483       _stack.RemoveAt(_stack.Count - 1);
484       if (_stack.Count == 0)
485         _currentContext = null;
486       else
487         _currentContext = _stack[_stack.Count - 1];
488     }
489 
PushContext(ContainerContext newContext)490     private void PushContext(ContainerContext newContext)
491     {
492       _stack.Add(newContext);
493       _currentContext = newContext;
494     }
495 
ReadByte()496     private byte ReadByte()
497     {
498       MovePosition(1);
499       return _reader.ReadByte();
500     }
501 
ReadType(BsonType type)502     private void ReadType(BsonType type)
503     {
504       switch (type)
505       {
506         case BsonType.Number:
507           SetToken(JsonToken.Float, ReadDouble());
508           break;
509         case BsonType.String:
510         case BsonType.Symbol:
511           SetToken(JsonToken.String, ReadLengthString());
512           break;
513         case BsonType.Object:
514           {
515             SetToken(JsonToken.StartObject);
516 
517             ContainerContext newContext = new ContainerContext(BsonType.Object);
518             PushContext(newContext);
519             newContext.Length = ReadInt32();
520             break;
521           }
522         case BsonType.Array:
523           {
524             SetToken(JsonToken.StartArray);
525 
526             ContainerContext newContext = new ContainerContext(BsonType.Array);
527             PushContext(newContext);
528             newContext.Length = ReadInt32();
529             break;
530           }
531         case BsonType.Binary:
532           SetToken(JsonToken.Bytes, ReadBinary());
533           break;
534         case BsonType.Undefined:
535           SetToken(JsonToken.Undefined);
536           break;
537         case BsonType.Oid:
538           byte[] oid = ReadBytes(12);
539           SetToken(JsonToken.Bytes, oid);
540           break;
541         case BsonType.Boolean:
542           bool b = Convert.ToBoolean(ReadByte());
543           SetToken(JsonToken.Boolean, b);
544           break;
545         case BsonType.Date:
546           long ticks = ReadInt64();
547           DateTime utcDateTime = JsonConvert.ConvertJavaScriptTicksToDateTime(ticks);
548 
549           DateTime dateTime;
550           switch (DateTimeKindHandling)
551           {
552             case DateTimeKind.Unspecified:
553               dateTime = DateTime.SpecifyKind(utcDateTime, DateTimeKind.Unspecified);
554               break;
555             case DateTimeKind.Local:
556               dateTime = utcDateTime.ToLocalTime();
557               break;
558             default:
559               dateTime = utcDateTime;
560               break;
561           }
562 
563           SetToken(JsonToken.Date, dateTime);
564           break;
565         case BsonType.Null:
566           SetToken(JsonToken.Null);
567           break;
568         case BsonType.Regex:
569           string expression = ReadString();
570           string modifiers = ReadString();
571 
572           string regex = @"/" + expression + @"/" + modifiers;
573           SetToken(JsonToken.String, regex);
574           break;
575         case BsonType.Reference:
576           SetToken(JsonToken.StartObject);
577           _bsonReaderState = BsonReaderState.ReferenceStart;
578           break;
579         case BsonType.Code:
580           SetToken(JsonToken.String, ReadLengthString());
581           break;
582         case BsonType.CodeWScope:
583           SetToken(JsonToken.StartObject);
584           _bsonReaderState = BsonReaderState.CodeWScopeStart;
585           break;
586         case BsonType.Integer:
587           SetToken(JsonToken.Integer, (long) ReadInt32());
588           break;
589         case BsonType.TimeStamp:
590         case BsonType.Long:
591           SetToken(JsonToken.Integer, ReadInt64());
592           break;
593         default:
594           throw new ArgumentOutOfRangeException("type", "Unexpected BsonType value: " + type);
595       }
596     }
597 
ReadBinary()598     private byte[] ReadBinary()
599     {
600       int dataLength = ReadInt32();
601 
602       BsonBinaryType binaryType = (BsonBinaryType) ReadByte();
603 
604 #pragma warning disable 612,618
605       // the old binary type has the data length repeated in the data for some reason
606       if (binaryType == BsonBinaryType.Data && !_jsonNet35BinaryCompatibility)
607       {
608         dataLength = ReadInt32();
609       }
610 #pragma warning restore 612,618
611 
612       return ReadBytes(dataLength);
613     }
614 
ReadString()615     private string ReadString()
616     {
617       EnsureBuffers();
618 
619       StringBuilder builder = null;
620 
621       int totalBytesRead = 0;
622       // used in case of left over multibyte characters in the buffer
623       int offset = 0;
624       do
625       {
626         int count = offset;
627         byte b;
628         while (count < MaxCharBytesSize && (b = _reader.ReadByte()) > 0)
629         {
630           _byteBuffer[count++] = b;
631         }
632         int byteCount = count - offset;
633         totalBytesRead += byteCount;
634 
635         if (count < MaxCharBytesSize && builder == null)
636         {
637           // pref optimization to avoid reading into a string builder
638           // if string is smaller than the buffer then return it directly
639           int length = Encoding.UTF8.GetChars(_byteBuffer, 0, byteCount, _charBuffer, 0);
640 
641           MovePosition(totalBytesRead + 1);
642           return new string(_charBuffer, 0, length);
643         }
644         else
645         {
646           // calculate the index of the end of the last full character in the buffer
647           int lastFullCharStop = GetLastFullCharStop(count - 1);
648 
649           int charCount = Encoding.UTF8.GetChars(_byteBuffer, 0, lastFullCharStop + 1, _charBuffer, 0);
650 
651           if (builder == null)
652             builder = new StringBuilder(MaxCharBytesSize*2);
653 
654           builder.Append(_charBuffer, 0, charCount);
655 
656           if (lastFullCharStop < byteCount - 1)
657           {
658             offset = byteCount - lastFullCharStop - 1;
659             // copy left over multi byte characters to beginning of buffer for next iteration
660             Array.Copy(_byteBuffer, lastFullCharStop + 1, _byteBuffer, 0, offset);
661           }
662           else
663           {
664             // reached end of string
665             if (count < MaxCharBytesSize)
666             {
667               MovePosition(totalBytesRead + 1);
668               return builder.ToString();
669             }
670 
671             offset = 0;
672           }
673         }
674       } while (true);
675     }
676 
ReadLengthString()677     private string ReadLengthString()
678     {
679       int length = ReadInt32();
680 
681       MovePosition(length);
682 
683       string s = GetString(length - 1);
684       _reader.ReadByte();
685 
686       return s;
687     }
688 
GetString(int length)689     private string GetString(int length)
690     {
691       if (length == 0)
692         return string.Empty;
693 
694       EnsureBuffers();
695 
696       StringBuilder builder = null;
697 
698       int totalBytesRead = 0;
699 
700       // used in case of left over multibyte characters in the buffer
701       int offset = 0;
702       do
703       {
704         int count = ((length - totalBytesRead) > MaxCharBytesSize - offset)
705                       ? MaxCharBytesSize - offset
706                       : length - totalBytesRead;
707 
708         int byteCount = _reader.Read(_byteBuffer, offset, count);
709 
710         if (byteCount == 0)
711           throw new EndOfStreamException("Unable to read beyond the end of the stream.");
712 
713         totalBytesRead += byteCount;
714 
715         // Above, byteCount is how many bytes we read this time.
716         // Below, byteCount is how many bytes are in the _byteBuffer.
717         byteCount += offset;
718 
719         if (byteCount == length)
720         {
721           // pref optimization to avoid reading into a string builder
722           // first iteration and all bytes read then return string directly
723           int charCount = Encoding.UTF8.GetChars(_byteBuffer, 0, byteCount, _charBuffer, 0);
724           return new string(_charBuffer, 0, charCount);
725         }
726         else
727         {
728           int lastFullCharStop = GetLastFullCharStop(byteCount - 1);
729 
730           if (builder == null)
731             builder = new StringBuilder(length);
732 
733           int charCount = Encoding.UTF8.GetChars(_byteBuffer, 0, lastFullCharStop + 1, _charBuffer, 0);
734           builder.Append(_charBuffer, 0, charCount);
735 
736           if (lastFullCharStop < byteCount - 1)
737           {
738             offset = byteCount - lastFullCharStop - 1;
739             // copy left over multi byte characters to beginning of buffer for next iteration
740             Array.Copy(_byteBuffer, lastFullCharStop + 1, _byteBuffer, 0, offset);
741           }
742           else
743           {
744             offset = 0;
745           }
746         }
747       } while (totalBytesRead < length);
748 
749       return builder.ToString();
750     }
751 
GetLastFullCharStop(int start)752     private int GetLastFullCharStop(int start)
753     {
754       int lookbackPos = start;
755       int bis = 0;
756       while (lookbackPos >= 0)
757       {
758         bis = BytesInSequence(_byteBuffer[lookbackPos]);
759         if (bis == 0)
760         {
761           lookbackPos--;
762           continue;
763         }
764         else if (bis == 1)
765         {
766           break;
767         }
768         else
769         {
770           lookbackPos--;
771           break;
772         }
773       }
774       if (bis == start - lookbackPos)
775       {
776         //Full character.
777         return start;
778       }
779       else
780       {
781         return lookbackPos;
782       }
783     }
784 
BytesInSequence(byte b)785     private int BytesInSequence(byte b)
786     {
787       if (b <= SeqRange1[1]) return 1;
788       if (b >= SeqRange2[0] && b <= SeqRange2[1]) return 2;
789       if (b >= SeqRange3[0] && b <= SeqRange3[1]) return 3;
790       if (b >= SeqRange4[0] && b <= SeqRange4[1]) return 4;
791       return 0;
792     }
793 
EnsureBuffers()794     private void EnsureBuffers()
795     {
796       if (_byteBuffer == null)
797       {
798         _byteBuffer = new byte[MaxCharBytesSize];
799       }
800       if (_charBuffer == null)
801       {
802         int charBufferSize = Encoding.UTF8.GetMaxCharCount(MaxCharBytesSize);
803         _charBuffer = new char[charBufferSize];
804       }
805     }
806 
ReadDouble()807     private double ReadDouble()
808     {
809       MovePosition(8);
810       return _reader.ReadDouble();
811     }
812 
ReadInt32()813     private int ReadInt32()
814     {
815       MovePosition(4);
816       return _reader.ReadInt32();
817     }
818 
ReadInt64()819     private long ReadInt64()
820     {
821       MovePosition(8);
822       return _reader.ReadInt64();
823     }
824 
ReadType()825     private BsonType ReadType()
826     {
827       MovePosition(1);
828       return (BsonType) _reader.ReadSByte();
829     }
830 
MovePosition(int count)831     private void MovePosition(int count)
832     {
833       _currentContext.Position += count;
834     }
835 
ReadBytes(int count)836     private byte[] ReadBytes(int count)
837     {
838       MovePosition(count);
839       return _reader.ReadBytes(count);
840     }
841   }
842 }