Json.NET
Code Coverage Statistics for Source File

Newtonsoft.Json\JsonWriter.cs

Symbol Coverage: 91.97% (332 of 361)

Branch Coverage: 91.91% (159 of 173)

Cyclomatic Complexity Avg: 2.47 Max:22

Code Lines: 369


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 Newtonsoft.Json.Utilities;
32
using Newtonsoft.Json.Linq;
33
using System.Globalization;
34

  
35
namespace Newtonsoft.Json
36
{
37
  /// <summary>
38
  /// Specifies the state of the <see cref="JsonWriter"/>.
39
  /// </summary>
40
  public enum WriteState
41
  {
42
    /// <summary>
43
    /// An exception has been thrown, which has left the <see cref="JsonWriter"/> in an invalid state.
44
    /// You may call the <see cref="JsonWriter.Close"/> method to put the <see cref="JsonWriter"/> in the <c>Closed</c> state.
45
    /// Any other <see cref="JsonWriter"/> method calls results in an <see cref="InvalidOperationException"/> being thrown. 
46
    /// </summary>
47
    Error,
48
    /// <summary>
49
    /// The <see cref="JsonWriter.Close"/> method has been called. 
50
    /// </summary>
51
    Closed,
52
    /// <summary>
53
    /// An object is being written. 
54
    /// </summary>
55
    Object,
56
    /// <summary>
57
    /// A array is being written.
58
    /// </summary>
59
    Array,
60
    /// <summary>
61
    /// A constructor is being written.
62
    /// </summary>
63
    Constructor,
64
    /// <summary>
65
    /// A property is being written.
66
    /// </summary>
67
    Property,
68
    /// <summary>
69
    /// A write method has not been called.
70
    /// </summary>
71
    Start
72
  }
73

  
74
  /// <summary>
75
  /// Specifies formatting options for the <see cref="JsonTextWriter"/>.
76
  /// </summary>
77
  public enum Formatting
78
  {
79
    /// <summary>
80
    /// No special formatting is applied. This is the default.
81
    /// </summary>
82
    None,
83
    /// <summary>
84
    /// Causes child objects to be indented according to the <see cref="JsonTextWriter.Indentation"/> and <see cref="JsonTextWriter.IndentChar"/> settings.
85
    /// </summary>
86
    Indented
87
  }
88

  
89
  /// <summary>
90
  /// Represents a writer that provides a fast, non-cached, forward-only way of generating Json data.
91
  /// </summary>
92
  public abstract class JsonWriter : IDisposable
93
  {
94
    private enum State
95
    {
96
      Start,
97
      Property,
98
      ObjectStart,
99
      Object,
100
      ArrayStart,
101
      Array,
102
      ConstructorStart,
103
      Constructor,
104
      Bytes,
105
      Closed,
106
      Error
107
    }
108

  
109
    // array that gives a new state based on the current state an the token being written
110
 1
    private static readonly State[][] stateArray = new[] {
111
 1
//                      Start                   PropertyName            ObjectStart         Object            ArrayStart              Array                   ConstructorStart        Constructor             Closed          Error
112
 1
//                        
113
 1
/* None             */new[]{ State.Error,            State.Error,            State.Error,        State.Error,      State.Error,            State.Error,            State.Error,            State.Error,            State.Error,    State.Error },
114
 1
/* StartObject      */new[]{ State.ObjectStart,      State.ObjectStart,      State.Error,        State.Error,      State.ObjectStart,      State.ObjectStart,      State.ObjectStart,      State.ObjectStart,      State.Error,    State.Error },
115
 1
/* StartArray       */new[]{ State.ArrayStart,       State.ArrayStart,       State.Error,        State.Error,      State.ArrayStart,       State.ArrayStart,       State.ArrayStart,       State.ArrayStart,       State.Error,    State.Error },
116
 1
/* StartConstructor */new[]{ State.ConstructorStart, State.ConstructorStart, State.Error,        State.Error,      State.ConstructorStart, State.ConstructorStart, State.ConstructorStart, State.ConstructorStart, State.Error,    State.Error },
117
 1
/* StartProperty    */new[]{ State.Property,         State.Error,            State.Property,     State.Property,   State.Error,            State.Error,            State.Error,            State.Error,            State.Error,    State.Error },
118
 1
/* Comment          */new[]{ State.Start,            State.Property,         State.ObjectStart,  State.Object,     State.ArrayStart,       State.Array,            State.Constructor,      State.Constructor,      State.Error,    State.Error },
119
 1
/* Raw              */new[]{ State.Start,            State.Property,         State.ObjectStart,  State.Object,     State.ArrayStart,       State.Array,            State.Constructor,      State.Constructor,      State.Error,    State.Error },
120
 1
/* Value            */new[]{ State.Start,            State.Object,           State.Error,        State.Error,      State.Array,            State.Array,            State.Constructor,      State.Constructor,      State.Error,    State.Error },
121
 1
		};
122

  
123
    private int _top;
124

  
125
    private readonly List<JTokenType> _stack;
126
    private State _currentState;
127
    private Formatting _formatting;
128

  
129
    /// <summary>
130
    /// Gets the top.
131
    /// </summary>
132
    /// <value>The top.</value>
133
    protected internal int Top
134
    {
135
 312725
      get { return _top; }
136
    }
137

  
138
    /// <summary>
139
    /// Gets the state of the writer.
140
    /// </summary>
141
    public WriteState WriteState
142
    {
143
      get
144
      {
145
 1077076
        switch (_currentState)
146
        {
147
          case State.Error:
148
 0
            return WriteState.Error;
149
          case State.Closed:
150
 0
            return WriteState.Closed;
151
          case State.Object:
152
          case State.ObjectStart:
153
 501157
            return WriteState.Object;
154
          case State.Array:
155
          case State.ArrayStart:
156
 52809
            return WriteState.Array;
157
          case State.Constructor:
158
          case State.ConstructorStart:
159
 15
            return WriteState.Constructor;
160
          case State.Property:
161
 501155
            return WriteState.Property;
162
          case State.Start:
163
 21940
            return WriteState.Start;
164
          default:
165
 0
            throw new JsonWriterException("Invalid state: " + _currentState);
166
        }
167
 1077076
      }
168
    }
169

  
170
    /// <summary>
171
    /// Indicates how the output is formatted.
172
    /// </summary>
173
    public Formatting Formatting
174
    {
175
 165318
      get { return _formatting; }
176
 5727
      set { _formatting = value; }
177
    }
178

  
179
    /// <summary>
180
    /// Creates an instance of the <c>JsonWriter</c> class. 
181
    /// </summary>
182
 16242
    public JsonWriter()
183
    {
184
 16242
      _stack = new List<JTokenType>(8);
185
 16242
      _stack.Add(JTokenType.None);
186
 16242
      _currentState = State.Start;
187
 16242
      _formatting = Formatting.None;
188
 16242
    }
189

  
190
    private void Push(JTokenType value)
191
    {
192
 174257
      _top++;
193
 174257
      if (_stack.Count <= _top)
194
 132336
        _stack.Add(value);
195
      else
196
 41921
        _stack[_top] = value;
197
 174257
    }
198

  
199
    private JTokenType Pop()
200
    {
201
 174253
      JTokenType value = Peek();
202
 174253
      _top--;
203

  
204
 174253
      return value;
205
 174253
    }
206

  
207
    private JTokenType Peek()
208
    {
209
 348534
      return _stack[_top];
210
 348534
    }
211

  
212
    /// <summary>
213
    /// Flushes whatever is in the buffer to the underlying streams and also flushes the underlying stream.
214
    /// </summary>
215
    public abstract void Flush();
216

  
217
    /// <summary>
218
    /// Closes this stream and the underlying stream.
219
    /// </summary>
220
    public virtual void Close()
221
    {
222
 5702
      AutoCompleteAll();
223
 5702
    }
224

  
225
    /// <summary>
226
    /// Writes the beginning of a Json object.
227
    /// </summary>
228
    public virtual void WriteStartObject()
229
    {
230
 153157
      AutoComplete(JsonToken.StartObject);
231
 153157
      Push(JTokenType.Object);
232
 153157
    }
233

  
234
    /// <summary>
235
    /// Writes the end of a Json object.
236
    /// </summary>
237
    public void WriteEndObject()
238
    {
239
 153157
      AutoCompleteClose(JsonToken.EndObject);
240
 153157
    }
241

  
242
    /// <summary>
243
    /// Writes the beginning of a Json array.
244
    /// </summary>
245
    public virtual void WriteStartArray()
246
    {
247
 21087
      AutoComplete(JsonToken.StartArray);
248
 21087
      Push(JTokenType.Array);
249
 21087
    }
250

  
251
    /// <summary>
252
    /// Writes the end of an array.
253
    /// </summary>
254
    public void WriteEndArray()
255
    {
256
 21084
      AutoCompleteClose(JsonToken.EndArray);
257
 21083
    }
258

  
259
    /// <summary>
260
    /// Writes the start of a constructor with the given name.
261
    /// </summary>
262
    /// <param name="name">The name of the constructor.</param>
263
    public virtual void WriteStartConstructor(string name)
264
    {
265
 13
      AutoComplete(JsonToken.StartConstructor);
266
 13
      Push(JTokenType.Constructor);
267
 13
    }
268

  
269
    /// <summary>
270
    /// Writes the end constructor.
271
    /// </summary>
272
    public void WriteEndConstructor()
273
    {
274
 13
      AutoCompleteClose(JsonToken.EndConstructor);
275
 13
    }
276

  
277
    /// <summary>
278
    /// Writes the property name of a name/value pair on a Json object.
279
    /// </summary>
280
    /// <param name="name">The name of the property.</param>
281
    public virtual void WritePropertyName(string name)
282
    {
283
 501151
      AutoComplete(JsonToken.PropertyName);
284
 501151
    }
285

  
286
    /// <summary>
287
    /// Writes the end of the current Json object or array.
288
    /// </summary>
289
    public void WriteEnd()
290
    {
291
 28
      WriteEnd(Peek());
292
 28
    }
293

  
294
    /// <summary>
295
    /// Writes the current <see cref="JsonReader"/> token.
296
    /// </summary>
297
    /// <param name="reader">The <see cref="JsonReader"/> to read the token from.</param>
298
    public void WriteToken(JsonReader reader)
299
    {
300
 11
      ValidationUtils.ArgumentNotNull(reader, "reader");
301

  
302
      int initialDepth;
303

  
304
 11
      if (reader.TokenType == JsonToken.None)
305
 0
        initialDepth = -1;
306
 11
      else if (!IsStartToken(reader.TokenType))
307
 4
        initialDepth = reader.Depth + 1;
308
      else
309
 7
        initialDepth = reader.Depth;
310

  
311
 11
      WriteToken(reader, initialDepth);
312
 11
    }
313

  
314
    internal void WriteToken(JsonReader reader, int initialDepth)
315
    {
316
      do
317
      {
318
 219
        switch (reader.TokenType)
319
        {
320
          case JsonToken.None:
321
            // read to next
322
 0
            break;
323
          case JsonToken.StartObject:
324
 7
            WriteStartObject();
325
 7
            break;
326
          case JsonToken.StartArray:
327
 15
            WriteStartArray();
328
 15
            break;
329
          case JsonToken.StartConstructor:
330
 1
            string constructorName = reader.Value.ToString();
331
            // write a JValue date when the constructor is for a date
332
 1
            if (string.Compare(constructorName, "Date", StringComparison.Ordinal) == 0)
333
 1
              WriteConstructorDate(reader);
334
            else
335
 0
              WriteStartConstructor(reader.Value.ToString());
336
 1
            break;
337
          case JsonToken.PropertyName:
338
 58
            WritePropertyName(reader.Value.ToString());
339
 58
            break;
340
          case JsonToken.Comment:
341
 1
            WriteComment(reader.Value.ToString());
342
 1
            break;
343
          case JsonToken.Integer:
344
 42
            WriteValue((long)reader.Value);
345
 42
            break;
346
          case JsonToken.Float:
347
 1
            WriteValue((double)reader.Value);
348
 1
            break;
349
          case JsonToken.String:
350
 57
            WriteValue(reader.Value.ToString());
351
 57
            break;
352
          case JsonToken.Boolean:
353
 2
            WriteValue((bool)reader.Value);
354
 2
            break;
355
          case JsonToken.Null:
356
 4
            WriteNull();
357
 4
            break;
358
          case JsonToken.Undefined:
359
 0
            WriteUndefined();
360
 0
            break;
361
          case JsonToken.EndObject:
362
 15
            WriteEndObject();
363
 15
            break;
364
          case JsonToken.EndArray:
365
 15
            WriteEndArray();
366
 15
            break;
367
          case JsonToken.EndConstructor:
368
 0
            WriteEndConstructor();
369
 0
            break;
370
          case JsonToken.Date:
371
 0
            WriteValue((DateTime)reader.Value);
372
 0
            break;
373
          case JsonToken.Raw:
374
 1
            WriteRawValue((string)reader.Value);
375
 1
            break;
376
          case JsonToken.Bytes:
377
 0
            WriteValue((byte[])reader.Value);
378
 0
            break;
379
          default:
380
 0
            throw MiscellaneousUtils.CreateArgumentOutOfRangeException("TokenType", reader.TokenType, "Unexpected token type.");
381
        }
382
      }
383
 219
      while (
384
 219
        // stop if we have reached the end of the token being read
385
 219
        initialDepth - 1 < reader.Depth - (IsEndToken(reader.TokenType) ? 1 : 0)
386
 219
        && reader.Read());
387
 19
    }
388

  
389
    private void WriteConstructorDate(JsonReader reader)
390
    {
391
 1
      if (!reader.Read())
392
 0
        throw new Exception("Unexpected end while reading date constructor.");
393
 1
      if (reader.TokenType != JsonToken.Integer)
394
 0
        throw new Exception("Unexpected token while reading date constructor. Expected Integer, got " + reader.TokenType);
395

  
396
 1
      long ticks = (long)reader.Value;
397
 1
      DateTime date = JsonConvert.ConvertJavaScriptTicksToDateTime(ticks);
398

  
399
 1
      if (!reader.Read())
400
 0
        throw new Exception("Unexpected end while reading date constructor.");
401
 1
      if (reader.TokenType != JsonToken.EndConstructor)
402
 0
        throw new Exception("Unexpected token while reading date constructor. Expected EndConstructor, got " + reader.TokenType);
403

  
404
 1
      WriteValue(date);
405
 1
    }
406

  
407
    private bool IsEndToken(JsonToken token)
408
    {
409
 219
      switch (token)
410
      {
411
        case JsonToken.EndObject:
412
        case JsonToken.EndArray:
413
        case JsonToken.EndConstructor:
414
 31
          return true;
415
        default:
416
 188
          return false;
417
      }
418
 219
    }
419

  
420
    private bool IsStartToken(JsonToken token)
421
    {
422
 11
      switch (token)
423
      {
424
        case JsonToken.StartObject:
425
        case JsonToken.StartArray:
426
        case JsonToken.StartConstructor:
427
 7
          return true;
428
        default:
429
 4
          return false;
430
      }
431
 11
    }
432

  
433
    private void WriteEnd(JTokenType type)
434
    {
435
 28
      switch (type)
436
      {
437
        case JTokenType.Object:
438
 20
          WriteEndObject();
439
 20
          break;
440
        case JTokenType.Array:
441
 8
          WriteEndArray();
442
 8
          break;
443
        case JTokenType.Constructor:
444
 0
          WriteEndConstructor();
445
 0
          break;
446
        default:
447
 0
          throw new JsonWriterException("Unexpected type when writing end: " + type);
448
      }
449
 28
    }
450

  
451
    private void AutoCompleteAll()
452
    {
453
 5709
      while (_top > 0)
454
      {
455
 7
        WriteEnd();
456
      }
457
 5702
    }
458

  
459
    private JTokenType GetTypeForCloseToken(JsonToken token)
460
    {
461
 174253
      switch (token)
462
      {
463
        case JsonToken.EndObject:
464
 153157
          return JTokenType.Object;
465
        case JsonToken.EndArray:
466
 21083
          return JTokenType.Array;
467
        case JsonToken.EndConstructor:
468
 13
          return JTokenType.Constructor;
469
        default:
470
 0
          throw new JsonWriterException("No type for token: " + token);
471
      }
472
 174253
    }
473

  
474
    private JsonToken GetCloseTokenForType(JTokenType type)
475
    {
476
 174253
      switch (type)
477
      {
478
        case JTokenType.Object:
479
 153157
          return JsonToken.EndObject;
480
        case JTokenType.Array:
481
 21083
          return JsonToken.EndArray;
482
        case JTokenType.Constructor:
483
 13
          return JsonToken.EndConstructor;
484
        default:
485
 0
          throw new JsonWriterException("No close token for type: " + type);
486
      }
487
 174253
    }
488

  
489
    private void AutoCompleteClose(JsonToken tokenBeingClosed)
490
    {
491
      // write closing symbol and calculate new state
492

  
493
 174254
      int levelsToComplete = 0;
494

  
495
 0
      for (int i = 0; i < _top; i++)
496
      {
497
 174253
        int currentLevel = _top - i;
498

  
499
 174253
        if (_stack[currentLevel] == GetTypeForCloseToken(tokenBeingClosed))
500
        {
501
 174253
          levelsToComplete = i + 1;
502
 174253
          break;
503
        }
504
      }
505

  
506
 174254
      if (levelsToComplete == 0)
507
 1
        throw new JsonWriterException("No token to close.");
508

  
509
 174253
      for (int i = 0; i < levelsToComplete; i++)
510
      {
511
 174253
        JsonToken token = GetCloseTokenForType(Pop());
512

  
513
 174253
        if (_currentState != State.ObjectStart && _currentState != State.ArrayStart)
514
 174228
          WriteIndent();
515

  
516
 174253
        WriteEnd(token);
517
      }
518

  
519
 174253
      JTokenType currentLevelType = Peek();
520

  
521
 174253
      switch (currentLevelType)
522
      {
523
        case JTokenType.Object:
524
 137122
          _currentState = State.Object;
525
 137122
          break;
526
        case JTokenType.Array:
527
 20957
          _currentState = State.Array;
528
 20957
          break;
529
        case JTokenType.Constructor:
530
 1
          _currentState = State.Array;
531
 1
          break;
532
        case JTokenType.None:
533
 16173
          _currentState = State.Start;
534
 16173
          break;
535
        default:
536
 0
          throw new JsonWriterException("Unknown JsonType: " + currentLevelType);
537
      }
538
 174253
    }
539

  
540
    /// <summary>
541
    /// Writes the specified end token.
542
    /// </summary>
543
    /// <param name="token">The end token to write.</param>
544
    protected virtual void WriteEnd(JsonToken token)
545
    {
546
 136696
    }
547

  
548
    /// <summary>
549
    /// Writes indent characters.
550
    /// </summary>
551
    protected virtual void WriteIndent()
552
    {
553
 562876
    }
554

  
555
    /// <summary>
556
    /// Writes the JSON value delimiter.
557
    /// </summary>
558
    protected virtual void WriteValueDelimiter()
559
    {
560
 289360
    }
561

  
562
    /// <summary>
563
    /// Writes an indent space.
564
    /// </summary>
565
    protected virtual void WriteIndentSpace()
566
    {
567
 0
    }
568

  
569
    internal void AutoComplete(JsonToken tokenBeingWritten)
570
    {
571
      int token;
572

  
573
 1071355
      switch (tokenBeingWritten)
574
      {
575
        default:
576
 675414
          token = (int)tokenBeingWritten;
577
 675414
          break;
578
        case JsonToken.Integer:
579
        case JsonToken.Float:
580
        case JsonToken.String:
581
        case JsonToken.Boolean:
582
        case JsonToken.Null:
583
        case JsonToken.Undefined:
584
        case JsonToken.Date:
585
        case JsonToken.Bytes:
586
          // a value is being written
587
 395941
          token = 7;
588
 395941
          break;
589
      }
590

  
591
      // gets new state based on the current state and what is being written
592
 1071355
      State newState = stateArray[token][(int)_currentState];
593

  
594
 1071355
      if (newState == State.Error)
595
 0
        throw new JsonWriterException("Token {0} in state {1} would result in an invalid JavaScript object.".FormatWith(CultureInfo.InvariantCulture, tokenBeingWritten.ToString(), _currentState.ToString()));
596

  
597
 1071355
      if ((_currentState == State.Object || _currentState == State.Array || _currentState == State.Constructor) && tokenBeingWritten != JsonToken.Comment)
598
      {
599
 379731
        WriteValueDelimiter();
600
      }
601
 691624
      else if (_currentState == State.Property)
602
      {
603
 501151
        if (_formatting == Formatting.Indented)
604
 1343
          WriteIndentSpace();
605
      }
606

  
607
 1071355
      WriteState writeState = WriteState;
608

  
609
      // don't indent a property when it is the first token to be written (i.e. at the start)
610
 1071355
      if ((tokenBeingWritten == JsonToken.PropertyName && writeState != WriteState.Start) ||
611
 1071355
        writeState == WriteState.Array || writeState == WriteState.Constructor)
612
      {
613
 553963
        WriteIndent();
614
      }
615

  
616
 1071355
      _currentState = newState;
617
 1071355
    }
618

  
619
    #region WriteValue methods
620
    /// <summary>
621
    /// Writes a null value.
622
    /// </summary>
623
    public virtual void WriteNull()
624
    {
625
 25973
      AutoComplete(JsonToken.Null);
626
 25973
    }
627

  
628
    /// <summary>
629
    /// Writes an undefined value.
630
    /// </summary>
631
    public virtual void WriteUndefined()
632
    {
633
 4
      AutoComplete(JsonToken.Undefined);
634
 4
    }
635

  
636
    /// <summary>
637
    /// Writes raw JSON without changing the writer's state.
638
    /// </summary>
639
    /// <param name="json">The raw JSON to write.</param>
640
    public virtual void WriteRaw(string json)
641
    {
642
 27
    }
643

  
644
    /// <summary>
645
    /// Writes raw JSON where a value is expected and updates the writer's state.
646
    /// </summary>
647
    /// <param name="json">The raw JSON to write.</param>
648
    public virtual void WriteRawValue(string json)
649
    {
650
      // hack. want writer to change state as if a value had been written
651
 21
      AutoComplete(JsonToken.Undefined);
652
 21
      WriteRaw(json);
653
 21
    }
654

  
655
    /// <summary>
656
    /// Writes a <see cref="String"/> value.
657
    /// </summary>
658
    /// <param name="value">The <see cref="String"/> value to write.</param>
659
    public virtual void WriteValue(string value)
660
    {
661
 185659
      AutoComplete(JsonToken.String);
662
 185659
    }
663

  
664
    /// <summary>
665
    /// Writes a <see cref="Int32"/> value.
666
    /// </summary>
667
    /// <param name="value">The <see cref="Int32"/> value to write.</param>
668
    public virtual void WriteValue(int value)
669
    {
670
 131443
      AutoComplete(JsonToken.Integer);
671
 131443
    }
672

  
673
    /// <summary>
674
    /// Writes a <see cref="UInt32"/> value.
675
    /// </summary>
676
    /// <param name="value">The <see cref="UInt32"/> value to write.</param>
677
    public virtual void WriteValue(uint value)
678
    {
679
 4
      AutoComplete(JsonToken.Integer);
680
 4
    }
681

  
682
    /// <summary>
683
    /// Writes a <see cref="Int64"/> value.
684
    /// </summary>
685
    /// <param name="value">The <see cref="Int64"/> value to write.</param>
686
    public virtual void WriteValue(long value)
687
    {
688
 102
      AutoComplete(JsonToken.Integer);
689
 102
    }
690

  
691
    /// <summary>
692
    /// Writes a <see cref="UInt64"/> value.
693
    /// </summary>
694
    /// <param name="value">The <see cref="UInt64"/> value to write.</param>
695
    public virtual void WriteValue(ulong value)
696
    {
697
 4
      AutoComplete(JsonToken.Integer);
698
 4
    }
699

  
700
    /// <summary>
701
    /// Writes a <see cref="Single"/> value.
702
    /// </summary>
703
    /// <param name="value">The <see cref="Single"/> value to write.</param>
704
    public virtual void WriteValue(float value)
705
    {
706
 12
      AutoComplete(JsonToken.Float);
707
 12
    }
708

  
709
    /// <summary>
710
    /// Writes a <see cref="Double"/> value.
711
    /// </summary>
712
    /// <param name="value">The <see cref="Double"/> value to write.</param>
713
    public virtual void WriteValue(double value)
714
    {
715
 58
      AutoComplete(JsonToken.Float);
716
 58
    }
717

  
718
    /// <summary>
719
    /// Writes a <see cref="Boolean"/> value.
720
    /// </summary>
721
    /// <param name="value">The <see cref="Boolean"/> value to write.</param>
722
    public virtual void WriteValue(bool value)
723
    {
724
 45
      AutoComplete(JsonToken.Boolean);
725
 45
    }
726

  
727
    /// <summary>
728
    /// Writes a <see cref="Int16"/> value.
729
    /// </summary>
730
    /// <param name="value">The <see cref="Int16"/> value to write.</param>
731
    public virtual void WriteValue(short value)
732
    {
733
 5
      AutoComplete(JsonToken.Integer);
734
 5
    }
735

  
736
    /// <summary>
737
    /// Writes a <see cref="UInt16"/> value.
738
    /// </summary>
739
    /// <param name="value">The <see cref="UInt16"/> value to write.</param>
740
    public virtual void WriteValue(ushort value)
741
    {
742
 3
      AutoComplete(JsonToken.Integer);
743
 3
    }
744

  
745
    /// <summary>
746
    /// Writes a <see cref="Char"/> value.
747
    /// </summary>
748
    /// <param name="value">The <see cref="Char"/> value to write.</param>
749
    public virtual void WriteValue(char value)
750
    {
751
 13
      AutoComplete(JsonToken.String);
752
 13
    }
753

  
754
    /// <summary>
755
    /// Writes a <see cref="Byte"/> value.
756
    /// </summary>
757
    /// <param name="value">The <see cref="Byte"/> value to write.</param>
758
    public virtual void WriteValue(byte value)
759
    {
760
 5
      AutoComplete(JsonToken.Integer);
761
 5
    }
762

  
763
    /// <summary>
764
    /// Writes a <see cref="SByte"/> value.
765
    /// </summary>
766
    /// <param name="value">The <see cref="SByte"/> value to write.</param>
767
    public virtual void WriteValue(sbyte value)
768
    {
769
 4
      AutoComplete(JsonToken.Integer);
770
 4
    }
771

  
772
    /// <summary>
773
    /// Writes a <see cref="Decimal"/> value.
774
    /// </summary>
775
    /// <param name="value">The <see cref="Decimal"/> value to write.</param>
776
    public virtual void WriteValue(decimal value)
777
    {
778
 10461
      AutoComplete(JsonToken.Float);
779
 10461
    }
780

  
781
    /// <summary>
782
    /// Writes a <see cref="DateTime"/> value.
783
    /// </summary>
784
    /// <param name="value">The <see cref="DateTime"/> value to write.</param>
785
    public virtual void WriteValue(DateTime value)
786
    {
787
 41690
      AutoComplete(JsonToken.Date);
788
 41690
    }
789

  
790
#if !PocketPC && !NET20
791
    /// <summary>
792
    /// Writes a <see cref="DateTimeOffset"/> value.
793
    /// </summary>
794
    /// <param name="value">The <see cref="DateTimeOffset"/> value to write.</param>
795
    public virtual void WriteValue(DateTimeOffset value)
796
    {
797
 11
      AutoComplete(JsonToken.Date);
798
 11
    }
799
#endif
800

  
801
    /// <summary>
802
    /// Writes a <see cref="Nullable{Int32}"/> value.
803
    /// </summary>
804
    /// <param name="value">The <see cref="Nullable{Int32}"/> value to write.</param>
805
    public virtual void WriteValue(int? value)
806
    {
807
 2
      if (value == null)
808
 1
        WriteNull();
809
      else
810
 1
        WriteValue(value.Value);
811
 2
    }
812

  
813
    /// <summary>
814
    /// Writes a <see cref="Nullable{UInt32}"/> value.
815
    /// </summary>
816
    /// <param name="value">The <see cref="Nullable{UInt32}"/> value to write.</param>
817
    public virtual void WriteValue(uint? value)
818
    {
819
 2
      if (value == null)
820
 1
        WriteNull();
821
      else
822
 1
        WriteValue(value.Value);
823
 2
    }
824

  
825
    /// <summary>
826
    /// Writes a <see cref="Nullable{Int64}"/> value.
827
    /// </summary>
828
    /// <param name="value">The <see cref="Nullable{Int64}"/> value to write.</param>
829
    public virtual void WriteValue(long? value)
830
    {
831
 2
      if (value == null)
832
 1
        WriteNull();
833
      else
834
 1
        WriteValue(value.Value);
835
 2
    }
836

  
837
    /// <summary>
838
    /// Writes a <see cref="Nullable{UInt64}"/> value.
839
    /// </summary>
840
    /// <param name="value">The <see cref="Nullable{UInt64}"/> value to write.</param>
841
    public virtual void WriteValue(ulong? value)
842
    {
843
 2
      if (value == null)
844
 1
        WriteNull();
845
      else
846
 1
        WriteValue(value.Value);
847
 2
    }
848

  
849
    /// <summary>
850
    /// Writes a <see cref="Nullable{Single}"/> value.
851
    /// </summary>
852
    /// <param name="value">The <see cref="Nullable{Single}"/> value to write.</param>
853
    public virtual void WriteValue(float? value)
854
    {
855
 2
      if (value == null)
856
 1
        WriteNull();
857
      else
858
 1
        WriteValue(value.Value);
859
 2
    }
860

  
861
    /// <summary>
862
    /// Writes a <see cref="Nullable{Double}"/> value.
863
    /// </summary>
864
    /// <param name="value">The <see cref="Nullable{Double}"/> value to write.</param>
865
    public virtual void WriteValue(double? value)
866
    {
867
 2
      if (value == null)
868
 1
        WriteNull();
869
      else
870
 1
        WriteValue(value.Value);
871
 2
    }
872

  
873
    /// <summary>
874
    /// Writes a <see cref="Nullable{Boolean}"/> value.
875
    /// </summary>
876
    /// <param name="value">The <see cref="Nullable{Boolean}"/> value to write.</param>
877
    public virtual void WriteValue(bool? value)
878
    {
879
 2
      if (value == null)
880
 1
        WriteNull();
881
      else
882
 1
        WriteValue(value.Value);
883
 2
    }
884

  
885
    /// <summary>
886
    /// Writes a <see cref="Nullable{Int16}"/> value.
887
    /// </summary>
888
    /// <param name="value">The <see cref="Nullable{Int16}"/> value to write.</param>
889
    public virtual void WriteValue(short? value)
890
    {
891
 2
      if (value == null)
892
 1
        WriteNull();
893
      else
894
 1
        WriteValue(value.Value);
895
 2
    }
896

  
897
    /// <summary>
898
    /// Writes a <see cref="Nullable{UInt16}"/> value.
899
    /// </summary>
900
    /// <param name="value">The <see cref="Nullable{UInt16}"/> value to write.</param>
901
    public virtual void WriteValue(ushort? value)
902
    {
903
 2
      if (value == null)
904
 1
        WriteNull();
905
      else
906
 1
        WriteValue(value.Value);
907
 2
    }
908

  
909
    /// <summary>
910
    /// Writes a <see cref="Nullable{Char}"/> value.
911
    /// </summary>
912
    /// <param name="value">The <see cref="Nullable{Char}"/> value to write.</param>
913
    public virtual void WriteValue(char? value)
914
    {
915
 2
      if (value == null)
916
 1
        WriteNull();
917
      else
918
 1
        WriteValue(value.Value);
919
 2
    }
920

  
921
    /// <summary>
922
    /// Writes a <see cref="Nullable{Byte}"/> value.
923
    /// </summary>
924
    /// <param name="value">The <see cref="Nullable{Byte}"/> value to write.</param>
925
    public virtual void WriteValue(byte? value)
926
    {
927
 2
      if (value == null)
928
 1
        WriteNull();
929
      else
930
 1
        WriteValue(value.Value);
931
 2
    }
932

  
933
    /// <summary>
934
    /// Writes a <see cref="Nullable{SByte}"/> value.
935
    /// </summary>
936
    /// <param name="value">The <see cref="Nullable{SByte}"/> value to write.</param>
937
    public virtual void WriteValue(sbyte? value)
938
    {
939
 2
      if (value == null)
940
 1
        WriteNull();
941
      else
942
 1
        WriteValue(value.Value);
943
 2
    }
944

  
945
    /// <summary>
946
    /// Writes a <see cref="Nullable{Decimal}"/> value.
947
    /// </summary>
948
    /// <param name="value">The <see cref="Nullable{Decimal}"/> value to write.</param>
949
    public virtual void WriteValue(decimal? value)
950
    {
951
 2
      if (value == null)
952
 1
        WriteNull();
953
      else
954
 1
        WriteValue(value.Value);
955
 2
    }
956

  
957
    /// <summary>
958
    /// Writes a <see cref="Nullable{DateTime}"/> value.
959
    /// </summary>
960
    /// <param name="value">The <see cref="Nullable{DateTime}"/> value to write.</param>
961
    public virtual void WriteValue(DateTime? value)
962
    {
963
 2
      if (value == null)
964
 1
        WriteNull();
965
      else
966
 1
        WriteValue(value.Value);
967
 2
    }
968

  
969
#if !PocketPC && !NET20
970
    /// <summary>
971
    /// Writes a <see cref="Nullable{DateTimeOffset}"/> value.
972
    /// </summary>
973
    /// <param name="value">The <see cref="Nullable{DateTimeOffset}"/> value to write.</param>
974
    public virtual void WriteValue(DateTimeOffset? value)
975
    {
976
 2
      if (value == null)
977
 1
        WriteNull();
978
      else
979
 1
        WriteValue(value.Value);
980
 2
    }
981
#endif
982

  
983
    /// <summary>
984
    /// Writes a <see cref="T:Byte[]"/> value.
985
    /// </summary>
986
    /// <param name="value">The <see cref="T:Byte[]"/> value to write.</param>
987
    public virtual void WriteValue(byte[] value)
988
    {
989
 417
      if (value == null)
990
 1
        WriteNull();
991
      else
992
 416
        AutoComplete(JsonToken.Bytes);
993
 417
    }
994

  
995
    /// <summary>
996
    /// Writes a <see cref="Object"/> value.
997
    /// An error will raised if the value cannot be written as a single JSON token.
998
    /// </summary>
999
    /// <param name="value">The <see cref="Object"/> value to write.</param>
1000
    public virtual void WriteValue(object value)
1001
    {
1002
 368861
      if (value == null)
1003
      {
1004
 1
        WriteNull();
1005
 1
        return;
1006
      }
1007
 368860
      else if (value is IConvertible)
1008
      {
1009
 368446
        IConvertible convertible = value as IConvertible;
1010

  
1011
 368446
        switch (convertible.GetTypeCode())
1012
        {
1013
          case TypeCode.String:
1014
 184802
            WriteValue(convertible.ToString(CultureInfo.InvariantCulture));
1015
 184802
            return;
1016
          case TypeCode.Char:
1017
 9
            WriteValue(convertible.ToChar(CultureInfo.InvariantCulture));
1018
 9
            return;
1019
          case TypeCode.Boolean:
1020
 27
            WriteValue(convertible.ToBoolean(CultureInfo.InvariantCulture));
1021
 27
            return;
1022
          case TypeCode.SByte:
1023
 2
            WriteValue(convertible.ToSByte(CultureInfo.InvariantCulture));
1024
 2
            return;
1025
          case TypeCode.Int16:
1026
 4
            WriteValue(convertible.ToInt16(CultureInfo.InvariantCulture));
1027
 4
            return;
1028
          case TypeCode.UInt16:
1029
 2
            WriteValue(convertible.ToUInt16(CultureInfo.InvariantCulture));
1030
 2
            return;
1031
          case TypeCode.Int32:
1032
 131428
            WriteValue(convertible.ToInt32(CultureInfo.InvariantCulture));
1033
 131428
            return;
1034
          case TypeCode.Byte:
1035
 3
            WriteValue(convertible.ToByte(CultureInfo.InvariantCulture));
1036
 3
            return;
1037
          case TypeCode.UInt32:
1038
 2
            WriteValue(convertible.ToUInt32(CultureInfo.InvariantCulture));
1039
 2
            return;
1040
          case TypeCode.Int64:
1041
 15
            WriteValue(convertible.ToInt64(CultureInfo.InvariantCulture));
1042
 15
            return;
1043
          case TypeCode.UInt64:
1044
 2
            WriteValue(convertible.ToUInt64(CultureInfo.InvariantCulture));
1045
 2
            return;
1046
          case TypeCode.Single:
1047
 2
            WriteValue(convertible.ToSingle(CultureInfo.InvariantCulture));
1048
 2
            return;
1049
          case TypeCode.Double:
1050
 9
            WriteValue(convertible.ToDouble(CultureInfo.InvariantCulture));
1051
 9
            return;
1052
          case TypeCode.DateTime:
1053
 41681
            WriteValue(convertible.ToDateTime(CultureInfo.InvariantCulture));
1054
 41681
            return;
1055
          case TypeCode.Decimal:
1056
 10456
            WriteValue(convertible.ToDecimal(CultureInfo.InvariantCulture));
1057
 10456
            return;
1058
          case TypeCode.DBNull:
1059
 2
            WriteNull();
1060
 2
            return;
1061
        }
1062
      }
1063
#if !PocketPC && !NET20
1064
 414
      else if (value is DateTimeOffset)
1065
      {
1066
 9
        WriteValue((DateTimeOffset)value);
1067
 9
        return;
1068
      }
1069
#endif
1070
 405
      else if (value is byte[])
1071
      {
1072
 404
        WriteValue((byte[])value);
1073
 404
        return;
1074
      }
1075

  
1076
 1
      throw new ArgumentException("Unsupported type: {0}. Use the JsonSerializer class to get the object's JSON representation.".FormatWith(CultureInfo.InvariantCulture, value.GetType()));
1077
 368860
    }
1078
    #endregion
1079

  
1080
    /// <summary>
1081
    /// Writes out a comment <code>/*...*/</code> containing the specified text. 
1082
    /// </summary>
1083
    /// <param name="text">Text to place inside the comment.</param>
1084
    public virtual void WriteComment(string text)
1085
    {
1086
 6
      AutoComplete(JsonToken.Comment);
1087
 6
    }
1088

  
1089
    /// <summary>
1090
    /// Writes out the given white space.
1091
    /// </summary>
1092
    /// <param name="ws">The string of white space characters.</param>
1093
    public virtual void WriteWhitespace(string ws)
1094
    {
1095
 1
      if (ws != null)
1096
      {
1097
 1
        if (!StringUtils.IsWhiteSpace(ws))
1098
 0
          throw new JsonWriterException("Only white space characters should be used.");
1099
      }
1100
 1
    }
1101

  
1102

  
1103
    void IDisposable.Dispose()
1104
    {
1105
 5702
      Dispose(true);
1106
 5702
    }
1107

  
1108
    private void Dispose(bool disposing)
1109
    {
1110
 5702
      if (WriteState != WriteState.Closed)
1111
 5702
        Close();
1112
 5702
    }
1113
  }
1114
}