Json.NET
Code Coverage Statistics for Source File

Newtonsoft.Json\Bson\BsonReader.cs

Symbol Coverage: 93.83% (289 of 308)

Branch Coverage: 88.70% (102 of 115)

Cyclomatic Complexity Avg: 3.55 Max:18

Code Lines: 303


L V Source
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
 1
    private static readonly byte[] _seqRange1 = new byte[] { 0, 127 }; // range of 1-byte sequence
43
 1
    private static readonly byte[] _seqRange2 = new byte[] { 194, 223 }; // range of 2-byte sequence
44
 1
    private static readonly byte[] _seqRange3 = new byte[] { 224, 239 }; // range of 3-byte sequence
45
 1
    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 DateTimeKind _dateTimeKindHandling;
59

  
60
    private enum BsonReaderState
61
    {
62
      Normal,
63
      ReferenceStart,
64
      ReferenceRef,
65
      ReferenceId,
66
      CodeWScopeStart,
67
      CodeWScopeCode,
68
      CodeWScopeScope,
69
      CodeWScopeScopeObject,
70
      CodeWScopeScopeEnd
71
    }
72

  
73
    private class ContainerContext
74
    {
75
      public readonly BsonType Type;
76
      public int Length;
77
      public int Position;
78

  
79
 35083
      public ContainerContext(BsonType type)
80
      {
81
 35083
        Type = type;
82
 35083
      }
83
    }
84

  
85
    /// <summary>
86
    /// Gets or sets a value indicating whether the root object will be read as a JSON array.
87
    /// </summary>
88
    /// <value>
89
    /// 	<c>true</c> if the root object will be read as a JSON array; otherwise, <c>false</c>.
90
    /// </value>
91
    public bool ReadRootValueAsArray
92
    {
93
 3
      get { return _readRootValueAsArray; }
94
 3
      set { _readRootValueAsArray = value; }
95
    }
96

  
97
    /// <summary>
98
    /// Gets or sets the <see cref="DateTimeKind" /> used when reading <see cref="DateTime"/> values from BSON.
99
    /// </summary>
100
    /// <value>The <see cref="DateTimeKind" /> used when reading <see cref="DateTime"/> values from BSON.</value>
101
    public DateTimeKind DateTimeKindHandling
102
    {
103
 20018
      get { return _dateTimeKindHandling; }
104
 2
      set { _dateTimeKindHandling = value; }
105
    }
106

  
107
    /// <summary>
108
    /// Initializes a new instance of the <see cref="BsonReader"/> class.
109
    /// </summary>
110
    /// <param name="stream">The stream.</param>
111
 5045
    public BsonReader(Stream stream)
112
 5045
      : this(stream, false, DateTimeKind.Local)
113
    {
114
 5045
    }
115

  
116
    /// <summary>
117
    /// Initializes a new instance of the <see cref="BsonReader"/> class.
118
    /// </summary>
119
    /// <param name="stream">The stream.</param>
120
    /// <param name="readRootValueAsArray">if set to <c>true</c> the root object will be read as a JSON array.</param>
121
    /// <param name="dateTimeKindHandling">The <see cref="DateTimeKind" /> used when reading <see cref="DateTime"/> values from BSON.</param>
122
 5049
    public BsonReader(Stream stream, bool readRootValueAsArray, DateTimeKind dateTimeKindHandling)
123
    {
124
 5049
      ValidationUtils.ArgumentNotNull(stream, "stream");
125
 5049
      _reader = new BinaryReader(stream);
126
 5049
      _stack = new List<ContainerContext>();
127
 5049
      _readRootValueAsArray = readRootValueAsArray;
128
 5049
      _dateTimeKindHandling = dateTimeKindHandling;
129
 5049
    }
130

  
131
    private string ReadElement()
132
    {
133
 120214
      _currentElementType = ReadType();
134
 120214
      string elementName = ReadString();
135
 120214
      return elementName;
136
 120214
    }
137

  
138
    /// <summary>
139
    /// Reads the next JSON token from the stream as a <see cref="T:Byte[]"/>.
140
    /// </summary>
141
    /// <returns>
142
    /// A <see cref="T:Byte[]"/> or a null reference if the next JSON token is null.
143
    /// </returns>
144
    public override byte[] ReadAsBytes()
145
    {
146
 1
      Read();
147
 1
      if (TokenType != JsonToken.Bytes)
148
 0
        throw new JsonReaderException("Error reading bytes. Expected bytes but got {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType));
149

  
150
 1
      return (byte[])Value;
151
 1
    }
152

  
153
    /// <summary>
154
    /// Reads the next JSON token from the stream.
155
    /// </summary>
156
    /// <returns>
157
    /// true if the next token was read successfully; false if there are no more tokens to read.
158
    /// </returns>
159
    public override bool Read()
160
    {
161
      try
162
      {
163
 255478
        switch (_bsonReaderState)
164
        {
165
          case BsonReaderState.Normal:
166
 255465
            return ReadNormal();
167
          case BsonReaderState.ReferenceStart:
168
          case BsonReaderState.ReferenceRef:
169
          case BsonReaderState.ReferenceId:
170
 5
            return ReadReference();
171
          case BsonReaderState.CodeWScopeStart:
172
          case BsonReaderState.CodeWScopeCode:
173
          case BsonReaderState.CodeWScopeScope:
174
          case BsonReaderState.CodeWScopeScopeObject:
175
          case BsonReaderState.CodeWScopeScopeEnd:
176
 8
            return ReadCodeWScope();
177
          default:
178
 0
            throw new JsonReaderException("Unexpected state: {0}".FormatWith(CultureInfo.InvariantCulture, _bsonReaderState));
179
        }
180
      }
181
 1
      catch (EndOfStreamException)
182
      {
183
 1
        return false;
184
      }
185
 255478
    }
186

  
187
    private bool ReadCodeWScope()
188
    {
189
 8
      switch (_bsonReaderState)
190
      {
191
        case BsonReaderState.CodeWScopeStart:
192
 1
          SetToken(JsonToken.PropertyName, "$code");
193
 1
          _bsonReaderState = BsonReaderState.CodeWScopeCode;
194
 1
          return true;
195
        case BsonReaderState.CodeWScopeCode:
196
          // total CodeWScope size - not used
197
 1
          ReadInt32();
198

  
199
 1
          SetToken(JsonToken.String, ReadLengthString());
200
 1
          _bsonReaderState = BsonReaderState.CodeWScopeScope;
201
 1
          return true;
202
        case BsonReaderState.CodeWScopeScope:
203
 2
          if (CurrentState == State.PostValue)
204
          {
205
 1
            SetToken(JsonToken.PropertyName, "$scope");
206
 1
            return true;
207
          }
208
          else
209
          {
210
 1
            SetToken(JsonToken.StartObject);
211
 1
            _bsonReaderState = BsonReaderState.CodeWScopeScopeObject;
212

  
213
 1
            ContainerContext newContext = new ContainerContext(BsonType.Object);
214
 1
            PushContext(newContext);
215
 1
            newContext.Length = ReadInt32();
216

  
217
 1
            return true;
218
          }
219
        case BsonReaderState.CodeWScopeScopeObject:
220
 3
          bool result = ReadNormal();
221
 3
          if (result && TokenType == JsonToken.EndObject)
222
 1
            _bsonReaderState = BsonReaderState.CodeWScopeScopeEnd;
223

  
224
 3
          return result;
225
        case BsonReaderState.CodeWScopeScopeEnd:
226
 1
          SetToken(JsonToken.EndObject);
227
 1
          _bsonReaderState = BsonReaderState.Normal;
228
 1
          return true;
229
        default:
230
 0
          throw new ArgumentOutOfRangeException();
231
      }
232
 8
    }
233

  
234
    private bool ReadReference()
235
    {
236
 5
      switch (CurrentState)
237
      {
238
        case State.ObjectStart:
239
          {
240
 1
            SetToken(JsonToken.PropertyName, "$ref");
241
 1
            _bsonReaderState = BsonReaderState.ReferenceRef;
242
 1
            return true;
243
          }
244
        case State.Property:
245
          {
246
 2
            if (_bsonReaderState == BsonReaderState.ReferenceRef)
247
            {
248
 1
              SetToken(JsonToken.String, ReadLengthString());
249
 1
              return true;
250
            }
251
 1
            else if (_bsonReaderState == BsonReaderState.ReferenceId)
252
            {
253
 1
              SetToken(JsonToken.Bytes, ReadBytes(12));
254
 1
              return true;
255
            }
256
            else
257
            {
258
 0
              throw new JsonReaderException("Unexpected state when reading BSON reference: " + _bsonReaderState);
259
            }
260
          }
261
        case State.PostValue:
262
          {
263
 2
            if (_bsonReaderState == BsonReaderState.ReferenceRef)
264
            {
265
 1
              SetToken(JsonToken.PropertyName, "$id");
266
 1
              _bsonReaderState = BsonReaderState.ReferenceId;
267
 1
              return true;
268
            }
269
 1
            else if (_bsonReaderState == BsonReaderState.ReferenceId)
270
            {
271
 1
              SetToken(JsonToken.EndObject);
272
 1
              _bsonReaderState = BsonReaderState.Normal;
273
 1
              return true;
274
            }
275
            else
276
            {
277
 0
              throw new JsonReaderException("Unexpected state when reading BSON reference: " + _bsonReaderState);
278
            }
279
          }
280
        default:
281
 0
          throw new JsonReaderException("Unexpected state when reading BSON reference: " + CurrentState);
282
      }
283
 5
    }
284

  
285
    private bool ReadNormal()
286
    {
287
 255468
      switch (CurrentState)
288
      {
289
        case State.Start:
290
          {
291
 5049
            JsonToken token = (!_readRootValueAsArray) ? JsonToken.StartObject : JsonToken.StartArray;
292
 5049
            BsonType type = (!_readRootValueAsArray) ? BsonType.Object : BsonType.Array;
293

  
294
 5049
            SetToken(token);
295
 5049
            ContainerContext newContext = new ContainerContext(type);
296
 5049
            PushContext(newContext);
297
 5049
            newContext.Length = ReadInt32();
298
 5048
            return true;
299
          }
300
        case State.Complete:
301
        case State.Closed:
302
 0
          return false;
303
        case State.Property:
304
          {
305
 95119
            ReadType(_currentElementType);
306
 95119
            return true;
307
          }
308
        case State.ObjectStart:
309
        case State.ArrayStart:
310
        case State.PostValue:
311
 155300
          ContainerContext context = _currentContext;
312
 155300
          if (context == null)
313
 18
            return false;
314

  
315
 155282
          int lengthMinusEnd = context.Length - 1;
316

  
317
 155282
          if (context.Position < lengthMinusEnd)
318
          {
319
 120214
            if (context.Type == BsonType.Array)
320
            {
321
 25088
              ReadElement();
322
 25088
              ReadType(_currentElementType);
323
 25088
              return true;
324
            }
325
            else
326
            {
327
 95126
              SetToken(JsonToken.PropertyName, ReadElement());
328
 95126
              return true;
329
            }
330
          }
331
 35068
          else if (context.Position == lengthMinusEnd)
332
          {
333
 35068
            if (ReadByte() != 0)
334
 0
              throw new JsonReaderException("Unexpected end of object byte value.");
335

  
336
 35068
            PopContext();
337
 35068
            if (_currentContext != null)
338
 30034
              MovePosition(context.Length);
339

  
340
 35068
            JsonToken endToken = (context.Type == BsonType.Object) ? JsonToken.EndObject : JsonToken.EndArray;
341
 35068
            SetToken(endToken);
342
 35068
            return true;
343
          }
344
          else
345
          {
346
 0
            throw new JsonReaderException("Read past end of current container context.");
347
          }
348
        case State.ConstructorStart:
349
 0
          break;
350
        case State.Constructor:
351
 0
          break;
352
        case State.Error:
353
 0
          break;
354
        case State.Finished:
355
 0
          break;
356
        default:
357
 0
          throw new ArgumentOutOfRangeException();
358
      }
359

  
360
 0
      return false;
361
 255467
    }
362

  
363
    private void PopContext()
364
    {
365
 35068
      _stack.RemoveAt(_stack.Count - 1);
366
 35068
      if (_stack.Count == 0)
367
 5034
        _currentContext = null;
368
      else
369
 30034
        _currentContext = _stack[_stack.Count - 1];
370
 35068
    }
371

  
372
    private void PushContext(ContainerContext newContext)
373
    {
374
 35083
      _stack.Add(newContext);
375
 35083
      _currentContext = newContext;
376
 35083
    }
377

  
378
    private byte ReadByte()
379
    {
380
 35074
      MovePosition(1);
381
 35074
      return _reader.ReadByte();
382
 35074
    }
383

  
384
    private void ReadType(BsonType type)
385
    {
386
 120207
      switch (type)
387
      {
388
        case BsonType.Number:
389
 5046
          SetToken(JsonToken.Float, ReadDouble());
390
 5046
          break;
391
        case BsonType.String:
392
        case BsonType.Symbol:
393
 40061
          SetToken(JsonToken.String, ReadLengthString());
394
 40061
          break;
395
        case BsonType.Object:
396
          {
397
 20018
            SetToken(JsonToken.StartObject);
398

  
399
 20018
            ContainerContext newContext = new ContainerContext(BsonType.Object);
400
 20018
            PushContext(newContext);
401
 20018
            newContext.Length = ReadInt32();
402
 20018
            break;
403
          }
404
        case BsonType.Array:
405
          {
406
 10015
            SetToken(JsonToken.StartArray);
407

  
408
 10015
            ContainerContext newContext = new ContainerContext(BsonType.Array);
409
 10015
            PushContext(newContext);
410
 10015
            newContext.Length = ReadInt32();
411
 10015
            break;
412
          }
413
        case BsonType.Binary:
414
 4
          SetToken(JsonToken.Bytes, ReadBinary());
415
 4
          break;
416
        case BsonType.Undefined:
417
 1
          SetToken(JsonToken.Undefined);
418
 1
          break;
419
        case BsonType.Oid:
420
 5
          byte[] oid = ReadBytes(12);
421
 5
          SetToken(JsonToken.Bytes, oid);
422
 5
          break;
423
        case BsonType.Boolean:
424
 2
          bool b = Convert.ToBoolean(ReadByte());
425
 2
          SetToken(JsonToken.Boolean, b);
426
 2
          break;
427
        case BsonType.Date:
428
 20015
          long ticks = ReadInt64();
429
 20015
          DateTime utcDateTime = JsonConvert.ConvertJavaScriptTicksToDateTime(ticks);
430

  
431
          DateTime dateTime;
432
 20015
          switch (DateTimeKindHandling)
433
          {
434
            case DateTimeKind.Unspecified:
435
 1
              dateTime = DateTime.SpecifyKind(utcDateTime.ToLocalTime(), DateTimeKind.Unspecified);
436
 1
              break;
437
            case DateTimeKind.Local:
438
 20011
              dateTime = utcDateTime.ToLocalTime();
439
 20011
              break;
440
            default:
441
 3
              dateTime = utcDateTime;
442
 3
              break;
443
          }
444

  
445
 20015
          SetToken(JsonToken.Date, dateTime);
446
 20015
          break;
447
        case BsonType.Null:
448
 10008
          SetToken(JsonToken.Null);
449
 10008
          break;
450
        case BsonType.Regex:
451
 6
          string expression = ReadString();
452
 6
          string modifiers = ReadString();
453

  
454
 6
          string regex = @"/" + expression + @"/" + modifiers;
455
 6
          SetToken(JsonToken.String, regex);
456
 6
          break;
457
        case BsonType.Reference:
458
 1
          SetToken(JsonToken.StartObject);
459
 1
          _bsonReaderState = BsonReaderState.ReferenceStart;
460
 1
          break;
461
        case BsonType.Code:
462
 1
          SetToken(JsonToken.String, ReadLengthString());
463
 1
          break;
464
        case BsonType.CodeWScope:
465
 1
          SetToken(JsonToken.StartObject);
466
 1
          _bsonReaderState = BsonReaderState.CodeWScopeStart;
467
 1
          break;
468
        case BsonType.Integer:
469
 15020
          SetToken(JsonToken.Integer, (long)ReadInt32());
470
 15020
          break;
471
        case BsonType.TimeStamp:
472
        case BsonType.Long:
473
 3
          SetToken(JsonToken.Integer, ReadInt64());
474
 3
          break;
475
        default:
476
 0
          throw new ArgumentOutOfRangeException("type", "Unexpected BsonType value: " + type);
477
      }
478
 120207
    }
479

  
480
    private byte[] ReadBinary()
481
    {
482
 4
      int dataLength = ReadInt32();
483

  
484
      // BsonBinaryType not used
485
 4
      ReadByte();
486

  
487
 4
      return ReadBytes(dataLength);
488
 4
    }
489

  
490
    private string ReadString()
491
    {
492
 120226
      EnsureBuffers();
493

  
494
 120226
      StringBuilder builder = null;
495

  
496
 120226
      int totalBytesRead = 0;
497
      // used in case of left over multibyte characters in the buffer
498
 120226
      int offset = 0;
499
      do
500
      {
501
 120235
        int count = offset;
502
        byte b;
503
 827428
        while (count < MaxCharBytesSize && (b = _reader.ReadByte()) > 0)
504
        {
505
 707193
          _byteBuffer[count++] = b;
506
        }
507
 120235
        int byteCount = count - offset;
508
 120235
        totalBytesRead += byteCount;
509

  
510
 120235
        if (count < MaxCharBytesSize && builder == null)
511
        {
512
          // pref optimization to avoid reading into a string builder
513
          // if string is smaller than the buffer then return it directly
514
 120221
          int length = Encoding.UTF8.GetChars(_byteBuffer, 0, byteCount, _charBuffer, 0);
515

  
516
 120221
          MovePosition(totalBytesRead + 1);
517
 120221
          return new string(_charBuffer, 0, length);
518
        }
519
        else
520
        {
521
          // calculate the index of the end of the last full character in the buffer
522
 14
          int lastFullCharStop = GetLastFullCharStop(count - 1);
523

  
524
 14
          int charCount = Encoding.UTF8.GetChars(_byteBuffer, 0, lastFullCharStop + 1, _charBuffer, 0);
525

  
526
 14
          if (builder == null)
527
 5
            builder = new StringBuilder(MaxCharBytesSize * 2);
528

  
529
 14
          builder.Append(_charBuffer, 0, charCount);
530

  
531
 14
          if (lastFullCharStop < byteCount - 1)
532
          {
533
 2
            offset = byteCount - lastFullCharStop - 1;
534
            // copy left over multi byte characters to beginning of buffer for next iteration
535
 2
            Array.Copy(_byteBuffer, lastFullCharStop + 1, _byteBuffer, 0, offset);
536
          }
537
          else
538
          {
539
            // reached end of string
540
 12
            if (count < MaxCharBytesSize)
541
            {
542
 5
              MovePosition(totalBytesRead + 1);
543
 5
              return builder.ToString();
544
            }
545

  
546
 7
            offset = 0;
547
          }
548
        }
549
      }
550
 9
      while (true);
551
 120226
    }
552

  
553
    private string ReadLengthString()
554
    {
555
 40064
      int length = ReadInt32();
556

  
557
 40064
      MovePosition(length);
558

  
559
 40064
      string s = GetString(length - 1);
560
 40064
      _reader.ReadByte();
561

  
562
 40064
      return s;
563
 40064
    }
564

  
565
    private string GetString(int length)
566
    {
567
 40064
      if (length == 0)
568
 3
        return string.Empty;
569

  
570
 40061
      EnsureBuffers();
571

  
572
 40061
      StringBuilder builder = null;
573

  
574
 40061
      int totalBytesRead = 0;
575
 40061
      int offset = 0;
576
      do
577
      {
578
 40070
        int count = ((length - totalBytesRead) > MaxCharBytesSize - offset)
579
 40070
          ? MaxCharBytesSize - offset
580
 40070
          : length - totalBytesRead;
581

  
582
 40070
        int byteCount = _reader.BaseStream.Read(_byteBuffer, offset, count);
583

  
584
 40070
        if (byteCount == 0)
585
 0
          throw new EndOfStreamException("Unable to read beyond the end of the stream.");
586

  
587
 40070
        byteCount += offset;
588

  
589
 40070
        if (totalBytesRead == 0 && byteCount == length)
590
        {
591
          // pref optimization to avoid reading into a string builder
592
          // first iteration and all bytes read then return string directly
593
 40056
          int charCount = Encoding.UTF8.GetChars(_byteBuffer, 0, byteCount, _charBuffer, 0);
594
 40056
          return new string(_charBuffer, 0, charCount);
595
        }
596
        else
597
        {
598
 14
          int lastFullCharStop = GetLastFullCharStop(byteCount - 1);
599

  
600
 14
          if (builder == null)
601
 5
            builder = new StringBuilder(length);
602

  
603
 14
          int charCount = Encoding.UTF8.GetChars(_byteBuffer, 0, lastFullCharStop + 1, _charBuffer, 0);
604
 14
          builder.Append(_charBuffer, 0, charCount);
605

  
606
 14
          if (lastFullCharStop < byteCount - 1)
607
          {
608
 2
            offset = byteCount - lastFullCharStop - 1;
609
            // copy left over multi byte characters to beginning of buffer for next iteration
610
 2
            Array.Copy(_byteBuffer, lastFullCharStop + 1, _byteBuffer, 0, offset);
611
          }
612
          else
613
          {
614
 12
            offset = 0;
615
          }
616

  
617
 14
          totalBytesRead += (byteCount - offset);
618
        }
619
      }
620
 14
      while (totalBytesRead < length);
621

  
622
 5
      return builder.ToString();
623
 40064
    }
624

  
625
    private int GetLastFullCharStop(int start)
626
    {
627
 28
      int lookbackPos = start;
628
 28
      int bis = 0;
629
 46
      while (lookbackPos >= 0)
630
      {
631
 46
        bis = BytesInSequence(_byteBuffer[lookbackPos]);
632
 46
        if (bis == 0)
633
        {
634
 18
          lookbackPos--;
635
 18
          continue;
636
        }
637
 28
        else if (bis == 1)
638
        {
639
 16
          break;
640
        }
641
        else
642
        {
643
 12
          lookbackPos--;
644
 12
          break;
645
        }
646
      }
647
 28
      if (bis == start - lookbackPos)
648
      {
649
        //Full character.
650
 8
        return start;
651
      }
652
      else
653
      {
654
 20
        return lookbackPos;
655
      }
656
 28
    }
657

  
658
    private int BytesInSequence(byte b)
659
    {
660
 16
      if (b <= _seqRange1[1]) return 1;
661
 0
      if (b >= _seqRange2[0] && b <= _seqRange2[1]) return 2;
662
 12
      if (b >= _seqRange3[0] && b <= _seqRange3[1]) return 3;
663
 0
      if (b >= _seqRange4[0] && b <= _seqRange4[1]) return 4;
664
 18
      return 0;
665
 46
    }
666

  
667
    private void EnsureBuffers()
668
    {
669
 160287
      if (_byteBuffer == null)
670
      {
671
 5048
        _byteBuffer = new byte[MaxCharBytesSize];
672
      }
673
 160287
      if (_charBuffer == null)
674
      {
675
 5048
        int charBufferSize = Encoding.UTF8.GetMaxCharCount(MaxCharBytesSize);
676
 5048
        _charBuffer = new char[charBufferSize];
677
      }
678
 160287
    }
679

  
680
    private double ReadDouble()
681
    {
682
 5046
      MovePosition(8);
683
 5046
      return _reader.ReadDouble();
684
 5046
    }
685

  
686
    private int ReadInt32()
687
    {
688
 90172
      MovePosition(4);
689
 90172
      return _reader.ReadInt32();
690
 90171
    }
691

  
692
    private long ReadInt64()
693
    {
694
 20018
      MovePosition(8);
695
 20018
      return _reader.ReadInt64();
696
 20018
    }
697

  
698
    private BsonType ReadType()
699
    {
700
 120214
      MovePosition(1);
701
 120214
      return (BsonType)_reader.ReadSByte();
702
 120214
    }
703

  
704
    private void MovePosition(int count)
705
    {
706
 460858
      _currentContext.Position += count;
707
 460858
    }
708

  
709
    private byte[] ReadBytes(int count)
710
    {
711
 10
      MovePosition(count);
712
 10
      return _reader.ReadBytes(count);
713
 10
    }
714
  }
715
}