~ubuntu-branches/ubuntu/trusty/monodevelop/trusty-proposed

« back to all changes in this revision

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

  • Committer: Package Import Robot
  • Author(s): Jo Shields
  • Date: 2013-05-12 09:46:03 UTC
  • mto: This revision was merged to the branch mainline in revision 29.
  • Revision ID: package-import@ubuntu.com-20130512094603-mad323bzcxvmcam0
Tags: upstream-4.0.5+dfsg
ImportĀ upstreamĀ versionĀ 4.0.5+dfsg

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 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
  }
 
842
}
 
 
b'\\ No newline at end of file'