~ubuntu-branches/ubuntu/trusty/smuxi/trusty-proposed

« back to all changes in this revision

Viewing changes to lib/Newtonsoft.Json/Src/Newtonsoft.Json/Bson/BsonReader.cs

  • Committer: Package Import Robot
  • Author(s): Mirco Bauer
  • Date: 2013-05-25 22:11:31 UTC
  • mfrom: (1.2.12)
  • Revision ID: package-import@ubuntu.com-20130525221131-nd2mc0kzubuwyx20
Tags: 0.8.11-1
* [22d13d5] Imported Upstream version 0.8.11
* [6d2b95a] Refreshed patches
* [89eb66e] Added ServiceStack libraries to smuxi-engine package
* [848ab10] Enable Campfire engine
* [c6dbdc7] Always build db4o for predictable build result
* [13ec489] Exclude OS X specific libraries from dh_clideps

Show diffs side-by-side

added added

removed removed

Lines of Context:
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 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
 
      public ContainerContext(BsonType type)
80
 
      {
81
 
        Type = type;
82
 
      }
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
 
      get { return _readRootValueAsArray; }
94
 
      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
 
      get { return _dateTimeKindHandling; }
104
 
      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
 
    public BsonReader(Stream stream)
112
 
      : this(stream, false, DateTimeKind.Local)
113
 
    {
114
 
    }
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
 
    public BsonReader(Stream stream, bool readRootValueAsArray, DateTimeKind dateTimeKindHandling)
123
 
    {
124
 
      ValidationUtils.ArgumentNotNull(stream, "stream");
125
 
      _reader = new BinaryReader(stream);
126
 
      _stack = new List<ContainerContext>();
127
 
      _readRootValueAsArray = readRootValueAsArray;
128
 
      _dateTimeKindHandling = dateTimeKindHandling;
129
 
    }
130
 
 
131
 
    private string ReadElement()
132
 
    {
133
 
      _currentElementType = ReadType();
134
 
      string elementName = ReadString();
135
 
      return elementName;
136
 
    }
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
 
      Read();
147
 
      if (TokenType != JsonToken.Bytes)
148
 
        throw new JsonReaderException("Error reading bytes. Expected bytes but got {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType));
149
 
 
150
 
      return (byte[])Value;
151
 
    }
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
 
        switch (_bsonReaderState)
164
 
        {
165
 
          case BsonReaderState.Normal:
166
 
            return ReadNormal();
167
 
          case BsonReaderState.ReferenceStart:
168
 
          case BsonReaderState.ReferenceRef:
169
 
          case BsonReaderState.ReferenceId:
170
 
            return ReadReference();
171
 
          case BsonReaderState.CodeWScopeStart:
172
 
          case BsonReaderState.CodeWScopeCode:
173
 
          case BsonReaderState.CodeWScopeScope:
174
 
          case BsonReaderState.CodeWScopeScopeObject:
175
 
          case BsonReaderState.CodeWScopeScopeEnd:
176
 
            return ReadCodeWScope();
177
 
          default:
178
 
            throw new JsonReaderException("Unexpected state: {0}".FormatWith(CultureInfo.InvariantCulture, _bsonReaderState));
179
 
        }
180
 
      }
181
 
      catch (EndOfStreamException)
182
 
      {
183
 
        return false;
184
 
      }
185
 
    }
186
 
 
187
 
    private bool ReadCodeWScope()
188
 
    {
189
 
      switch (_bsonReaderState)
190
 
      {
191
 
        case BsonReaderState.CodeWScopeStart:
192
 
          SetToken(JsonToken.PropertyName, "$code");
193
 
          _bsonReaderState = BsonReaderState.CodeWScopeCode;
194
 
          return true;
195
 
        case BsonReaderState.CodeWScopeCode:
196
 
          // total CodeWScope size - not used
197
 
          ReadInt32();
198
 
 
199
 
          SetToken(JsonToken.String, ReadLengthString());
200
 
          _bsonReaderState = BsonReaderState.CodeWScopeScope;
201
 
          return true;
202
 
        case BsonReaderState.CodeWScopeScope:
203
 
          if (CurrentState == State.PostValue)
204
 
          {
205
 
            SetToken(JsonToken.PropertyName, "$scope");
206
 
            return true;
207
 
          }
208
 
          else
209
 
          {
210
 
            SetToken(JsonToken.StartObject);
211
 
            _bsonReaderState = BsonReaderState.CodeWScopeScopeObject;
212
 
 
213
 
            ContainerContext newContext = new ContainerContext(BsonType.Object);
214
 
            PushContext(newContext);
215
 
            newContext.Length = ReadInt32();
216
 
 
217
 
            return true;
218
 
          }
219
 
        case BsonReaderState.CodeWScopeScopeObject:
220
 
          bool result = ReadNormal();
221
 
          if (result && TokenType == JsonToken.EndObject)
222
 
            _bsonReaderState = BsonReaderState.CodeWScopeScopeEnd;
223
 
 
224
 
          return result;
225
 
        case BsonReaderState.CodeWScopeScopeEnd:
226
 
          SetToken(JsonToken.EndObject);
227
 
          _bsonReaderState = BsonReaderState.Normal;
228
 
          return true;
229
 
        default:
230
 
          throw new ArgumentOutOfRangeException();
231
 
      }
232
 
    }
233
 
 
234
 
    private bool ReadReference()
235
 
    {
236
 
      switch (CurrentState)
237
 
      {
238
 
        case State.ObjectStart:
239
 
          {
240
 
            SetToken(JsonToken.PropertyName, "$ref");
241
 
            _bsonReaderState = BsonReaderState.ReferenceRef;
242
 
            return true;
243
 
          }
244
 
        case State.Property:
245
 
          {
246
 
            if (_bsonReaderState == BsonReaderState.ReferenceRef)
247
 
            {
248
 
              SetToken(JsonToken.String, ReadLengthString());
249
 
              return true;
250
 
            }
251
 
            else if (_bsonReaderState == BsonReaderState.ReferenceId)
252
 
            {
253
 
              SetToken(JsonToken.Bytes, ReadBytes(12));
254
 
              return true;
255
 
            }
256
 
            else
257
 
            {
258
 
              throw new JsonReaderException("Unexpected state when reading BSON reference: " + _bsonReaderState);
259
 
            }
260
 
          }
261
 
        case State.PostValue:
262
 
          {
263
 
            if (_bsonReaderState == BsonReaderState.ReferenceRef)
264
 
            {
265
 
              SetToken(JsonToken.PropertyName, "$id");
266
 
              _bsonReaderState = BsonReaderState.ReferenceId;
267
 
              return true;
268
 
            }
269
 
            else if (_bsonReaderState == BsonReaderState.ReferenceId)
270
 
            {
271
 
              SetToken(JsonToken.EndObject);
272
 
              _bsonReaderState = BsonReaderState.Normal;
273
 
              return true;
274
 
            }
275
 
            else
276
 
            {
277
 
              throw new JsonReaderException("Unexpected state when reading BSON reference: " + _bsonReaderState);
278
 
            }
279
 
          }
280
 
        default:
281
 
          throw new JsonReaderException("Unexpected state when reading BSON reference: " + CurrentState);
282
 
      }
283
 
    }
284
 
 
285
 
    private bool ReadNormal()
286
 
    {
287
 
      switch (CurrentState)
288
 
      {
289
 
        case State.Start:
290
 
          {
291
 
            JsonToken token = (!_readRootValueAsArray) ? JsonToken.StartObject : JsonToken.StartArray;
292
 
            BsonType type = (!_readRootValueAsArray) ? BsonType.Object : BsonType.Array;
293
 
 
294
 
            SetToken(token);
295
 
            ContainerContext newContext = new ContainerContext(type);
296
 
            PushContext(newContext);
297
 
            newContext.Length = ReadInt32();
298
 
            return true;
299
 
          }
300
 
        case State.Complete:
301
 
        case State.Closed:
302
 
          return false;
303
 
        case State.Property:
304
 
          {
305
 
            ReadType(_currentElementType);
306
 
            return true;
307
 
          }
308
 
        case State.ObjectStart:
309
 
        case State.ArrayStart:
310
 
        case State.PostValue:
311
 
          ContainerContext context = _currentContext;
312
 
          if (context == null)
313
 
            return false;
314
 
 
315
 
          int lengthMinusEnd = context.Length - 1;
316
 
 
317
 
          if (context.Position < lengthMinusEnd)
318
 
          {
319
 
            if (context.Type == BsonType.Array)
320
 
            {
321
 
              ReadElement();
322
 
              ReadType(_currentElementType);
323
 
              return true;
324
 
            }
325
 
            else
326
 
            {
327
 
              SetToken(JsonToken.PropertyName, ReadElement());
328
 
              return true;
329
 
            }
330
 
          }
331
 
          else if (context.Position == lengthMinusEnd)
332
 
          {
333
 
            if (ReadByte() != 0)
334
 
              throw new JsonReaderException("Unexpected end of object byte value.");
335
 
 
336
 
            PopContext();
337
 
            if (_currentContext != null)
338
 
              MovePosition(context.Length);
339
 
 
340
 
            JsonToken endToken = (context.Type == BsonType.Object) ? JsonToken.EndObject : JsonToken.EndArray;
341
 
            SetToken(endToken);
342
 
            return true;
343
 
          }
344
 
          else
345
 
          {
346
 
            throw new JsonReaderException("Read past end of current container context.");
347
 
          }
348
 
        case State.ConstructorStart:
349
 
          break;
350
 
        case State.Constructor:
351
 
          break;
352
 
        case State.Error:
353
 
          break;
354
 
        case State.Finished:
355
 
          break;
356
 
        default:
357
 
          throw new ArgumentOutOfRangeException();
358
 
      }
359
 
 
360
 
      return false;
361
 
    }
362
 
 
363
 
    private void PopContext()
364
 
    {
365
 
      _stack.RemoveAt(_stack.Count - 1);
366
 
      if (_stack.Count == 0)
367
 
        _currentContext = null;
368
 
      else
369
 
        _currentContext = _stack[_stack.Count - 1];
370
 
    }
371
 
 
372
 
    private void PushContext(ContainerContext newContext)
373
 
    {
374
 
      _stack.Add(newContext);
375
 
      _currentContext = newContext;
376
 
    }
377
 
 
378
 
    private byte ReadByte()
379
 
    {
380
 
      MovePosition(1);
381
 
      return _reader.ReadByte();
382
 
    }
383
 
 
384
 
    private void ReadType(BsonType type)
385
 
    {
386
 
      switch (type)
387
 
      {
388
 
        case BsonType.Number:
389
 
          SetToken(JsonToken.Float, ReadDouble());
390
 
          break;
391
 
        case BsonType.String:
392
 
        case BsonType.Symbol:
393
 
          SetToken(JsonToken.String, ReadLengthString());
394
 
          break;
395
 
        case BsonType.Object:
396
 
          {
397
 
            SetToken(JsonToken.StartObject);
398
 
 
399
 
            ContainerContext newContext = new ContainerContext(BsonType.Object);
400
 
            PushContext(newContext);
401
 
            newContext.Length = ReadInt32();
402
 
            break;
403
 
          }
404
 
        case BsonType.Array:
405
 
          {
406
 
            SetToken(JsonToken.StartArray);
407
 
 
408
 
            ContainerContext newContext = new ContainerContext(BsonType.Array);
409
 
            PushContext(newContext);
410
 
            newContext.Length = ReadInt32();
411
 
            break;
412
 
          }
413
 
        case BsonType.Binary:
414
 
          SetToken(JsonToken.Bytes, ReadBinary());
415
 
          break;
416
 
        case BsonType.Undefined:
417
 
          SetToken(JsonToken.Undefined);
418
 
          break;
419
 
        case BsonType.Oid:
420
 
          byte[] oid = ReadBytes(12);
421
 
          SetToken(JsonToken.Bytes, oid);
422
 
          break;
423
 
        case BsonType.Boolean:
424
 
          bool b = Convert.ToBoolean(ReadByte());
425
 
          SetToken(JsonToken.Boolean, b);
426
 
          break;
427
 
        case BsonType.Date:
428
 
          long ticks = ReadInt64();
429
 
          DateTime utcDateTime = JsonConvert.ConvertJavaScriptTicksToDateTime(ticks);
430
 
 
431
 
          DateTime dateTime;
432
 
          switch (DateTimeKindHandling)
433
 
          {
434
 
            case DateTimeKind.Unspecified:
435
 
              dateTime = DateTime.SpecifyKind(utcDateTime.ToLocalTime(), DateTimeKind.Unspecified);
436
 
              break;
437
 
            case DateTimeKind.Local:
438
 
              dateTime = utcDateTime.ToLocalTime();
439
 
              break;
440
 
            default:
441
 
              dateTime = utcDateTime;
442
 
              break;
443
 
          }
444
 
 
445
 
          SetToken(JsonToken.Date, dateTime);
446
 
          break;
447
 
        case BsonType.Null:
448
 
          SetToken(JsonToken.Null);
449
 
          break;
450
 
        case BsonType.Regex:
451
 
          string expression = ReadString();
452
 
          string modifiers = ReadString();
453
 
 
454
 
          string regex = @"/" + expression + @"/" + modifiers;
455
 
          SetToken(JsonToken.String, regex);
456
 
          break;
457
 
        case BsonType.Reference:
458
 
          SetToken(JsonToken.StartObject);
459
 
          _bsonReaderState = BsonReaderState.ReferenceStart;
460
 
          break;
461
 
        case BsonType.Code:
462
 
          SetToken(JsonToken.String, ReadLengthString());
463
 
          break;
464
 
        case BsonType.CodeWScope:
465
 
          SetToken(JsonToken.StartObject);
466
 
          _bsonReaderState = BsonReaderState.CodeWScopeStart;
467
 
          break;
468
 
        case BsonType.Integer:
469
 
          SetToken(JsonToken.Integer, (long)ReadInt32());
470
 
          break;
471
 
        case BsonType.TimeStamp:
472
 
        case BsonType.Long:
473
 
          SetToken(JsonToken.Integer, ReadInt64());
474
 
          break;
475
 
        default:
476
 
          throw new ArgumentOutOfRangeException("type", "Unexpected BsonType value: " + type);
477
 
      }
478
 
    }
479
 
 
480
 
    private byte[] ReadBinary()
481
 
    {
482
 
      int dataLength = ReadInt32();
483
 
 
484
 
      // BsonBinaryType not used
485
 
      ReadByte();
486
 
 
487
 
      return ReadBytes(dataLength);
488
 
    }
489
 
 
490
 
    private string ReadString()
491
 
    {
492
 
      EnsureBuffers();
493
 
 
494
 
      StringBuilder builder = null;
495
 
 
496
 
      int totalBytesRead = 0;
497
 
      // used in case of left over multibyte characters in the buffer
498
 
      int offset = 0;
499
 
      do
500
 
      {
501
 
        int count = offset;
502
 
        byte b;
503
 
        while (count < MaxCharBytesSize && (b = _reader.ReadByte()) > 0)
504
 
        {
505
 
          _byteBuffer[count++] = b;
506
 
        }
507
 
        int byteCount = count - offset;
508
 
        totalBytesRead += byteCount;
509
 
 
510
 
        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
 
          int length = Encoding.UTF8.GetChars(_byteBuffer, 0, byteCount, _charBuffer, 0);
515
 
 
516
 
          MovePosition(totalBytesRead + 1);
517
 
          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
 
          int lastFullCharStop = GetLastFullCharStop(count - 1);
523
 
 
524
 
          int charCount = Encoding.UTF8.GetChars(_byteBuffer, 0, lastFullCharStop + 1, _charBuffer, 0);
525
 
 
526
 
          if (builder == null)
527
 
            builder = new StringBuilder(MaxCharBytesSize * 2);
528
 
 
529
 
          builder.Append(_charBuffer, 0, charCount);
530
 
 
531
 
          if (lastFullCharStop < byteCount - 1)
532
 
          {
533
 
            offset = byteCount - lastFullCharStop - 1;
534
 
            // copy left over multi byte characters to beginning of buffer for next iteration
535
 
            Array.Copy(_byteBuffer, lastFullCharStop + 1, _byteBuffer, 0, offset);
536
 
          }
537
 
          else
538
 
          {
539
 
            // reached end of string
540
 
            if (count < MaxCharBytesSize)
541
 
            {
542
 
              MovePosition(totalBytesRead + 1);
543
 
              return builder.ToString();
544
 
            }
545
 
 
546
 
            offset = 0;
547
 
          }
548
 
        }
549
 
      }
550
 
      while (true);
551
 
    }
552
 
 
553
 
    private string ReadLengthString()
554
 
    {
555
 
      int length = ReadInt32();
556
 
 
557
 
      MovePosition(length);
558
 
 
559
 
      string s = GetString(length - 1);
560
 
      _reader.ReadByte();
561
 
 
562
 
      return s;
563
 
    }
564
 
 
565
 
    private string GetString(int length)
566
 
    {
567
 
      if (length == 0)
568
 
        return string.Empty;
569
 
 
570
 
      EnsureBuffers();
571
 
 
572
 
      StringBuilder builder = null;
573
 
 
574
 
      int totalBytesRead = 0;
575
 
 
576
 
      // used in case of left over multibyte characters in the buffer
577
 
      int offset = 0;
578
 
      do
579
 
      {
580
 
        int count = ((length - totalBytesRead) > MaxCharBytesSize - offset)
581
 
          ? MaxCharBytesSize - offset
582
 
          : length - totalBytesRead;
583
 
 
584
 
        int byteCount = _reader.BaseStream.Read(_byteBuffer, offset, count);
585
 
 
586
 
        if (byteCount == 0)
587
 
          throw new EndOfStreamException("Unable to read beyond the end of the stream.");
588
 
 
589
 
        totalBytesRead += byteCount;
590
 
 
591
 
        // Above, byteCount is how many bytes we read this time.
592
 
        // Below, byteCount is how many bytes are in the _byteBuffer.
593
 
        byteCount += offset;
594
 
 
595
 
        if (byteCount == length)
596
 
        {
597
 
          // pref optimization to avoid reading into a string builder
598
 
          // first iteration and all bytes read then return string directly
599
 
          int charCount = Encoding.UTF8.GetChars(_byteBuffer, 0, byteCount, _charBuffer, 0);
600
 
          return new string(_charBuffer, 0, charCount);
601
 
        }
602
 
        else
603
 
        {
604
 
          int lastFullCharStop = GetLastFullCharStop(byteCount - 1);
605
 
 
606
 
          if (builder == null)
607
 
            builder = new StringBuilder(length);
608
 
 
609
 
          int charCount = Encoding.UTF8.GetChars(_byteBuffer, 0, lastFullCharStop + 1, _charBuffer, 0);
610
 
          builder.Append(_charBuffer, 0, charCount);
611
 
 
612
 
          if (lastFullCharStop < byteCount - 1)
613
 
          {
614
 
            offset = byteCount - lastFullCharStop - 1;
615
 
            // copy left over multi byte characters to beginning of buffer for next iteration
616
 
            Array.Copy(_byteBuffer, lastFullCharStop + 1, _byteBuffer, 0, offset);
617
 
          }
618
 
          else
619
 
          {
620
 
            offset = 0;
621
 
          }
622
 
        }
623
 
      }
624
 
      while (totalBytesRead < length);
625
 
 
626
 
      return builder.ToString();
627
 
    }
628
 
 
629
 
    private int GetLastFullCharStop(int start)
630
 
    {
631
 
      int lookbackPos = start;
632
 
      int bis = 0;
633
 
      while (lookbackPos >= 0)
634
 
      {
635
 
        bis = BytesInSequence(_byteBuffer[lookbackPos]);
636
 
        if (bis == 0)
637
 
        {
638
 
          lookbackPos--;
639
 
          continue;
640
 
        }
641
 
        else if (bis == 1)
642
 
        {
643
 
          break;
644
 
        }
645
 
        else
646
 
        {
647
 
          lookbackPos--;
648
 
          break;
649
 
        }
650
 
      }
651
 
      if (bis == start - lookbackPos)
652
 
      {
653
 
        //Full character.
654
 
        return start;
655
 
      }
656
 
      else
657
 
      {
658
 
        return lookbackPos;
659
 
      }
660
 
    }
661
 
 
662
 
    private int BytesInSequence(byte b)
663
 
    {
664
 
      if (b <= _seqRange1[1]) return 1;
665
 
      if (b >= _seqRange2[0] && b <= _seqRange2[1]) return 2;
666
 
      if (b >= _seqRange3[0] && b <= _seqRange3[1]) return 3;
667
 
      if (b >= _seqRange4[0] && b <= _seqRange4[1]) return 4;
668
 
      return 0;
669
 
    }
670
 
 
671
 
    private void EnsureBuffers()
672
 
    {
673
 
      if (_byteBuffer == null)
674
 
      {
675
 
        _byteBuffer = new byte[MaxCharBytesSize];
676
 
      }
677
 
      if (_charBuffer == null)
678
 
      {
679
 
        int charBufferSize = Encoding.UTF8.GetMaxCharCount(MaxCharBytesSize);
680
 
        _charBuffer = new char[charBufferSize];
681
 
      }
682
 
    }
683
 
 
684
 
    private double ReadDouble()
685
 
    {
686
 
      MovePosition(8);
687
 
      return _reader.ReadDouble();
688
 
    }
689
 
 
690
 
    private int ReadInt32()
691
 
    {
692
 
      MovePosition(4);
693
 
      return _reader.ReadInt32();
694
 
    }
695
 
 
696
 
    private long ReadInt64()
697
 
    {
698
 
      MovePosition(8);
699
 
      return _reader.ReadInt64();
700
 
    }
701
 
 
702
 
    private BsonType ReadType()
703
 
    {
704
 
      MovePosition(1);
705
 
      return (BsonType)_reader.ReadSByte();
706
 
    }
707
 
 
708
 
    private void MovePosition(int count)
709
 
    {
710
 
      _currentContext.Position += count;
711
 
    }
712
 
 
713
 
    private byte[] ReadBytes(int count)
714
 
    {
715
 
      MovePosition(count);
716
 
      return _reader.ReadBytes(count);
717
 
    }
718
 
  }
 
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
 
 
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>
 
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>
 
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>
 
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>
 
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
 
 
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>
 
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>
 
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>
 
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>
 
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>
 
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>
 
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>
 
241
    public override bool Read()
 
242
    {
 
243
      _readType = Json.ReadType.Read;
 
244
 
 
245
      return ReadInternal();
 
246
    }
 
247
 
 
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>
 
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
 
 
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
 
 
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
 
 
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
 
 
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
 
 
490
    private void PushContext(ContainerContext newContext)
 
491
    {
 
492
      _stack.Add(newContext);
 
493
      _currentContext = newContext;
 
494
    }
 
495
 
 
496
    private byte ReadByte()
 
497
    {
 
498
      MovePosition(1);
 
499
      return _reader.ReadByte();
 
500
    }
 
501
 
 
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
 
 
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
 
 
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
 
 
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
 
 
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
 
 
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
 
 
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
 
 
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
 
 
807
    private double ReadDouble()
 
808
    {
 
809
      MovePosition(8);
 
810
      return _reader.ReadDouble();
 
811
    }
 
812
 
 
813
    private int ReadInt32()
 
814
    {
 
815
      MovePosition(4);
 
816
      return _reader.ReadInt32();
 
817
    }
 
818
 
 
819
    private long ReadInt64()
 
820
    {
 
821
      MovePosition(8);
 
822
      return _reader.ReadInt64();
 
823
    }
 
824
 
 
825
    private BsonType ReadType()
 
826
    {
 
827
      MovePosition(1);
 
828
      return (BsonType) _reader.ReadSByte();
 
829
    }
 
830
 
 
831
    private void MovePosition(int count)
 
832
    {
 
833
      _currentContext.Position += count;
 
834
    }
 
835
 
 
836
    private byte[] ReadBytes(int count)
 
837
    {
 
838
      MovePosition(count);
 
839
      return _reader.ReadBytes(count);
 
840
    }
 
841
  }
719
842
}
 
 
b'\\ No newline at end of file'