Json.NET
Code Coverage Statistics for Source File

Newtonsoft.Json\JsonTextReader.cs

Symbol Coverage: 90.29% (344 of 381)

Branch Coverage: 92.62% (251 of 271)

Cyclomatic Complexity Avg: 6.21 Max:31

Code Lines: 381


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.Text;
29
using System.IO;
30
using System.Xml;
31
using System.Globalization;
32
using Newtonsoft.Json.Utilities;
33

  
34
namespace Newtonsoft.Json
35
{
36
  /// <summary>
37
  /// Represents a reader that provides fast, non-cached, forward-only access to serialized Json data.
38
  /// </summary>
39
  public class JsonTextReader : JsonReader, IJsonLineInfo
40
  {
41
    private readonly TextReader _reader;
42
    private readonly StringBuffer _buffer;
43
    private char? _lastChar;
44
    private int _currentLinePosition;
45
    private int _currentLineNumber;
46
    private bool _end;
47

  
48
    /// <summary>
49
    /// Initializes a new instance of the <see cref="JsonReader"/> class with the specified <see cref="TextReader"/>.
50
    /// </summary>
51
    /// <param name="reader">The <c>TextReader</c> containing the XML data to read.</param>
52
 5439
    public JsonTextReader(TextReader reader)
53
    {
54
 5439
      if (reader == null)
55
 1
        throw new ArgumentNullException("reader");
56

  
57
 5438
      _reader = reader;
58
 5438
      _buffer = new StringBuffer(4096);
59
 5438
      _currentLineNumber = 1;
60
 5438
    }
61

  
62
    private void ParseString(char quote)
63
    {
64
 61309
      ReadStringIntoBuffer(quote);
65

  
66
 61305
      string text = _buffer.ToString();
67
 61305
      _buffer.Position = 0;
68

  
69
 61305
      if (text.StartsWith("/Date(", StringComparison.Ordinal) && text.EndsWith(")/", StringComparison.Ordinal))
70
      {
71
 20056
        ParseDate(text);
72
      }
73
      else
74
      {
75
 41249
        SetToken(JsonToken.String, text);
76
 41249
        QuoteChar = quote;
77
      }
78
 61305
    }
79

  
80
    private void ReadStringIntoBuffer(char quote)
81
    {
82
 1956661
      while (true)
83
      {
84
 1956661
        char currentChar = MoveNext();
85

  
86
 1956661
        switch (currentChar)
87
        {
88
          case '\0':
89
 3
            if (_end)
90
 2
              throw CreateJsonReaderException("Unterminated string. Expected delimiter: {0}. Line {1}, position {2}.", quote, _currentLineNumber, _currentLinePosition);
91

  
92
 1
            _buffer.Append('\0');
93
 1
            break;
94
          case '\\':
95
 45186
            if ((currentChar = MoveNext()) != '\0' || !_end)
96
            {
97
 45185
              switch (currentChar)
98
              {
99
                case 'b':
100
 6
                  _buffer.Append('\b');
101
 6
                  break;
102
                case 't':
103
 8
                  _buffer.Append('\t');
104
 8
                  break;
105
                case 'n':
106
 9
                  _buffer.Append('\n');
107
 9
                  break;
108
                case 'f':
109
 6
                  _buffer.Append('\f');
110
 6
                  break;
111
                case 'r':
112
 9
                  _buffer.Append('\r');
113
 9
                  break;
114
                case '\\':
115
 17
                  _buffer.Append('\\');
116
 17
                  break;
117
                case '"':
118
                case '\'':
119
                case '/':
120
 40121
                  _buffer.Append(currentChar);
121
 40121
                  break;
122
                case 'u':
123
 5008
                  char[] hexValues = new char[4];
124
 5008
                  for (int i = 0; i < hexValues.Length; i++)
125
                  {
126
 20032
                    if ((currentChar = MoveNext()) != '\0' || !_end)
127
 20031
                      hexValues[i] = currentChar;
128
                    else
129
 1
                      throw CreateJsonReaderException("Unexpected end while parsing unicode character. Line {0}, position {1}.", _currentLineNumber, _currentLinePosition);
130
                  }
131

  
132
 5007
                  char hexChar = Convert.ToChar(int.Parse(new string(hexValues), NumberStyles.HexNumber, NumberFormatInfo.InvariantInfo));
133
 5007
                  _buffer.Append(hexChar);
134
 5007
                  break;
135
                default:
136
 1
                  throw CreateJsonReaderException("Bad JSON escape sequence: {0}. Line {1}, position {2}.", @"\" + currentChar, _currentLineNumber, _currentLinePosition);
137
              }
138
            }
139
            else
140
            {
141
 1
              throw CreateJsonReaderException("Unterminated string. Expected delimiter: {0}. Line {1}, position {2}.", quote, _currentLineNumber, _currentLinePosition);
142
            }
143
 45183
            break;
144
          case '"':
145
          case '\'':
146
 158121
            if (currentChar == quote)
147
            {
148
 158105
              return;
149
            }
150
            else
151
            {
152
 16
              _buffer.Append(currentChar);
153
            }
154
 16
            break;
155
          default:
156
 1753351
            _buffer.Append(currentChar);
157
 1753351
            break;
158
        }
159
      }
160
 158105
    }
161

  
162
    private JsonReaderException CreateJsonReaderException(string format, params object[] args)
163
    {
164
 11
      string message = format.FormatWith(CultureInfo.InvariantCulture, args);
165
 11
      return new JsonReaderException(message, null, _currentLineNumber, _currentLinePosition);
166
 11
    }
167

  
168
    private void ParseDate(string text)
169
    {
170
 20056
      string value = text.Substring(6, text.Length - 8);
171
 20056
      DateTimeKind kind = DateTimeKind.Utc;
172

  
173
 20056
      int index = value.IndexOf('+', 1);
174

  
175
 20056
      if (index == -1)
176
 47
        index = value.IndexOf('-', 1);
177

  
178
 20056
      if (index != -1)
179
      {
180
 20015
        kind = DateTimeKind.Local;
181
 20015
        value = value.Substring(0, index);
182
      }
183

  
184
 20056
      long javaScriptTicks = long.Parse(value, NumberStyles.Integer, CultureInfo.InvariantCulture);
185
 20056
      DateTime utcDateTime = JsonConvert.ConvertJavaScriptTicksToDateTime(javaScriptTicks);
186
      DateTime dateTime;
187

  
188
 20056
      switch (kind)
189
      {
190
        case DateTimeKind.Unspecified:
191
 0
          dateTime = DateTime.SpecifyKind(utcDateTime.ToLocalTime(), DateTimeKind.Unspecified);
192
 0
          break;
193
        case DateTimeKind.Local:
194
 20015
          dateTime = utcDateTime.ToLocalTime();
195
 20015
          break;
196
        default:
197
 41
          dateTime = utcDateTime;
198
 41
          break;
199
      }
200

  
201
 20056
      SetToken(JsonToken.Date, dateTime);
202
 20056
    }
203

  
204
    private const int LineFeedValue = StringUtils.LineFeed;
205
    private const int CarriageReturnValue = StringUtils.CarriageReturn;
206

  
207
    private char MoveNext()
208
    {
209
 2586278
      int value = _reader.Read();
210

  
211
 2586278
      switch (value)
212
      {
213
        case -1:
214
 217
          _end = true;
215
 217
          return '\0';
216
        case CarriageReturnValue:
217
 2345
          if (_reader.Peek() == LineFeedValue)
218
 2345
            _reader.Read();
219

  
220
 2345
          _currentLineNumber++;
221
 2345
          _currentLinePosition = 0;
222
 2345
          break;
223
        case LineFeedValue:
224
 1
          _currentLineNumber++;
225
 1
          _currentLinePosition = 0;
226
 1
          break;
227
        default:
228
 2583715
          _currentLinePosition++;
229
 2583715
          break;
230
      }
231

  
232
 2586061
      return (char)value;
233
 2586278
    }
234

  
235
    private bool HasNext()
236
    {
237
 10131
      return (_reader.Peek() != -1);
238
 10131
    }
239

  
240
    private int PeekNext()
241
    {
242
 20340
      return _reader.Peek();
243
 20340
    }
244

  
245
    /// <summary>
246
    /// Reads the next JSON token from the stream.
247
    /// </summary>
248
    /// <returns>
249
    /// true if the next token was read successfully; false if there are no more tokens to read.
250
    /// </returns>
251
    public override bool Read()
252
    {
253
 347775
      while (true)
254
      {
255
        char currentChar;
256
 347775
        if (_lastChar != null)
257
        {
258
 20490
          currentChar = _lastChar.Value;
259
 20490
          _lastChar = null;
260
        }
261
        else
262
        {
263
 327285
          currentChar = MoveNext();
264
        }
265

  
266
 347775
        if (currentChar == '\0' && _end)
267
 194
          return false;
268

  
269
 347581
        switch (CurrentState)
270
        {
271
          case State.Start:
272
          case State.Property:
273
          case State.Array:
274
          case State.ArrayStart:
275
          case State.Constructor:
276
          case State.ConstructorStart:
277
 128030
            return ParseValue(currentChar);
278
          case State.Complete:
279
 0
            break;
280
          case State.Object:
281
          case State.ObjectStart:
282
 96964
            return ParseObject(currentChar);
283
          case State.PostValue:
284
            // returns true if it hits
285
            // end of object or array
286
 122587
            if (ParsePostValue(currentChar))
287
 35967
              return true;
288
 86619
            break;
289
          case State.Closed:
290
 0
            break;
291
          case State.Error:
292
 0
            break;
293
          default:
294
 0
            throw CreateJsonReaderException("Unexpected state: {0}. Line {1}, position {2}.", CurrentState, _currentLineNumber, _currentLinePosition);
295
        }
296
      }
297
 261148
    }
298

  
299
    /// <summary>
300
    /// Reads the next JSON token from the stream as a <see cref="T:Byte[]"/>.
301
    /// </summary>
302
    /// <returns>
303
    /// A <see cref="T:Byte[]"/> or a null reference if the next JSON token is null.
304
    /// </returns>
305
    public override byte[] ReadAsBytes()
306
    {
307
 11
      while (true)
308
      {
309
        char currentChar;
310
 11
        if (_lastChar != null)
311
        {
312
 1
          currentChar = _lastChar.Value;
313
 1
          _lastChar = null;
314
        }
315
        else
316
        {
317
 10
          currentChar = MoveNext();
318
        }
319

  
320
 11
        if (currentChar == '\0' && _end)
321
 1
          throw CreateJsonReaderException("Unexpected end when reading bytes: Line {0}, position {1}.", _currentLineNumber, _currentLinePosition);
322

  
323
 10
        switch (CurrentState)
324
        {
325
          case State.PostValue:
326
          case State.Start:
327
          case State.Property:
328
          case State.Array:
329
          case State.ArrayStart:
330
          case State.Constructor:
331
          case State.ConstructorStart:
332
            do
333
            {
334
 14
              switch (currentChar)
335
              {
336
                case '"':
337
                case '\'':
338
 7
                  ReadStringIntoBuffer(currentChar);
339

  
340
                  byte[] data;
341
 6
                  if (_buffer.Position == 0)
342
                  {
343
 2
                    data = new byte[0];
344
                  }
345
                  else
346
                  {
347
 4
                    data = Convert.FromBase64CharArray(_buffer.GetInternalBuffer(), 0, _buffer.Position);
348
 4
                    _buffer.Position = 0;
349
                  }
350

  
351
 6
                  SetToken(JsonToken.Bytes, data);
352

  
353
 6
                  return data;
354
                case 'n':
355
 1
                  ParseNull();
356
 1
                  return null;
357
                case ' ':
358
                case StringUtils.Tab:
359
                case StringUtils.LineFeed:
360
                case StringUtils.CarriageReturn:
361
                  // eat
362
 4
                  break;
363
                case ',':
364
 1
                  SetStateBasedOnCurrent();
365
 1
                  break;
366
                default:
367
 1
                  if (char.IsWhiteSpace(currentChar))
368
                  {
369
                    // eat
370
                  }
371
                  else
372
                  {
373
 1
                    throw CreateJsonReaderException("Unexpected character encountered while parsing value: {0}. Line {1}, position {2}.", currentChar, _currentLineNumber, _currentLinePosition);
374
                  }
375
 0
                  break;
376
              }
377
 5
            } while ((currentChar = MoveNext()) != '\0' || !_end);
378
 1
            break;
379
          default:
380
 0
            throw CreateJsonReaderException("Unexpected state: {0}. Line {1}, position {2}.", CurrentState, _currentLineNumber, _currentLinePosition);
381
        }
382
      }
383
 7
    }
384

  
385
    private bool ParsePostValue(char currentChar)
386
    {
387
      do
388
      {
389
 125738
        switch (currentChar)
390
        {
391
          case '}':
392
 25709
            SetToken(JsonToken.EndObject);
393
 25709
            return true;
394
          case ']':
395
 10238
            SetToken(JsonToken.EndArray);
396
 10238
            return true;
397
          case ')':
398
 13
            SetToken(JsonToken.EndConstructor);
399
 13
            return true;
400
          case '/':
401
 7
            ParseComment();
402
 7
            return true;
403
          case ',':
404
            // finished parsing
405
 86614
            SetStateBasedOnCurrent();
406
 86614
            return false;
407
          case ' ':
408
          case StringUtils.Tab:
409
          case StringUtils.LineFeed:
410
          case StringUtils.CarriageReturn:
411
            // eat
412
 3156
            break;
413
          default:
414
 1
            if (char.IsWhiteSpace(currentChar))
415
            {
416
              // eat
417
            }
418
            else
419
            {
420
 1
              throw CreateJsonReaderException("After parsing a value an unexpected character was encountered: {0}. Line {1}, position {2}.", currentChar, _currentLineNumber, _currentLinePosition);
421
            }
422
 0
            break;
423
        }
424
 3156
      } while ((currentChar = MoveNext()) != '\0' || !_end);
425

  
426
 5
      return false;
427
 122586
    }
428

  
429
    private bool ParseObject(char currentChar)
430
    {
431
      do
432
      {
433
 106918
        switch (currentChar)
434
        {
435
          case '}':
436
 28
            SetToken(JsonToken.EndObject);
437
 28
            return true;
438
          case '/':
439
 2
            ParseComment();
440
 2
            return true;
441
          case ' ':
442
          case StringUtils.Tab:
443
          case StringUtils.LineFeed:
444
          case StringUtils.CarriageReturn:
445
            // eat
446
 9954
            break;
447
          default:
448
 96934
            if (char.IsWhiteSpace(currentChar))
449
            {
450
              // eat
451
            }
452
            else
453
            {
454
 96934
              return ParseProperty(currentChar);
455
            }
456
 0
            break;
457
        }
458
 9954
      } while ((currentChar = MoveNext()) != '\0' || !_end);
459

  
460
 0
      return false;
461
 96961
    }
462

  
463
    private bool ParseProperty(char firstChar)
464
    {
465
 96934
      char currentChar = firstChar;
466
      char quoteChar;
467

  
468
 96934
      if (ValidIdentifierChar(currentChar))
469
      {
470
 139
        quoteChar = '\0';
471
 139
        currentChar = ParseUnquotedProperty(currentChar);
472
      }
473
 96795
      else if (currentChar == '"' || currentChar == '\'')
474
      {
475
 96794
        quoteChar = currentChar;
476
 96794
        ReadStringIntoBuffer(quoteChar);
477
 96794
        currentChar = MoveNext();
478
      }
479
      else
480
      {
481
 1
        throw CreateJsonReaderException("Invalid property identifier character: {0}. Line {1}, position {2}.", currentChar, _currentLineNumber, _currentLinePosition);
482
      }
483

  
484
 96932
      if (currentChar != ':')
485
      {
486
 88
        currentChar = MoveNext();
487

  
488
        // finished property. skip any whitespace and move to colon
489
 88
        EatWhitespace(currentChar, false, out currentChar);
490

  
491
 88
        if (currentChar != ':')
492
 1
          throw CreateJsonReaderException("Invalid character after parsing property name. Expected ':' but got: {0}. Line {1}, position {2}.", currentChar, _currentLineNumber, _currentLinePosition);
493
      }
494

  
495
 96931
      SetToken(JsonToken.PropertyName, _buffer.ToString());
496
 96931
      QuoteChar = quoteChar;
497
 96931
      _buffer.Position = 0;
498

  
499
 96931
      return true;
500
 96931
    }
501

  
502
    private bool ValidIdentifierChar(char value)
503
    {
504
 97885
      return (char.IsLetterOrDigit(value) || value == '_' || value == '$');
505
 97885
    }
506

  
507
    private char ParseUnquotedProperty(char firstChar)
508
    {
509
      // parse unquoted property name until whitespace or colon
510
 139
      _buffer.Append(firstChar);
511

  
512
      char currentChar;
513

  
514
 1090
      while ((currentChar = MoveNext()) != '\0' || !_end)
515
      {
516
 1089
        if (char.IsWhiteSpace(currentChar) || currentChar == ':')
517
        {
518
 138
          return currentChar;
519
        }
520
 951
        else if (ValidIdentifierChar(currentChar))
521
        {
522
 951
          _buffer.Append(currentChar);
523
        }
524
        else
525
        {
526
 0
          throw CreateJsonReaderException("Invalid JavaScript property identifier character: {0}. Line {1}, position {2}.", currentChar, _currentLineNumber, _currentLinePosition);
527
        }
528
      }
529

  
530
 1
      throw CreateJsonReaderException("Unexpected end when parsing unquoted property name. Line {0}, position {1}.", _currentLineNumber, _currentLinePosition);
531
 138
    }
532

  
533
    private bool ParseValue(char currentChar)
534
    {
535
      do
536
      {
537
 131743
        switch (currentChar)
538
        {
539
          case '"':
540
          case '\'':
541
 61309
            ParseString(currentChar);
542
 61305
            return true;
543
          case 't':
544
 27
            ParseTrue();
545
 27
            return true;
546
          case 'f':
547
 16
            ParseFalse();
548
 16
            return true;
549
          case 'n':
550
 10131
            if (HasNext())
551
            {
552
 10131
              char next = (char)PeekNext();
553

  
554
 10131
              if (next == 'u')
555
 10118
                ParseNull();
556
 13
              else if (next == 'e')
557
 13
                ParseConstructor();
558
              else
559
 0
                throw CreateJsonReaderException("Unexpected character encountered while parsing value: {0}. Line {1}, position {2}.", currentChar, _currentLineNumber, _currentLinePosition);
560
            }
561
            else
562
            {
563
 0
              throw CreateJsonReaderException("Unexpected end. Line {0}, position {1}.", _currentLineNumber, _currentLinePosition);
564
            }
565
 10131
            return true;
566
          case 'N':
567
 3
            ParseNumberNaN();
568
 3
            return true;
569
          case 'I':
570
 3
            ParseNumberPositiveInfinity();
571
 3
            return true;
572
          case '-':
573
 23
            if (PeekNext() == 'I')
574
 3
              ParseNumberNegativeInfinity();
575
            else
576
 20
              ParseNumber(currentChar);
577
 23
            return true;
578
          case '/':
579
 7
            ParseComment();
580
 7
            return true;
581
          case 'u':
582
 2
            ParseUndefined();
583
 2
            return true;
584
          case '{':
585
 25767
            SetToken(JsonToken.StartObject);
586
 25767
            return true;
587
          case '[':
588
 10253
            SetToken(JsonToken.StartArray);
589
 10253
            return true;
590
          case '}':
591
 0
            SetToken(JsonToken.EndObject);
592
 0
            return true;
593
          case ']':
594
 4
            SetToken(JsonToken.EndArray);
595
 4
            return true;
596
          case ',':
597
 0
            SetToken(JsonToken.Undefined);
598
 0
            return true;
599
          case ')':
600
 0
            SetToken(JsonToken.EndConstructor);
601
 0
            return true;
602
          case ' ':
603
          case StringUtils.Tab:
604
          case StringUtils.LineFeed:
605
          case StringUtils.CarriageReturn:
606
            // eat
607
 3713
            break;
608
          default:
609
 20485
            if (char.IsWhiteSpace(currentChar))
610
            {
611
              // eat
612
            }
613
 20485
            else if (char.IsNumber(currentChar) || currentChar == '-' || currentChar == '.')
614
            {
615
 20485
              ParseNumber(currentChar);
616
 20485
              return true;
617
            }
618
            else
619
            {
620
 0
              throw CreateJsonReaderException("Unexpected character encountered while parsing value: {0}. Line {1}, position {2}.", currentChar, _currentLineNumber, _currentLinePosition);
621
            }
622
 0
            break;
623
        }
624
 3713
      } while ((currentChar = MoveNext()) != '\0' || !_end);
625

  
626
 0
      return false;
627
 128026
    }
628

  
629
    private bool EatWhitespace(char initialChar, bool oneOrMore, out char finalChar)
630
    {
631
 114
      bool whitespace = false;
632
 114
      char currentChar = initialChar;
633
 127
      while (currentChar == ' ' || char.IsWhiteSpace(currentChar))
634
      {
635
 13
        whitespace = true;
636
 13
        currentChar = MoveNext();
637
      }
638

  
639
 114
      finalChar = currentChar;
640

  
641
 114
      return (!oneOrMore || whitespace);
642
 114
    }
643

  
644
    private void ParseConstructor()
645
    {
646
 13
      if (MatchValue('n', "new", true))
647
      {
648
 13
        char currentChar = MoveNext();
649

  
650
 13
        if (EatWhitespace(currentChar, true, out currentChar))
651
        {
652
 65
          while (char.IsLetter(currentChar))
653
          {
654
 52
            _buffer.Append(currentChar);
655
 52
            currentChar = MoveNext();
656
          }
657

  
658
 13
          EatWhitespace(currentChar, false, out currentChar);
659

  
660
 13
          if (currentChar != '(')
661
 0
            throw CreateJsonReaderException("Unexpected character while parsing constructor: {0}. Line {1}, position {2}.", currentChar, _currentLineNumber, _currentLinePosition);
662

  
663
 13
          string constructorName = _buffer.ToString();
664
 13
          _buffer.Position = 0;
665

  
666
 13
          SetToken(JsonToken.StartConstructor, constructorName);
667
        }
668
      }
669
 13
    }
670

  
671
    private void ParseNumber(char firstChar)
672
    {
673
 20505
      char currentChar = firstChar;
674
 20505
      bool nonBase10 = (firstChar == '0');
675

  
676
      // parse until seperator character or end
677
 20505
      bool end = false;
678
      do
679
      {
680
 111966
        if (IsSeperator(currentChar))
681
        {
682
 20494
          end = true;
683
 20494
          _lastChar = currentChar;
684
        }
685
        else
686
        {
687
 91472
          _buffer.Append(currentChar);
688
        }
689

  
690
 111966
      } while (!end && ((currentChar = MoveNext()) != '\0' || !_end));
691

  
692
 20505
      string number = _buffer.ToString();
693
      object numberValue;
694
      JsonToken numberType;
695

  
696
 20505
      if (number.IndexOf(".", StringComparison.OrdinalIgnoreCase) != -1
697
 20505
        || number.IndexOf("e", StringComparison.OrdinalIgnoreCase) != -1)
698
      {
699
 5093
        numberValue = Convert.ToDouble(number, CultureInfo.InvariantCulture);
700
 5093
        numberType = JsonToken.Float;
701
      }
702
 15412
      else if (nonBase10)
703
      {
704
 34
        numberValue = number.StartsWith("0x", StringComparison.OrdinalIgnoreCase)
705
 34
          ? Convert.ToInt64(number, 16)
706
 34
          : Convert.ToInt64(number, 8);
707
 34
        numberType = JsonToken.Integer;
708
      }
709
      else
710
      {
711
 15378
        numberValue = Convert.ToInt64(number, CultureInfo.InvariantCulture);
712
 15378
        numberType = JsonToken.Integer;
713
      }
714

  
715
 20505
      _buffer.Position = 0;
716

  
717
 20505
      SetToken(numberType, numberValue);
718
 20505
    }
719

  
720
    private void ParseComment()
721
    {
722
      // should have already parsed / character before reaching this method
723

  
724
 16
      char currentChar = MoveNext();
725

  
726
 16
      if (currentChar == '*')
727
      {
728
 126
        while ((currentChar = MoveNext()) != '\0' || !_end)
729
        {
730
 126
          if (currentChar == '*')
731
          {
732
 17
            if ((currentChar = MoveNext()) != '\0' || !_end)
733
            {
734
 17
              if (currentChar == '/')
735
              {
736
 16
                break;
737
              }
738
              else
739
              {
740
 1
                _buffer.Append('*');
741
 1
                _buffer.Append(currentChar);
742
              }
743
            }
744
          }
745
          else
746
          {
747
 109
            _buffer.Append(currentChar);
748
          }
749
        }
750
      }
751
      else
752
      {
753
 0
        throw CreateJsonReaderException("Error parsing comment. Expected: *. Line {0}, position {1}.", _currentLineNumber, _currentLinePosition);
754
      }
755

  
756
 16
      SetToken(JsonToken.Comment, _buffer.ToString());
757

  
758
 16
      _buffer.Position = 0;
759
 16
    }
760

  
761
    private bool MatchValue(char firstChar, string value)
762
    {
763
 10186
      char currentChar = firstChar;
764

  
765
 10186
      int i = 0;
766
      do
767
      {
768
 40781
        if (currentChar != value[i])
769
        {
770
 0
          break;
771
        }
772
 40781
        i++;
773
      }
774
 40781
      while (i < value.Length && ((currentChar = MoveNext()) != '\0' || !_end));
775

  
776
 10186
      return (i == value.Length);
777
 10186
    }
778

  
779
    private bool MatchValue(char firstChar, string value, bool noTrailingNonSeperatorCharacters)
780
    {
781
      // will match value and then move to the next character, checking that it is a seperator character
782
 10186
      bool match = MatchValue(firstChar, value);
783

  
784
 10186
      if (!noTrailingNonSeperatorCharacters)
785
      {
786
 0
        return match;
787
      }
788
      else
789
      {
790
 10186
        int c = PeekNext();
791
 10186
        char next = (c != -1) ? (char) c : '\0';
792
 10186
        bool matchAndNoTrainingNonSeperatorCharacters = (match && (next == '\0' || IsSeperator(next)));
793

  
794
 10186
        return matchAndNoTrainingNonSeperatorCharacters;
795
      }
796
 10186
    }
797

  
798
    private bool IsSeperator(char c)
799
    {
800
 122148
      switch (c)
801
      {
802
        case '}':
803
        case ']':
804
        case ',':
805
 30530
          return true;
806
        case '/':
807
          // check next character to see if start of a comment
808
 0
          return (HasNext() && PeekNext() == '*');
809
        case ')':
810
 13
          if (CurrentState == State.Constructor || CurrentState == State.ConstructorStart)
811
 13
            return true;
812
 0
          break;
813
        case ' ':
814
        case StringUtils.Tab:
815
        case StringUtils.LineFeed:
816
        case StringUtils.CarriageReturn:
817
 133
          return true;
818
        default:
819
 91472
          if (char.IsWhiteSpace(c))
820
 0
            return true;
821
 91472
          break;
822
      }
823

  
824
 91472
      return false;
825
 122148
    }
826

  
827
    private void ParseTrue()
828
    {
829
      // check characters equal 'true'
830
      // and that it is followed by either a seperator character
831
      // or the text ends
832
 27
      if (MatchValue('t', JsonConvert.True, true))
833
      {
834
 27
        SetToken(JsonToken.Boolean, true);
835
      }
836
      else
837
      {
838
 0
        throw CreateJsonReaderException("Error parsing boolean value. Line {0}, position {1}.", _currentLineNumber, _currentLinePosition);
839
      }
840
 27
    }
841

  
842
    private void ParseNull()
843
    {
844
 10119
      if (MatchValue('n', JsonConvert.Null, true))
845
      {
846
 10119
        SetToken(JsonToken.Null);
847
      }
848
      else
849
      {
850
 0
        throw CreateJsonReaderException("Error parsing null value. Line {0}, position {1}.", _currentLineNumber, _currentLinePosition);
851
      }
852
 10119
    }
853

  
854
    private void ParseUndefined()
855
    {
856
 2
      if (MatchValue('u', JsonConvert.Undefined, true))
857
      {
858
 2
        SetToken(JsonToken.Undefined);
859
      }
860
      else
861
      {
862
 0
        throw CreateJsonReaderException("Error parsing undefined value. Line {0}, position {1}.", _currentLineNumber, _currentLinePosition);
863
      }
864
 2
    }
865

  
866
    private void ParseFalse()
867
    {
868
 16
      if (MatchValue('f', JsonConvert.False, true))
869
      {
870
 16
        SetToken(JsonToken.Boolean, false);
871
      }
872
      else
873
      {
874
 0
        throw CreateJsonReaderException("Error parsing boolean value. Line {0}, position {1}.", _currentLineNumber, _currentLinePosition);
875
      }
876
 16
    }
877

  
878
    private void ParseNumberNegativeInfinity()
879
    {
880
 3
      if (MatchValue('-', JsonConvert.NegativeInfinity, true))
881
      {
882
 3
        SetToken(JsonToken.Float, double.NegativeInfinity);
883
      }
884
      else
885
      {
886
 0
        throw CreateJsonReaderException("Error parsing negative infinity value. Line {0}, position {1}.", _currentLineNumber, _currentLinePosition);
887
      }
888
 3
    }
889

  
890
    private void ParseNumberPositiveInfinity()
891
    {
892
 3
      if (MatchValue('I', JsonConvert.PositiveInfinity, true))
893
      {
894
 3
        SetToken(JsonToken.Float, double.PositiveInfinity);
895
      }
896
      else
897
      {
898
 0
        throw CreateJsonReaderException("Error parsing positive infinity value. Line {0}, position {1}.", _currentLineNumber, _currentLinePosition);
899
      }
900
 3
    }
901

  
902
    private void ParseNumberNaN()
903
    {
904
 3
      if (MatchValue('N', JsonConvert.NaN, true))
905
      {
906
 3
        SetToken(JsonToken.Float, double.NaN);
907
      }
908
      else
909
      {
910
 0
        throw CreateJsonReaderException("Error parsing NaN value. Line {0}, position {1}.", _currentLineNumber, _currentLinePosition);
911
      }
912
 3
    }
913

  
914
    /// <summary>
915
    /// Changes the state to closed. 
916
    /// </summary>
917
    public override void Close()
918
    {
919
 215
      base.Close();
920

  
921
 215
      if (_reader != null)
922
 215
        _reader.Close();
923

  
924
 215
      if (_buffer != null)
925
 215
        _buffer.Clear();
926
 215
    }
927

  
928
    /// <summary>
929
    /// Gets a value indicating whether the class can return line information.
930
    /// </summary>
931
    /// <returns>
932
    /// 	<c>true</c> if LineNumber and LinePosition can be provided; otherwise, <c>false</c>.
933
    /// </returns>
934
    public bool HasLineInfo()
935
    {
936
 867
      return true;
937
 867
    }
938

  
939
    /// <summary>
940
    /// Gets the current line number.
941
    /// </summary>
942
    /// <value>
943
    /// The current line number or 0 if no line information is available (for example, HasLineInfo returns false).
944
    /// </value>
945
    public int LineNumber
946
    {
947
      get
948
      {
949
 912
        if (CurrentState == State.Start)
950
 1
          return 0;
951

  
952
 911
        return _currentLineNumber;
953
 912
      }
954
    }
955

  
956
    /// <summary>
957
    /// Gets the current line position.
958
    /// </summary>
959
    /// <value>
960
    /// The current line position or 0 if no line information is available (for example, HasLineInfo returns false).
961
    /// </value>
962
    public int LinePosition
963
    {
964
 912
      get { return _currentLinePosition; }
965
    }
966
  }
967
}