Json.NET
Code Coverage Statistics for Source File

Newtonsoft.Json\JsonReader.cs

Symbol Coverage: 94.59% (105 of 111)

Branch Coverage: 85.71% (36 of 42)

Cyclomatic Complexity Avg: 2.14 Max:12

Code Lines: 105


L V Source
1
#region License
2
// Copyright (c) 2007 James Newton-King
3
//
4
// Permission is hereby granted, free of charge, to any person
5
// obtaining a copy of this software and associated documentation
6
// files (the "Software"), to deal in the Software without
7
// restriction, including without limitation the rights to use,
8
// copy, modify, merge, publish, distribute, sublicense, and/or sell
9
// copies of the Software, and to permit persons to whom the
10
// Software is furnished to do so, subject to the following
11
// conditions:
12
//
13
// The above copyright notice and this permission notice shall be
14
// included in all copies or substantial portions of the Software.
15
//
16
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
18
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23
// OTHER DEALINGS IN THE SOFTWARE.
24
#endregion
25

  
26
using System;
27
using System.Collections.Generic;
28
using System.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
 604561
      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
 7
      get { return _quoteChar; }
126
 138180
      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
 1023337
      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
 505171
      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
 40
      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
 70727
        int depth = _top - 1;
162
 70727
        if (IsStartToken(TokenType))
163
 70488
          return depth - 1;
164
        else
165
 239
          return depth;
166
 70727
      }
167
    }
168

  
169
    /// <summary>
170
    /// Initializes a new instance of the <see cref="JsonReader"/> class with the specified <see cref="TextReader"/>.
171
    /// </summary>
172
 10596
    protected JsonReader()
173
    {
174
 10596
      _currentState = State.Start;
175
 10596
      _stack = new List<JTokenType>();
176
 10596
      Push(JTokenType.None);
177
 10596
    }
178

  
179
    private void Push(JTokenType value)
180
    {
181
 273948
      _stack.Add(value);
182
 273948
      _top++;
183
 273948
      _currentTypeContext = value;
184
 273948
    }
185

  
186
    private JTokenType Pop()
187
    {
188
 263270
      JTokenType value = Peek();
189
 263270
      _stack.RemoveAt(_stack.Count - 1);
190
 263270
      _top--;
191
 263270
      _currentTypeContext = _stack[_top - 1];
192

  
193
 263270
      return value;
194
 263270
    }
195

  
196
    private JTokenType Peek()
197
    {
198
 866682
      return _currentTypeContext;
199
 866682
    }
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
 60
      if (IsStartToken(TokenType))
219
      {
220
 43
        int depth = Depth;
221

  
222
 69
        while (Read() && (depth < Depth))
223
        {
224
        }
225
      }
226
 60
    }
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
 162392
      SetToken(newToken, null);
235
 162392
    }
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
 516797
      _token = newToken;
245

  
246
 516797
      switch (newToken)
247
      {
248
        case JsonToken.StartObject:
249
 50872
          _currentState = State.ObjectStart;
250
 50872
          Push(JTokenType.Object);
251
 50872
          break;
252
        case JsonToken.StartArray:
253
 20281
          _currentState = State.ArrayStart;
254
 20281
          Push(JTokenType.Array);
255
 20281
          break;
256
        case JsonToken.StartConstructor:
257
 13
          _currentState = State.ConstructorStart;
258
 13
          Push(JTokenType.Constructor);
259
 13
          break;
260
        case JsonToken.EndObject:
261
 50826
          ValidateEnd(JsonToken.EndObject);
262
 50826
          _currentState = State.PostValue;
263
 50826
          break;
264
        case JsonToken.EndArray:
265
 20270
          ValidateEnd(JsonToken.EndArray);
266
 20270
          _currentState = State.PostValue;
267
 20270
          break;
268
        case JsonToken.EndConstructor:
269
 13
          ValidateEnd(JsonToken.EndConstructor);
270
 13
          _currentState = State.PostValue;
271
 13
          break;
272
        case JsonToken.PropertyName:
273
 192186
          _currentState = State.Property;
274
 192186
          Push(JTokenType.Property);
275
 192186
          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
 182320
          _currentState = State.PostValue;
286
 182320
          break;
287
      }
288

  
289
 516797
      JTokenType current = Peek();
290
 516797
      if (current == JTokenType.Property && _currentState == State.PostValue)
291
 192161
        Pop();
292

  
293
 516797
      if (value != null)
294
      {
295
 354378
        _value = value;
296
 354378
        _valueType = value.GetType();
297
      }
298
      else
299
      {
300
 162419
        _value = null;
301
 162419
        _valueType = null;
302
      }
303
 516797
    }
304

  
305
    private void ValidateEnd(JsonToken endToken)
306
    {
307
 71109
      JTokenType currentObject = Pop();
308

  
309
 71109
      if (GetTypeForCloseToken(endToken) != currentObject)
310
 0
        throw new JsonReaderException("JsonToken {0} is not valid for closing JsonType {1}.".FormatWith(CultureInfo.InvariantCulture, endToken, currentObject));
311
 71109
    }
312

  
313
    /// <summary>
314
    /// Sets the state based on current token type.
315
    /// </summary>
316
    protected void SetStateBasedOnCurrent()
317
    {
318
 86615
      JTokenType currentObject = Peek();
319

  
320
 86615
      switch (currentObject)
321
      {
322
        case JTokenType.Object:
323
 71196
          _currentState = State.Object;
324
 71196
          break;
325
        case JTokenType.Array:
326
 15417
          _currentState = State.Array;
327
 15417
          break;
328
        case JTokenType.Constructor:
329
 2
          _currentState = State.Constructor;
330
 2
          break;
331
        case JTokenType.None:
332
 0
          _currentState = State.Finished;
333
 0
          break;
334
        default:
335
 0
          throw new JsonReaderException("While setting the reader state back to current object an unexpected JsonType was encountered: " + currentObject);
336
      }
337
 86615
    }
338

  
339
    internal static bool IsStartToken(JsonToken token)
340
    {
341
 70846
      switch (token)
342
      {
343
        case JsonToken.StartObject:
344
        case JsonToken.StartArray:
345
        case JsonToken.StartConstructor:
346
        case JsonToken.PropertyName:
347
 70531
          return true;
348
        case JsonToken.None:
349
        case JsonToken.Comment:
350
        case JsonToken.Integer:
351
        case JsonToken.Float:
352
        case JsonToken.String:
353
        case JsonToken.Boolean:
354
        case JsonToken.Null:
355
        case JsonToken.Undefined:
356
        case JsonToken.EndObject:
357
        case JsonToken.EndArray:
358
        case JsonToken.EndConstructor:
359
        case JsonToken.Date:
360
        case JsonToken.Raw:
361
        case JsonToken.Bytes:
362
 315
          return false;
363
        default:
364
 0
          throw MiscellaneousUtils.CreateArgumentOutOfRangeException("token", token, "Unexpected JsonToken value.");
365
      }
366
 70846
    }
367

  
368
    private JTokenType GetTypeForCloseToken(JsonToken token)
369
    {
370
 71109
      switch (token)
371
      {
372
        case JsonToken.EndObject:
373
 50826
          return JTokenType.Object;
374
        case JsonToken.EndArray:
375
 20270
          return JTokenType.Array;
376
        case JsonToken.EndConstructor:
377
 13
          return JTokenType.Constructor;
378
        default:
379
 0
          throw new JsonReaderException("Not a valid close JsonToken: " + token);
380
      }
381
 71109
    }
382

  
383
    /// <summary>
384
    /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
385
    /// </summary>
386
    void IDisposable.Dispose()
387
    {
388
 251
      Dispose(true);
389
 251
    }
390

  
391
    /// <summary>
392
    /// Releases unmanaged and - optionally - managed resources
393
    /// </summary>
394
    /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
395
    protected virtual void Dispose(bool disposing)
396
    {
397
 251
      if (_currentState != State.Closed && disposing)
398
 251
        Close();
399
 251
    }
400

  
401
    /// <summary>
402
    /// Changes the <see cref="State"/> to Closed. 
403
    /// </summary>
404
    public virtual void Close()
405
    {
406
 251
      _currentState = State.Closed;
407
 251
      _token = JsonToken.None;
408
 251
      _value = null;
409
 251
      _valueType = null;
410
 251
    }
411
  }
412
}