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

« back to all changes in this revision

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