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

« back to all changes in this revision

Viewing changes to external/Newtonsoft.Json/Src/Newtonsoft.Json/JsonReader.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.IO;
 
29
using System.Globalization;
 
30
using Newtonsoft.Json.Utilities;
 
31
#if NET20
 
32
using Newtonsoft.Json.Utilities.LinqBridge;
 
33
#else
 
34
using System.Linq;
 
35
#endif
 
36
 
 
37
namespace Newtonsoft.Json
 
38
{
 
39
  /// <summary>
 
40
  /// Represents a reader that provides fast, non-cached, forward-only access to serialized Json data.
 
41
  /// </summary>
 
42
  public abstract class JsonReader : IDisposable
 
43
  {
 
44
    /// <summary>
 
45
    /// Specifies the state of the reader.
 
46
    /// </summary>
 
47
    protected internal enum State
 
48
    {
 
49
      /// <summary>
 
50
      /// The Read method has not been called.
 
51
      /// </summary>
 
52
      Start,
 
53
      /// <summary>
 
54
      /// The end of the file has been reached successfully.
 
55
      /// </summary>
 
56
      Complete,
 
57
      /// <summary>
 
58
      /// Reader is at a property.
 
59
      /// </summary>
 
60
      Property,
 
61
      /// <summary>
 
62
      /// Reader is at the start of an object.
 
63
      /// </summary>
 
64
      ObjectStart,
 
65
      /// <summary>
 
66
      /// Reader is in an object.
 
67
      /// </summary>
 
68
      Object,
 
69
      /// <summary>
 
70
      /// Reader is at the start of an array.
 
71
      /// </summary>
 
72
      ArrayStart,
 
73
      /// <summary>
 
74
      /// Reader is in an array.
 
75
      /// </summary>
 
76
      Array,
 
77
      /// <summary>
 
78
      /// The Close method has been called.
 
79
      /// </summary>
 
80
      Closed,
 
81
      /// <summary>
 
82
      /// Reader has just read a value.
 
83
      /// </summary>
 
84
      PostValue,
 
85
      /// <summary>
 
86
      /// Reader is at the start of a constructor.
 
87
      /// </summary>
 
88
      ConstructorStart,
 
89
      /// <summary>
 
90
      /// Reader in a constructor.
 
91
      /// </summary>
 
92
      Constructor,
 
93
      /// <summary>
 
94
      /// An error occurred that prevents the read operation from continuing.
 
95
      /// </summary>
 
96
      Error,
 
97
      /// <summary>
 
98
      /// The end of the file has been reached successfully.
 
99
      /// </summary>
 
100
      Finished
 
101
    }
 
102
 
 
103
    // current Token data
 
104
    private JsonToken _tokenType;
 
105
    private object _value;
 
106
    private char _quoteChar;
 
107
    internal State _currentState;
 
108
    internal ReadType _readType;
 
109
    private JsonPosition _currentPosition;
 
110
    private CultureInfo _culture;
 
111
    private DateTimeZoneHandling _dateTimeZoneHandling;
 
112
    private int? _maxDepth;
 
113
    private bool _hasExceededMaxDepth;
 
114
    internal DateParseHandling _dateParseHandling;
 
115
    private readonly List<JsonPosition> _stack;
 
116
 
 
117
    /// <summary>
 
118
    /// Gets the current reader state.
 
119
    /// </summary>
 
120
    /// <value>The current reader state.</value>
 
121
    protected State CurrentState
 
122
    {
 
123
      get { return _currentState; }
 
124
    }
 
125
 
 
126
    /// <summary>
 
127
    /// Gets or sets a value indicating whether the underlying stream or
 
128
    /// <see cref="TextReader"/> should be closed when the reader is closed.
 
129
    /// </summary>
 
130
    /// <value>
 
131
    /// true to close the underlying stream or <see cref="TextReader"/> when
 
132
    /// the reader is closed; otherwise false. The default is true.
 
133
    /// </value>
 
134
    public bool CloseInput { get; set; }
 
135
 
 
136
    /// <summary>
 
137
    /// Gets the quotation mark character used to enclose the value of a string.
 
138
    /// </summary>
 
139
    public virtual char QuoteChar
 
140
    {
 
141
      get { return _quoteChar; }
 
142
      protected internal set { _quoteChar = value; }
 
143
    }
 
144
 
 
145
    /// <summary>
 
146
    /// Get or set how <see cref="DateTime"/> time zones are handling when reading JSON.
 
147
    /// </summary>
 
148
    public DateTimeZoneHandling DateTimeZoneHandling
 
149
    {
 
150
      get { return _dateTimeZoneHandling; }
 
151
      set { _dateTimeZoneHandling = value; }
 
152
    }
 
153
 
 
154
    /// <summary>
 
155
    /// Get or set how date formatted strings, e.g. "\/Date(1198908717056)\/" and "2012-03-21T05:40Z", are parsed when reading JSON.
 
156
    /// </summary>
 
157
    public DateParseHandling DateParseHandling
 
158
    {
 
159
      get { return _dateParseHandling; }
 
160
      set { _dateParseHandling = value; }
 
161
    }
 
162
 
 
163
    /// <summary>
 
164
    /// Gets or sets the maximum depth allowed when reading JSON. Reading past this depth will throw a <see cref="JsonReaderException"/>.
 
165
    /// </summary>
 
166
    public int? MaxDepth
 
167
    {
 
168
      get { return _maxDepth; }
 
169
      set
 
170
      {
 
171
        if (value <= 0)
 
172
          throw new ArgumentException("Value must be positive.", "value");
 
173
 
 
174
        _maxDepth = value;
 
175
      }
 
176
    }
 
177
 
 
178
    /// <summary>
 
179
    /// Gets the type of the current JSON token. 
 
180
    /// </summary>
 
181
    public virtual JsonToken TokenType
 
182
    {
 
183
      get { return _tokenType; }
 
184
    }
 
185
 
 
186
    /// <summary>
 
187
    /// Gets the text value of the current JSON token.
 
188
    /// </summary>
 
189
    public virtual object Value
 
190
    {
 
191
      get { return _value; }
 
192
    }
 
193
 
 
194
    /// <summary>
 
195
    /// Gets The Common Language Runtime (CLR) type for the current JSON token.
 
196
    /// </summary>
 
197
    public virtual Type ValueType
 
198
    {
 
199
      get { return (_value != null) ? _value.GetType() : null; }
 
200
    }
 
201
 
 
202
    /// <summary>
 
203
    /// Gets the depth of the current token in the JSON document.
 
204
    /// </summary>
 
205
    /// <value>The depth of the current token in the JSON document.</value>
 
206
    public virtual int Depth
 
207
    {
 
208
      get
 
209
      {
 
210
        int depth = _stack.Count;
 
211
        if (IsStartToken(TokenType) || _currentPosition.Type == JsonContainerType.None)
 
212
          return depth;
 
213
        else
 
214
          return depth + 1;
 
215
      }
 
216
    }
 
217
 
 
218
    /// <summary>
 
219
    /// Gets the path of the current JSON token. 
 
220
    /// </summary>
 
221
    public virtual string Path
 
222
    {
 
223
      get
 
224
      {
 
225
        if (_currentPosition.Type == JsonContainerType.None)
 
226
          return string.Empty;
 
227
 
 
228
        bool insideContainer = (_currentState != State.ArrayStart
 
229
          && _currentState != State.ConstructorStart
 
230
          && _currentState != State.ObjectStart);
 
231
 
 
232
        IEnumerable<JsonPosition> positions = (!insideContainer)
 
233
          ? _stack
 
234
          : _stack.Concat(new[] {_currentPosition});
 
235
 
 
236
        return JsonPosition.BuildPath(positions);
 
237
      }
 
238
    }
 
239
 
 
240
    /// <summary>
 
241
    /// Gets or sets the culture used when reading JSON. Defaults to <see cref="CultureInfo.InvariantCulture"/>.
 
242
    /// </summary>
 
243
    public CultureInfo Culture
 
244
    {
 
245
      get { return _culture ?? CultureInfo.InvariantCulture; }
 
246
      set { _culture = value; }
 
247
    }
 
248
 
 
249
    internal JsonPosition GetPosition(int depth)
 
250
    {
 
251
      if (depth < _stack.Count)
 
252
        return _stack[depth];
 
253
 
 
254
      return _currentPosition;
 
255
    }
 
256
 
 
257
    /// <summary>
 
258
    /// Initializes a new instance of the <see cref="JsonReader"/> class with the specified <see cref="TextReader"/>.
 
259
    /// </summary>
 
260
    protected JsonReader()
 
261
    {
 
262
      _currentState = State.Start;
 
263
      _stack = new List<JsonPosition>(4);
 
264
      _dateTimeZoneHandling = DateTimeZoneHandling.RoundtripKind;
 
265
      _dateParseHandling = DateParseHandling.DateTime;
 
266
 
 
267
      CloseInput = true;
 
268
    }
 
269
 
 
270
    private void Push(JsonContainerType value)
 
271
    {
 
272
      UpdateScopeWithFinishedValue();
 
273
 
 
274
      if (_currentPosition.Type == JsonContainerType.None)
 
275
      {
 
276
        _currentPosition = new JsonPosition(value);
 
277
      }
 
278
      else
 
279
      {
 
280
        _stack.Add(_currentPosition);
 
281
        _currentPosition = new JsonPosition(value);
 
282
 
 
283
        // this is a little hacky because Depth increases when first property/value is written but only testing here is faster/simpler
 
284
        if (_maxDepth != null && Depth + 1 > _maxDepth && !_hasExceededMaxDepth)
 
285
        {
 
286
          _hasExceededMaxDepth = true;
 
287
          throw JsonReaderException.Create(this, "The reader's MaxDepth of {0} has been exceeded.".FormatWith(CultureInfo.InvariantCulture, _maxDepth));
 
288
        }
 
289
      }
 
290
    }
 
291
 
 
292
    private JsonContainerType Pop()
 
293
    {
 
294
      JsonPosition oldPosition;
 
295
      if (_stack.Count > 0)
 
296
      {
 
297
        oldPosition = _currentPosition;
 
298
        _currentPosition = _stack[_stack.Count - 1];
 
299
        _stack.RemoveAt(_stack.Count - 1);
 
300
      }
 
301
      else
 
302
      {
 
303
        oldPosition = _currentPosition;
 
304
        _currentPosition = new JsonPosition();
 
305
      }
 
306
 
 
307
      if (_maxDepth != null && Depth <= _maxDepth)
 
308
        _hasExceededMaxDepth = false;
 
309
 
 
310
      return oldPosition.Type;
 
311
    }
 
312
 
 
313
    private JsonContainerType Peek()
 
314
    {
 
315
      return _currentPosition.Type;
 
316
    }
 
317
 
 
318
    /// <summary>
 
319
    /// Reads the next JSON token from the stream.
 
320
    /// </summary>
 
321
    /// <returns>true if the next token was read successfully; false if there are no more tokens to read.</returns>
 
322
    public abstract bool Read();
 
323
 
 
324
    /// <summary>
 
325
    /// Reads the next JSON token from the stream as a <see cref="Nullable{Int32}"/>.
 
326
    /// </summary>
 
327
    /// <returns>A <see cref="Nullable{Int32}"/>. This method will return <c>null</c> at the end of an array.</returns>
 
328
    public abstract int? ReadAsInt32();
 
329
 
 
330
    /// <summary>
 
331
    /// Reads the next JSON token from the stream as a <see cref="String"/>.
 
332
    /// </summary>
 
333
    /// <returns>A <see cref="String"/>. This method will return <c>null</c> at the end of an array.</returns>
 
334
    public abstract string ReadAsString();
 
335
 
 
336
    /// <summary>
 
337
    /// Reads the next JSON token from the stream as a <see cref="T:Byte[]"/>.
 
338
    /// </summary>
 
339
    /// <returns>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.</returns>
 
340
    public abstract byte[] ReadAsBytes();
 
341
 
 
342
    /// <summary>
 
343
    /// Reads the next JSON token from the stream as a <see cref="Nullable{Decimal}"/>.
 
344
    /// </summary>
 
345
    /// <returns>A <see cref="Nullable{Decimal}"/>. This method will return <c>null</c> at the end of an array.</returns>
 
346
    public abstract decimal? ReadAsDecimal();
 
347
 
 
348
    /// <summary>
 
349
    /// Reads the next JSON token from the stream as a <see cref="Nullable{DateTime}"/>.
 
350
    /// </summary>
 
351
    /// <returns>A <see cref="String"/>. This method will return <c>null</c> at the end of an array.</returns>
 
352
    public abstract DateTime? ReadAsDateTime();
 
353
 
 
354
#if !NET20
 
355
    /// <summary>
 
356
    /// Reads the next JSON token from the stream as a <see cref="Nullable{DateTimeOffset}"/>.
 
357
    /// </summary>
 
358
    /// <returns>A <see cref="Nullable{DateTimeOffset}"/>. This method will return <c>null</c> at the end of an array.</returns>
 
359
    public abstract DateTimeOffset? ReadAsDateTimeOffset();
 
360
#endif
 
361
 
 
362
    internal virtual bool ReadInternal()
 
363
    {
 
364
      throw new NotImplementedException();
 
365
    }
 
366
 
 
367
#if !NET20
 
368
    internal DateTimeOffset? ReadAsDateTimeOffsetInternal()
 
369
    {
 
370
      _readType = ReadType.ReadAsDateTimeOffset;
 
371
 
 
372
      do
 
373
      {
 
374
        if (!ReadInternal())
 
375
        {
 
376
          SetToken(JsonToken.None);
 
377
          return null;
 
378
        }
 
379
      } while (TokenType == JsonToken.Comment);
 
380
 
 
381
      if (TokenType == JsonToken.Date)
 
382
      {
 
383
        if (Value is DateTime)
 
384
          SetToken(JsonToken.Date, new DateTimeOffset((DateTime)Value));
 
385
 
 
386
        return (DateTimeOffset)Value;
 
387
      }
 
388
 
 
389
      if (TokenType == JsonToken.Null)
 
390
        return null;
 
391
 
 
392
      DateTimeOffset dt;
 
393
      if (TokenType == JsonToken.String)
 
394
      {
 
395
        string s = (string)Value;
 
396
        if (string.IsNullOrEmpty(s))
 
397
        {
 
398
          SetToken(JsonToken.Null);
 
399
          return null;
 
400
        }
 
401
 
 
402
        if (DateTimeOffset.TryParse(s, Culture, DateTimeStyles.RoundtripKind, out dt))
 
403
        {
 
404
          SetToken(JsonToken.Date, dt);
 
405
          return dt;
 
406
        }
 
407
        else
 
408
        {
 
409
          throw JsonReaderException.Create(this, "Could not convert string to DateTimeOffset: {0}.".FormatWith(CultureInfo.InvariantCulture, Value));
 
410
        }
 
411
      }
 
412
 
 
413
      if (TokenType == JsonToken.EndArray)
 
414
        return null;
 
415
 
 
416
      throw JsonReaderException.Create(this, "Error reading date. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType));
 
417
    }
 
418
#endif
 
419
 
 
420
    internal byte[] ReadAsBytesInternal()
 
421
    {
 
422
      _readType = ReadType.ReadAsBytes;
 
423
 
 
424
      do
 
425
      {
 
426
        if (!ReadInternal())
 
427
        {
 
428
          SetToken(JsonToken.None);
 
429
          return null;
 
430
        }
 
431
      } while (TokenType == JsonToken.Comment);
 
432
 
 
433
      if (IsWrappedInTypeObject())
 
434
      {
 
435
        byte[] data = ReadAsBytes();
 
436
        ReadInternal();
 
437
        SetToken(JsonToken.Bytes, data);
 
438
        return data;
 
439
      }
 
440
 
 
441
      // attempt to convert possible base 64 string to bytes
 
442
      if (TokenType == JsonToken.String)
 
443
      {
 
444
        string s = (string)Value;
 
445
        byte[] data = (s.Length == 0) ? new byte[0] : Convert.FromBase64String(s);
 
446
        SetToken(JsonToken.Bytes, data);
 
447
      }
 
448
 
 
449
      if (TokenType == JsonToken.Null)
 
450
        return null;
 
451
 
 
452
      if (TokenType == JsonToken.Bytes)
 
453
        return (byte[])Value;
 
454
 
 
455
      if (TokenType == JsonToken.StartArray)
 
456
      {
 
457
        List<byte> data = new List<byte>();
 
458
 
 
459
        while (ReadInternal())
 
460
        {
 
461
          switch (TokenType)
 
462
          {
 
463
            case JsonToken.Integer:
 
464
              data.Add(Convert.ToByte(Value, CultureInfo.InvariantCulture));
 
465
              break;
 
466
            case JsonToken.EndArray:
 
467
              byte[] d = data.ToArray();
 
468
              SetToken(JsonToken.Bytes, d);
 
469
              return d;
 
470
            case JsonToken.Comment:
 
471
              // skip
 
472
              break;
 
473
            default:
 
474
              throw JsonReaderException.Create(this, "Unexpected token when reading bytes: {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType));
 
475
          }
 
476
        }
 
477
 
 
478
        throw JsonReaderException.Create(this, "Unexpected end when reading bytes.");
 
479
      }
 
480
 
 
481
      if (TokenType == JsonToken.EndArray)
 
482
        return null;
 
483
 
 
484
      throw JsonReaderException.Create(this, "Error reading bytes. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType));
 
485
    }
 
486
 
 
487
    internal decimal? ReadAsDecimalInternal()
 
488
    {
 
489
      _readType = ReadType.ReadAsDecimal;
 
490
 
 
491
      do
 
492
      {
 
493
        if (!ReadInternal())
 
494
        {
 
495
          SetToken(JsonToken.None);
 
496
          return null;
 
497
        }
 
498
      } while (TokenType == JsonToken.Comment);
 
499
 
 
500
      if (TokenType == JsonToken.Integer || TokenType == JsonToken.Float)
 
501
      {
 
502
        if (!(Value is decimal))
 
503
          SetToken(JsonToken.Float, Convert.ToDecimal(Value, CultureInfo.InvariantCulture));
 
504
 
 
505
        return (decimal)Value;
 
506
      }
 
507
 
 
508
      if (TokenType == JsonToken.Null)
 
509
        return null;
 
510
 
 
511
      decimal d;
 
512
      if (TokenType == JsonToken.String)
 
513
      {
 
514
        string s = (string)Value;
 
515
        if (string.IsNullOrEmpty(s))
 
516
        {
 
517
          SetToken(JsonToken.Null);
 
518
          return null;
 
519
        }
 
520
 
 
521
        if (decimal.TryParse(s, NumberStyles.Number, Culture, out d))
 
522
        {
 
523
          SetToken(JsonToken.Float, d);
 
524
          return d;
 
525
        }
 
526
        else
 
527
        {
 
528
          throw JsonReaderException.Create(this, "Could not convert string to decimal: {0}.".FormatWith(CultureInfo.InvariantCulture, Value));
 
529
        }
 
530
      }
 
531
 
 
532
      if (TokenType == JsonToken.EndArray)
 
533
        return null;
 
534
 
 
535
      throw JsonReaderException.Create(this, "Error reading decimal. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType));
 
536
    }
 
537
 
 
538
    internal int? ReadAsInt32Internal()
 
539
    {
 
540
      _readType = ReadType.ReadAsInt32;
 
541
 
 
542
      do
 
543
      {
 
544
        if (!ReadInternal())
 
545
        {
 
546
          SetToken(JsonToken.None);
 
547
          return null;
 
548
        }
 
549
      } while (TokenType == JsonToken.Comment);
 
550
 
 
551
      if (TokenType == JsonToken.Integer || TokenType == JsonToken.Float)
 
552
      {
 
553
        if (!(Value is int))
 
554
          SetToken(JsonToken.Integer, Convert.ToInt32(Value, CultureInfo.InvariantCulture));
 
555
 
 
556
        return (int)Value;
 
557
      }
 
558
 
 
559
      if (TokenType == JsonToken.Null)
 
560
        return null;
 
561
 
 
562
      int i;
 
563
      if (TokenType == JsonToken.String)
 
564
      {
 
565
        string s = (string)Value;
 
566
        if (string.IsNullOrEmpty(s))
 
567
        {
 
568
          SetToken(JsonToken.Null);
 
569
          return null;
 
570
        }
 
571
 
 
572
        if (int.TryParse(s, NumberStyles.Integer, Culture, out i))
 
573
        {
 
574
          SetToken(JsonToken.Integer, i);
 
575
          return i;
 
576
        }
 
577
        else
 
578
        {
 
579
          throw JsonReaderException.Create(this, "Could not convert string to integer: {0}.".FormatWith(CultureInfo.InvariantCulture, Value));
 
580
        }
 
581
      }
 
582
 
 
583
      if (TokenType == JsonToken.EndArray)
 
584
        return null;
 
585
 
 
586
      throw JsonReaderException.Create(this, "Error reading integer. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType));
 
587
    }
 
588
 
 
589
    internal string ReadAsStringInternal()
 
590
    {
 
591
      _readType = ReadType.ReadAsString;
 
592
 
 
593
      do
 
594
      {
 
595
        if (!ReadInternal())
 
596
        {
 
597
          SetToken(JsonToken.None);
 
598
          return null;
 
599
        }
 
600
      } while (TokenType == JsonToken.Comment);
 
601
 
 
602
      if (TokenType == JsonToken.String)
 
603
        return (string)Value;
 
604
 
 
605
      if (TokenType == JsonToken.Null)
 
606
        return null;
 
607
 
 
608
      if (IsPrimitiveToken(TokenType))
 
609
      {
 
610
        if (Value != null)
 
611
        {
 
612
          string s;
 
613
          if (ConvertUtils.IsConvertible(Value))
 
614
            s = ConvertUtils.ToConvertible(Value).ToString(Culture);
 
615
          else if (Value is IFormattable)
 
616
            s = ((IFormattable)Value).ToString(null, Culture);
 
617
          else
 
618
            s = Value.ToString();
 
619
 
 
620
          SetToken(JsonToken.String, s);
 
621
          return s;
 
622
        }
 
623
      }
 
624
 
 
625
      if (TokenType == JsonToken.EndArray)
 
626
        return null;
 
627
 
 
628
      throw JsonReaderException.Create(this, "Error reading string. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType));
 
629
    }
 
630
 
 
631
    internal DateTime? ReadAsDateTimeInternal()
 
632
    {
 
633
      _readType = ReadType.ReadAsDateTime;
 
634
 
 
635
      do
 
636
      {
 
637
        if (!ReadInternal())
 
638
        {
 
639
          SetToken(JsonToken.None);
 
640
          return null;
 
641
        }
 
642
      } while (TokenType == JsonToken.Comment);
 
643
 
 
644
      if (TokenType == JsonToken.Date)
 
645
        return (DateTime)Value;
 
646
 
 
647
      if (TokenType == JsonToken.Null)
 
648
        return null;
 
649
 
 
650
      DateTime dt;
 
651
      if (TokenType == JsonToken.String)
 
652
      {
 
653
        string s = (string)Value;
 
654
        if (string.IsNullOrEmpty(s))
 
655
        {
 
656
          SetToken(JsonToken.Null);
 
657
          return null;
 
658
        }
 
659
 
 
660
        if (DateTime.TryParse(s, Culture, DateTimeStyles.RoundtripKind, out dt))
 
661
        {
 
662
          dt = JsonConvert.EnsureDateTime(dt, DateTimeZoneHandling);
 
663
          SetToken(JsonToken.Date, dt);
 
664
          return dt;
 
665
        }
 
666
        else
 
667
        {
 
668
          throw JsonReaderException.Create(this, "Could not convert string to DateTime: {0}.".FormatWith(CultureInfo.InvariantCulture, Value));
 
669
        }
 
670
      }
 
671
 
 
672
      if (TokenType == JsonToken.EndArray)
 
673
        return null;
 
674
 
 
675
      throw JsonReaderException.Create(this, "Error reading date. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType));
 
676
    }
 
677
 
 
678
    private bool IsWrappedInTypeObject()
 
679
    {
 
680
      _readType = ReadType.Read;
 
681
 
 
682
      if (TokenType == JsonToken.StartObject)
 
683
      {
 
684
        if (!ReadInternal())
 
685
          throw JsonReaderException.Create(this, "Unexpected end when reading bytes.");
 
686
 
 
687
        if (Value.ToString() == "$type")
 
688
        {
 
689
          ReadInternal();
 
690
          if (Value != null && Value.ToString().StartsWith("System.Byte[]"))
 
691
          {
 
692
            ReadInternal();
 
693
            if (Value.ToString() == "$value")
 
694
            {
 
695
              return true;
 
696
            }
 
697
          }
 
698
        }
 
699
 
 
700
        throw JsonReaderException.Create(this, "Error reading bytes. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, JsonToken.StartObject));
 
701
      }
 
702
 
 
703
      return false;
 
704
    }
 
705
 
 
706
    /// <summary>
 
707
    /// Skips the children of the current token.
 
708
    /// </summary>
 
709
    public void Skip()
 
710
    {
 
711
      if (TokenType == JsonToken.PropertyName)
 
712
        Read();
 
713
 
 
714
      if (IsStartToken(TokenType))
 
715
      {
 
716
        int depth = Depth;
 
717
 
 
718
        while (Read() && (depth < Depth))
 
719
        {
 
720
        }
 
721
      }
 
722
    }
 
723
 
 
724
    /// <summary>
 
725
    /// Sets the current token.
 
726
    /// </summary>
 
727
    /// <param name="newToken">The new token.</param>
 
728
    protected void SetToken(JsonToken newToken)
 
729
    {
 
730
      SetToken(newToken, null);
 
731
    }
 
732
 
 
733
    /// <summary>
 
734
    /// Sets the current token and value.
 
735
    /// </summary>
 
736
    /// <param name="newToken">The new token.</param>
 
737
    /// <param name="value">The value.</param>
 
738
    protected void SetToken(JsonToken newToken, object value)
 
739
    {
 
740
      _tokenType = newToken;
 
741
      _value = value;
 
742
 
 
743
      switch (newToken)
 
744
      {
 
745
        case JsonToken.StartObject:
 
746
          _currentState = State.ObjectStart;
 
747
          Push(JsonContainerType.Object);
 
748
          break;
 
749
        case JsonToken.StartArray:
 
750
          _currentState = State.ArrayStart;
 
751
          Push(JsonContainerType.Array);
 
752
          break;
 
753
        case JsonToken.StartConstructor:
 
754
          _currentState = State.ConstructorStart;
 
755
          Push(JsonContainerType.Constructor);
 
756
          break;
 
757
        case JsonToken.EndObject:
 
758
          ValidateEnd(JsonToken.EndObject);
 
759
          break;
 
760
        case JsonToken.EndArray:
 
761
          ValidateEnd(JsonToken.EndArray);
 
762
          break;
 
763
        case JsonToken.EndConstructor:
 
764
          ValidateEnd(JsonToken.EndConstructor);
 
765
          break;
 
766
        case JsonToken.PropertyName:
 
767
          _currentState = State.Property;
 
768
 
 
769
          _currentPosition.PropertyName = (string) value;
 
770
          break;
 
771
        case JsonToken.Undefined:
 
772
        case JsonToken.Integer:
 
773
        case JsonToken.Float:
 
774
        case JsonToken.Boolean:
 
775
        case JsonToken.Null:
 
776
        case JsonToken.Date:
 
777
        case JsonToken.String:
 
778
        case JsonToken.Raw:
 
779
        case JsonToken.Bytes:
 
780
          _currentState = (Peek() != JsonContainerType.None) ? State.PostValue : State.Finished;
 
781
 
 
782
          UpdateScopeWithFinishedValue();
 
783
          break;
 
784
      }
 
785
    }
 
786
 
 
787
    private void UpdateScopeWithFinishedValue()
 
788
    {
 
789
      if (_currentPosition.HasIndex)
 
790
        _currentPosition.Position++;
 
791
    }
 
792
 
 
793
    private void ValidateEnd(JsonToken endToken)
 
794
    {
 
795
      JsonContainerType currentObject = Pop();
 
796
 
 
797
      if (GetTypeForCloseToken(endToken) != currentObject)
 
798
        throw JsonReaderException.Create(this, "JsonToken {0} is not valid for closing JsonType {1}.".FormatWith(CultureInfo.InvariantCulture, endToken, currentObject));
 
799
 
 
800
      _currentState = (Peek() != JsonContainerType.None) ? State.PostValue : State.Finished;
 
801
    }
 
802
 
 
803
    /// <summary>
 
804
    /// Sets the state based on current token type.
 
805
    /// </summary>
 
806
    protected void SetStateBasedOnCurrent()
 
807
    {
 
808
      JsonContainerType currentObject = Peek();
 
809
 
 
810
      switch (currentObject)
 
811
      {
 
812
        case JsonContainerType.Object:
 
813
          _currentState = State.Object;
 
814
          break;
 
815
        case JsonContainerType.Array:
 
816
          _currentState = State.Array;
 
817
          break;
 
818
        case JsonContainerType.Constructor:
 
819
          _currentState = State.Constructor;
 
820
          break;
 
821
        case JsonContainerType.None:
 
822
          _currentState = State.Finished;
 
823
          break;
 
824
        default:
 
825
          throw JsonReaderException.Create(this, "While setting the reader state back to current object an unexpected JsonType was encountered: {0}".FormatWith(CultureInfo.InvariantCulture, currentObject));
 
826
      }
 
827
    }
 
828
 
 
829
    internal static bool IsPrimitiveToken(JsonToken token)
 
830
    {
 
831
      switch (token)
 
832
      {
 
833
        case JsonToken.Integer:
 
834
        case JsonToken.Float:
 
835
        case JsonToken.String:
 
836
        case JsonToken.Boolean:
 
837
        case JsonToken.Undefined:
 
838
        case JsonToken.Null:
 
839
        case JsonToken.Date:
 
840
        case JsonToken.Bytes:
 
841
          return true;
 
842
        default:
 
843
          return false;
 
844
      }
 
845
    }
 
846
 
 
847
    internal static bool IsStartToken(JsonToken token)
 
848
    {
 
849
      switch (token)
 
850
      {
 
851
        case JsonToken.StartObject:
 
852
        case JsonToken.StartArray:
 
853
        case JsonToken.StartConstructor:
 
854
          return true;
 
855
        default:
 
856
          return false;
 
857
      }
 
858
    }
 
859
 
 
860
    private JsonContainerType GetTypeForCloseToken(JsonToken token)
 
861
    {
 
862
      switch (token)
 
863
      {
 
864
        case JsonToken.EndObject:
 
865
          return JsonContainerType.Object;
 
866
        case JsonToken.EndArray:
 
867
          return JsonContainerType.Array;
 
868
        case JsonToken.EndConstructor:
 
869
          return JsonContainerType.Constructor;
 
870
        default:
 
871
          throw JsonReaderException.Create(this, "Not a valid close JsonToken: {0}".FormatWith(CultureInfo.InvariantCulture, token));
 
872
      }
 
873
    }
 
874
 
 
875
    /// <summary>
 
876
    /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
 
877
    /// </summary>
 
878
    void IDisposable.Dispose()
 
879
    {
 
880
      Dispose(true);
 
881
    }
 
882
 
 
883
    /// <summary>
 
884
    /// Releases unmanaged and - optionally - managed resources
 
885
    /// </summary>
 
886
    /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
 
887
    protected virtual void Dispose(bool disposing)
 
888
    {
 
889
      if (_currentState != State.Closed && disposing)
 
890
        Close();
 
891
    }
 
892
 
 
893
    /// <summary>
 
894
    /// Changes the <see cref="State"/> to Closed. 
 
895
    /// </summary>
 
896
    public virtual void Close()
 
897
    {
 
898
      _currentState = State.Closed;
 
899
      _tokenType = JsonToken.None;
 
900
      _value = null;
 
901
    }
 
902
  }
 
903
}
 
 
b'\\ No newline at end of file'