You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1789 lines
62 KiB

4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
  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. using System;
  26. using System.Collections.Generic;
  27. using System.IO;
  28. #if HAVE_BIG_INTEGER
  29. using System.Numerics;
  30. #endif
  31. using Newtonsoft.Json.Utilities;
  32. using System.Globalization;
  33. #if NET20
  34. using Newtonsoft.Json.Utilities.LinqBridge;
  35. #else
  36. using System.Linq;
  37. #endif
  38. namespace Newtonsoft.Json
  39. {
  40. /// <summary>
  41. /// Represents a writer that provides a fast, non-cached, forward-only way of generating JSON data.
  42. /// </summary>
  43. internal abstract partial class JsonWriter : IDisposable
  44. {
  45. internal enum State
  46. {
  47. Start = 0,
  48. Property = 1,
  49. ObjectStart = 2,
  50. Object = 3,
  51. ArrayStart = 4,
  52. Array = 5,
  53. ConstructorStart = 6,
  54. Constructor = 7,
  55. Closed = 8,
  56. Error = 9
  57. }
  58. // array that gives a new state based on the current state an the token being written
  59. private static readonly State[][] StateArray;
  60. internal static readonly State[][] StateArrayTempate = new[]
  61. {
  62. // Start PropertyName ObjectStart Object ArrayStart Array ConstructorStart Constructor Closed Error
  63. //
  64. /* None */new[] { State.Error, State.Error, State.Error, State.Error, State.Error, State.Error, State.Error, State.Error, State.Error, State.Error },
  65. /* StartObject */new[] { State.ObjectStart, State.ObjectStart, State.Error, State.Error, State.ObjectStart, State.ObjectStart, State.ObjectStart, State.ObjectStart, State.Error, State.Error },
  66. /* StartArray */new[] { State.ArrayStart, State.ArrayStart, State.Error, State.Error, State.ArrayStart, State.ArrayStart, State.ArrayStart, State.ArrayStart, State.Error, State.Error },
  67. /* StartConstructor */new[] { State.ConstructorStart, State.ConstructorStart, State.Error, State.Error, State.ConstructorStart, State.ConstructorStart, State.ConstructorStart, State.ConstructorStart, State.Error, State.Error },
  68. /* Property */new[] { State.Property, State.Error, State.Property, State.Property, State.Error, State.Error, State.Error, State.Error, State.Error, State.Error },
  69. /* Comment */new[] { State.Start, State.Property, State.ObjectStart, State.Object, State.ArrayStart, State.Array, State.Constructor, State.Constructor, State.Error, State.Error },
  70. /* Raw */new[] { State.Start, State.Property, State.ObjectStart, State.Object, State.ArrayStart, State.Array, State.Constructor, State.Constructor, State.Error, State.Error },
  71. /* Value (this will be copied) */new[] { State.Start, State.Object, State.Error, State.Error, State.Array, State.Array, State.Constructor, State.Constructor, State.Error, State.Error }
  72. };
  73. internal static State[][] BuildStateArray()
  74. {
  75. List<State[]> allStates = StateArrayTempate.List();
  76. State[] errorStates = StateArrayTempate[0];
  77. State[] valueStates = StateArrayTempate[7];
  78. EnumInfo enumValuesAndNames = EnumUtils.GetEnumValuesAndNames(typeof(JsonToken));
  79. foreach (ulong valueToken in enumValuesAndNames.Values)
  80. {
  81. if (allStates.Count <= (int)valueToken)
  82. {
  83. JsonToken token = (JsonToken)valueToken;
  84. switch (token)
  85. {
  86. case JsonToken.Integer:
  87. case JsonToken.Float:
  88. case JsonToken.String:
  89. case JsonToken.Boolean:
  90. case JsonToken.Null:
  91. case JsonToken.Undefined:
  92. case JsonToken.Date:
  93. case JsonToken.Bytes:
  94. allStates.Add(valueStates);
  95. break;
  96. default:
  97. allStates.Add(errorStates);
  98. break;
  99. }
  100. }
  101. }
  102. return allStates.ToArray();
  103. }
  104. static JsonWriter()
  105. {
  106. StateArray = BuildStateArray();
  107. }
  108. private List<JsonPosition> _stack;
  109. private JsonPosition _currentPosition;
  110. private State _currentState;
  111. private Formatting _formatting;
  112. /// <summary>
  113. /// Gets or sets a value indicating whether the destination should be closed when this writer is closed.
  114. /// </summary>
  115. /// <value>
  116. /// <c>true</c> to close the destination when this writer is closed; otherwise <c>false</c>. The default is <c>true</c>.
  117. /// </value>
  118. public bool CloseOutput { get; set; }
  119. /// <summary>
  120. /// Gets or sets a value indicating whether the JSON should be auto-completed when this writer is closed.
  121. /// </summary>
  122. /// <value>
  123. /// <c>true</c> to auto-complete the JSON when this writer is closed; otherwise <c>false</c>. The default is <c>true</c>.
  124. /// </value>
  125. public bool AutoCompleteOnClose { get; set; }
  126. /// <summary>
  127. /// Gets the top.
  128. /// </summary>
  129. /// <value>The top.</value>
  130. protected internal int Top
  131. {
  132. get
  133. {
  134. int depth = _stack?.Count ?? 0;
  135. if (Peek() != JsonContainerType.None)
  136. {
  137. depth++;
  138. }
  139. return depth;
  140. }
  141. }
  142. /// <summary>
  143. /// Gets the state of the writer.
  144. /// </summary>
  145. public WriteState WriteState
  146. {
  147. get
  148. {
  149. switch (_currentState)
  150. {
  151. case State.Error:
  152. return WriteState.Error;
  153. case State.Closed:
  154. return WriteState.Closed;
  155. case State.Object:
  156. case State.ObjectStart:
  157. return WriteState.Object;
  158. case State.Array:
  159. case State.ArrayStart:
  160. return WriteState.Array;
  161. case State.Constructor:
  162. case State.ConstructorStart:
  163. return WriteState.Constructor;
  164. case State.Property:
  165. return WriteState.Property;
  166. case State.Start:
  167. return WriteState.Start;
  168. default:
  169. throw JsonWriterException.Create(this, "Invalid state: " + _currentState, null);
  170. }
  171. }
  172. }
  173. internal string ContainerPath
  174. {
  175. get
  176. {
  177. if (_currentPosition.Type == JsonContainerType.None || _stack == null)
  178. {
  179. return string.Empty;
  180. }
  181. return JsonPosition.BuildPath(_stack, null);
  182. }
  183. }
  184. /// <summary>
  185. /// Gets the path of the writer.
  186. /// </summary>
  187. public string Path
  188. {
  189. get
  190. {
  191. if (_currentPosition.Type == JsonContainerType.None)
  192. {
  193. return string.Empty;
  194. }
  195. bool insideContainer = (_currentState != State.ArrayStart
  196. && _currentState != State.ConstructorStart
  197. && _currentState != State.ObjectStart);
  198. JsonPosition? current = insideContainer ? (JsonPosition?)_currentPosition : null;
  199. return JsonPosition.BuildPath(_stack, current);
  200. }
  201. }
  202. private DateFormatHandling _dateFormatHandling;
  203. private DateTimeZoneHandling _dateTimeZoneHandling;
  204. private StringEscapeHandling _stringEscapeHandling;
  205. private FloatFormatHandling _floatFormatHandling;
  206. private string _dateFormatString;
  207. private CultureInfo _culture;
  208. /// <summary>
  209. /// Gets or sets a value indicating how JSON text output should be formatted.
  210. /// </summary>
  211. public Formatting Formatting
  212. {
  213. get => _formatting;
  214. set
  215. {
  216. if (value < Formatting.None || value > Formatting.Indented)
  217. {
  218. throw new ArgumentOutOfRangeException(nameof(value));
  219. }
  220. _formatting = value;
  221. }
  222. }
  223. /// <summary>
  224. /// Gets or sets how dates are written to JSON text.
  225. /// </summary>
  226. public DateFormatHandling DateFormatHandling
  227. {
  228. get => _dateFormatHandling;
  229. set
  230. {
  231. if (value < DateFormatHandling.IsoDateFormat || value > DateFormatHandling.MicrosoftDateFormat)
  232. {
  233. throw new ArgumentOutOfRangeException(nameof(value));
  234. }
  235. _dateFormatHandling = value;
  236. }
  237. }
  238. /// <summary>
  239. /// Gets or sets how <see cref="DateTime"/> time zones are handled when writing JSON text.
  240. /// </summary>
  241. public DateTimeZoneHandling DateTimeZoneHandling
  242. {
  243. get => _dateTimeZoneHandling;
  244. set
  245. {
  246. if (value < DateTimeZoneHandling.Local || value > DateTimeZoneHandling.RoundtripKind)
  247. {
  248. throw new ArgumentOutOfRangeException(nameof(value));
  249. }
  250. _dateTimeZoneHandling = value;
  251. }
  252. }
  253. /// <summary>
  254. /// Gets or sets how strings are escaped when writing JSON text.
  255. /// </summary>
  256. public StringEscapeHandling StringEscapeHandling
  257. {
  258. get => _stringEscapeHandling;
  259. set
  260. {
  261. if (value < StringEscapeHandling.Default || value > StringEscapeHandling.EscapeHtml)
  262. {
  263. throw new ArgumentOutOfRangeException(nameof(value));
  264. }
  265. _stringEscapeHandling = value;
  266. OnStringEscapeHandlingChanged();
  267. }
  268. }
  269. internal virtual void OnStringEscapeHandlingChanged()
  270. {
  271. // hacky but there is a calculated value that relies on StringEscapeHandling
  272. }
  273. /// <summary>
  274. /// Gets or sets how special floating point numbers, e.g. <see cref="Double.NaN"/>,
  275. /// <see cref="Double.PositiveInfinity"/> and <see cref="Double.NegativeInfinity"/>,
  276. /// are written to JSON text.
  277. /// </summary>
  278. public FloatFormatHandling FloatFormatHandling
  279. {
  280. get => _floatFormatHandling;
  281. set
  282. {
  283. if (value < FloatFormatHandling.String || value > FloatFormatHandling.DefaultValue)
  284. {
  285. throw new ArgumentOutOfRangeException(nameof(value));
  286. }
  287. _floatFormatHandling = value;
  288. }
  289. }
  290. /// <summary>
  291. /// Gets or sets how <see cref="DateTime"/> and <see cref="DateTimeOffset"/> values are formatted when writing JSON text.
  292. /// </summary>
  293. public string DateFormatString
  294. {
  295. get => _dateFormatString;
  296. set => _dateFormatString = value;
  297. }
  298. /// <summary>
  299. /// Gets or sets the culture used when writing JSON. Defaults to <see cref="CultureInfo.InvariantCulture"/>.
  300. /// </summary>
  301. public CultureInfo Culture
  302. {
  303. get => _culture ?? CultureInfo.InvariantCulture;
  304. set => _culture = value;
  305. }
  306. /// <summary>
  307. /// Initializes a new instance of the <see cref="JsonWriter"/> class.
  308. /// </summary>
  309. protected JsonWriter()
  310. {
  311. _currentState = State.Start;
  312. _formatting = Formatting.None;
  313. _dateTimeZoneHandling = DateTimeZoneHandling.RoundtripKind;
  314. CloseOutput = true;
  315. AutoCompleteOnClose = true;
  316. }
  317. internal void UpdateScopeWithFinishedValue()
  318. {
  319. if (_currentPosition.HasIndex)
  320. {
  321. _currentPosition.Position++;
  322. }
  323. }
  324. private void Push(JsonContainerType value)
  325. {
  326. if (_currentPosition.Type != JsonContainerType.None)
  327. {
  328. if (_stack == null)
  329. {
  330. _stack = new List<JsonPosition>();
  331. }
  332. _stack.Add(_currentPosition);
  333. }
  334. _currentPosition = new JsonPosition(value);
  335. }
  336. private JsonContainerType Pop()
  337. {
  338. JsonPosition oldPosition = _currentPosition;
  339. if (_stack != null && _stack.Count > 0)
  340. {
  341. _currentPosition = _stack[_stack.Count - 1];
  342. _stack.RemoveAt(_stack.Count - 1);
  343. }
  344. else
  345. {
  346. _currentPosition = new JsonPosition();
  347. }
  348. return oldPosition.Type;
  349. }
  350. private JsonContainerType Peek()
  351. {
  352. return _currentPosition.Type;
  353. }
  354. /// <summary>
  355. /// Flushes whatever is in the buffer to the destination and also flushes the destination.
  356. /// </summary>
  357. public abstract void Flush();
  358. /// <summary>
  359. /// Closes this writer.
  360. /// If <see cref="CloseOutput"/> is set to <c>true</c>, the destination is also closed.
  361. /// If <see cref="AutoCompleteOnClose"/> is set to <c>true</c>, the JSON is auto-completed.
  362. /// </summary>
  363. public virtual void Close()
  364. {
  365. if (AutoCompleteOnClose)
  366. {
  367. AutoCompleteAll();
  368. }
  369. }
  370. /// <summary>
  371. /// Writes the beginning of a JSON object.
  372. /// </summary>
  373. public virtual void WriteStartObject()
  374. {
  375. InternalWriteStart(JsonToken.StartObject, JsonContainerType.Object);
  376. }
  377. /// <summary>
  378. /// Writes the end of a JSON object.
  379. /// </summary>
  380. public virtual void WriteEndObject()
  381. {
  382. InternalWriteEnd(JsonContainerType.Object);
  383. }
  384. /// <summary>
  385. /// Writes the beginning of a JSON array.
  386. /// </summary>
  387. public virtual void WriteStartArray()
  388. {
  389. InternalWriteStart(JsonToken.StartArray, JsonContainerType.Array);
  390. }
  391. /// <summary>
  392. /// Writes the end of an array.
  393. /// </summary>
  394. public virtual void WriteEndArray()
  395. {
  396. InternalWriteEnd(JsonContainerType.Array);
  397. }
  398. /// <summary>
  399. /// Writes the start of a constructor with the given name.
  400. /// </summary>
  401. /// <param name="name">The name of the constructor.</param>
  402. public virtual void WriteStartConstructor(string name)
  403. {
  404. InternalWriteStart(JsonToken.StartConstructor, JsonContainerType.Constructor);
  405. }
  406. /// <summary>
  407. /// Writes the end constructor.
  408. /// </summary>
  409. public virtual void WriteEndConstructor()
  410. {
  411. InternalWriteEnd(JsonContainerType.Constructor);
  412. }
  413. /// <summary>
  414. /// Writes the property name of a name/value pair of a JSON object.
  415. /// </summary>
  416. /// <param name="name">The name of the property.</param>
  417. public virtual void WritePropertyName(string name)
  418. {
  419. InternalWritePropertyName(name);
  420. }
  421. /// <summary>
  422. /// Writes the property name of a name/value pair of a JSON object.
  423. /// </summary>
  424. /// <param name="name">The name of the property.</param>
  425. /// <param name="escape">A flag to indicate whether the text should be escaped when it is written as a JSON property name.</param>
  426. public virtual void WritePropertyName(string name, bool escape)
  427. {
  428. WritePropertyName(name);
  429. }
  430. /// <summary>
  431. /// Writes the end of the current JSON object or array.
  432. /// </summary>
  433. public virtual void WriteEnd()
  434. {
  435. WriteEnd(Peek());
  436. }
  437. /// <summary>
  438. /// Writes the current <see cref="JsonReader"/> token and its children.
  439. /// </summary>
  440. /// <param name="reader">The <see cref="JsonReader"/> to read the token from.</param>
  441. public void WriteToken(JsonReader reader)
  442. {
  443. WriteToken(reader, true);
  444. }
  445. /// <summary>
  446. /// Writes the current <see cref="JsonReader"/> token.
  447. /// </summary>
  448. /// <param name="reader">The <see cref="JsonReader"/> to read the token from.</param>
  449. /// <param name="writeChildren">A flag indicating whether the current token's children should be written.</param>
  450. public void WriteToken(JsonReader reader, bool writeChildren)
  451. {
  452. ValidationUtils.ArgumentNotNull(reader, nameof(reader));
  453. WriteToken(reader, writeChildren, true, true);
  454. }
  455. /// <summary>
  456. /// Writes the <see cref="JsonToken"/> token and its value.
  457. /// </summary>
  458. /// <param name="token">The <see cref="JsonToken"/> to write.</param>
  459. /// <param name="value">
  460. /// The value to write.
  461. /// A value is only required for tokens that have an associated value, e.g. the <see cref="String"/> property name for <see cref="JsonToken.PropertyName"/>.
  462. /// <c>null</c> can be passed to the method for tokens that don't have a value, e.g. <see cref="JsonToken.StartObject"/>.
  463. /// </param>
  464. public void WriteToken(JsonToken token, object value)
  465. {
  466. switch (token)
  467. {
  468. case JsonToken.None:
  469. // read to next
  470. break;
  471. case JsonToken.StartObject:
  472. WriteStartObject();
  473. break;
  474. case JsonToken.StartArray:
  475. WriteStartArray();
  476. break;
  477. case JsonToken.StartConstructor:
  478. ValidationUtils.ArgumentNotNull(value, nameof(value));
  479. WriteStartConstructor(value.ToString());
  480. break;
  481. case JsonToken.PropertyName:
  482. ValidationUtils.ArgumentNotNull(value, nameof(value));
  483. WritePropertyName(value.ToString());
  484. break;
  485. case JsonToken.Comment:
  486. WriteComment(value?.ToString());
  487. break;
  488. case JsonToken.Integer:
  489. ValidationUtils.ArgumentNotNull(value, nameof(value));
  490. #if HAVE_BIG_INTEGER
  491. if (value is BigInteger integer)
  492. {
  493. WriteValue(integer);
  494. }
  495. else
  496. #endif
  497. {
  498. WriteValue(Convert.ToInt64(value, CultureInfo.InvariantCulture));
  499. }
  500. break;
  501. case JsonToken.Float:
  502. ValidationUtils.ArgumentNotNull(value, nameof(value));
  503. if (value is decimal d)
  504. {
  505. WriteValue(d);
  506. }
  507. else if (value is double)
  508. {
  509. WriteValue((double)value);
  510. }
  511. else if (value is float)
  512. {
  513. WriteValue((float)value);
  514. }
  515. else
  516. {
  517. WriteValue(Convert.ToDouble(value, CultureInfo.InvariantCulture));
  518. }
  519. break;
  520. case JsonToken.String:
  521. ValidationUtils.ArgumentNotNull(value, nameof(value));
  522. WriteValue(value.ToString());
  523. break;
  524. case JsonToken.Boolean:
  525. ValidationUtils.ArgumentNotNull(value, nameof(value));
  526. WriteValue(Convert.ToBoolean(value, CultureInfo.InvariantCulture));
  527. break;
  528. case JsonToken.Null:
  529. WriteNull();
  530. break;
  531. case JsonToken.Undefined:
  532. WriteUndefined();
  533. break;
  534. case JsonToken.EndObject:
  535. WriteEndObject();
  536. break;
  537. case JsonToken.EndArray:
  538. WriteEndArray();
  539. break;
  540. case JsonToken.EndConstructor:
  541. WriteEndConstructor();
  542. break;
  543. case JsonToken.Date:
  544. ValidationUtils.ArgumentNotNull(value, nameof(value));
  545. #if !NET20
  546. if (value is DateTimeOffset dt)
  547. {
  548. WriteValue(dt);
  549. }
  550. else
  551. #endif
  552. {
  553. WriteValue(Convert.ToDateTime(value, CultureInfo.InvariantCulture));
  554. }
  555. break;
  556. case JsonToken.Raw:
  557. WriteRawValue(value?.ToString());
  558. break;
  559. case JsonToken.Bytes:
  560. ValidationUtils.ArgumentNotNull(value, nameof(value));
  561. if (value is Guid guid)
  562. {
  563. WriteValue(guid);
  564. }
  565. else
  566. {
  567. WriteValue((byte[])value);
  568. }
  569. break;
  570. default:
  571. throw MiscellaneousUtils.CreateArgumentOutOfRangeException(nameof(token), token, "Unexpected token type.");
  572. }
  573. }
  574. /// <summary>
  575. /// Writes the <see cref="JsonToken"/> token.
  576. /// </summary>
  577. /// <param name="token">The <see cref="JsonToken"/> to write.</param>
  578. public void WriteToken(JsonToken token)
  579. {
  580. WriteToken(token, null);
  581. }
  582. internal virtual void WriteToken(JsonReader reader, bool writeChildren, bool writeDateConstructorAsDate, bool writeComments)
  583. {
  584. int initialDepth = CalculateWriteTokenInitialDepth(reader);
  585. do
  586. {
  587. // write a JValue date when the constructor is for a date
  588. if (writeDateConstructorAsDate && reader.TokenType == JsonToken.StartConstructor && string.Equals(reader.Value.ToString(), "Date", StringComparison.Ordinal))
  589. {
  590. WriteConstructorDate(reader);
  591. }
  592. else
  593. {
  594. if (writeComments || reader.TokenType != JsonToken.Comment)
  595. {
  596. WriteToken(reader.TokenType, reader.Value);
  597. }
  598. }
  599. } while (
  600. // stop if we have reached the end of the token being read
  601. initialDepth - 1 < reader.Depth - (JsonTokenUtils.IsEndToken(reader.TokenType) ? 1 : 0)
  602. && writeChildren
  603. && reader.Read());
  604. if (initialDepth < CalculateWriteTokenFinalDepth(reader))
  605. {
  606. throw JsonWriterException.Create(this, "Unexpected end when reading token.", null);
  607. }
  608. }
  609. private int CalculateWriteTokenInitialDepth(JsonReader reader)
  610. {
  611. JsonToken type = reader.TokenType;
  612. if (type == JsonToken.None)
  613. {
  614. return -1;
  615. }
  616. return JsonTokenUtils.IsStartToken(type) ? reader.Depth : reader.Depth + 1;
  617. }
  618. private int CalculateWriteTokenFinalDepth(JsonReader reader)
  619. {
  620. JsonToken type = reader.TokenType;
  621. if (type == JsonToken.None)
  622. {
  623. return -1;
  624. }
  625. return JsonTokenUtils.IsEndToken(type) ? reader.Depth - 1 : reader.Depth;
  626. }
  627. private void WriteConstructorDate(JsonReader reader)
  628. {
  629. if (!reader.Read())
  630. {
  631. throw JsonWriterException.Create(this, "Unexpected end when reading date constructor.", null);
  632. }
  633. if (reader.TokenType != JsonToken.Integer)
  634. {
  635. throw JsonWriterException.Create(this, "Unexpected token when reading date constructor. Expected Integer, got " + reader.TokenType, null);
  636. }
  637. long ticks = (long)reader.Value;
  638. DateTime date = DateTimeUtils.ConvertJavaScriptTicksToDateTime(ticks);
  639. if (!reader.Read())
  640. {
  641. throw JsonWriterException.Create(this, "Unexpected end when reading date constructor.", null);
  642. }
  643. if (reader.TokenType != JsonToken.EndConstructor)
  644. {
  645. throw JsonWriterException.Create(this, "Unexpected token when reading date constructor. Expected EndConstructor, got " + reader.TokenType, null);
  646. }
  647. WriteValue(date);
  648. }
  649. private void WriteEnd(JsonContainerType type)
  650. {
  651. switch (type)
  652. {
  653. case JsonContainerType.Object:
  654. WriteEndObject();
  655. break;
  656. case JsonContainerType.Array:
  657. WriteEndArray();
  658. break;
  659. case JsonContainerType.Constructor:
  660. WriteEndConstructor();
  661. break;
  662. default:
  663. throw JsonWriterException.Create(this, "Unexpected type when writing end: " + type, null);
  664. }
  665. }
  666. private void AutoCompleteAll()
  667. {
  668. while (Top > 0)
  669. {
  670. WriteEnd();
  671. }
  672. }
  673. private JsonToken GetCloseTokenForType(JsonContainerType type)
  674. {
  675. switch (type)
  676. {
  677. case JsonContainerType.Object:
  678. return JsonToken.EndObject;
  679. case JsonContainerType.Array:
  680. return JsonToken.EndArray;
  681. case JsonContainerType.Constructor:
  682. return JsonToken.EndConstructor;
  683. default:
  684. throw JsonWriterException.Create(this, "No close token for type: " + type, null);
  685. }
  686. }
  687. private void AutoCompleteClose(JsonContainerType type)
  688. {
  689. int levelsToComplete = CalculateLevelsToComplete(type);
  690. for (int i = 0; i < levelsToComplete; i++)
  691. {
  692. JsonToken token = GetCloseTokenForType(Pop());
  693. if (_currentState == State.Property)
  694. {
  695. WriteNull();
  696. }
  697. if (_formatting == Formatting.Indented)
  698. {
  699. if (_currentState != State.ObjectStart && _currentState != State.ArrayStart)
  700. {
  701. WriteIndent();
  702. }
  703. }
  704. WriteEnd(token);
  705. UpdateCurrentState();
  706. }
  707. }
  708. private int CalculateLevelsToComplete(JsonContainerType type)
  709. {
  710. int levelsToComplete = 0;
  711. if (_currentPosition.Type == type)
  712. {
  713. levelsToComplete = 1;
  714. }
  715. else
  716. {
  717. int top = Top - 2;
  718. for (int i = top; i >= 0; i--)
  719. {
  720. int currentLevel = top - i;
  721. if (_stack[currentLevel].Type == type)
  722. {
  723. levelsToComplete = i + 2;
  724. break;
  725. }
  726. }
  727. }
  728. if (levelsToComplete == 0)
  729. {
  730. throw JsonWriterException.Create(this, "No token to close.", null);
  731. }
  732. return levelsToComplete;
  733. }
  734. private void UpdateCurrentState()
  735. {
  736. JsonContainerType currentLevelType = Peek();
  737. switch (currentLevelType)
  738. {
  739. case JsonContainerType.Object:
  740. _currentState = State.Object;
  741. break;
  742. case JsonContainerType.Array:
  743. _currentState = State.Array;
  744. break;
  745. case JsonContainerType.Constructor:
  746. _currentState = State.Array;
  747. break;
  748. case JsonContainerType.None:
  749. _currentState = State.Start;
  750. break;
  751. default:
  752. throw JsonWriterException.Create(this, "Unknown JsonType: " + currentLevelType, null);
  753. }
  754. }
  755. /// <summary>
  756. /// Writes the specified end token.
  757. /// </summary>
  758. /// <param name="token">The end token to write.</param>
  759. protected virtual void WriteEnd(JsonToken token)
  760. {
  761. }
  762. /// <summary>
  763. /// Writes indent characters.
  764. /// </summary>
  765. protected virtual void WriteIndent()
  766. {
  767. }
  768. /// <summary>
  769. /// Writes the JSON value delimiter.
  770. /// </summary>
  771. protected virtual void WriteValueDelimiter()
  772. {
  773. }
  774. /// <summary>
  775. /// Writes an indent space.
  776. /// </summary>
  777. protected virtual void WriteIndentSpace()
  778. {
  779. }
  780. internal void AutoComplete(JsonToken tokenBeingWritten)
  781. {
  782. // gets new state based on the current state and what is being written
  783. State newState = StateArray[(int)tokenBeingWritten][(int)_currentState];
  784. if (newState == State.Error)
  785. {
  786. throw JsonWriterException.Create(this, "Token {0} in state {1} would result in an invalid JSON object.".FormatWith(CultureInfo.InvariantCulture, tokenBeingWritten.ToString(), _currentState.ToString()), null);
  787. }
  788. if ((_currentState == State.Object || _currentState == State.Array || _currentState == State.Constructor) && tokenBeingWritten != JsonToken.Comment)
  789. {
  790. WriteValueDelimiter();
  791. }
  792. if (_formatting == Formatting.Indented)
  793. {
  794. if (_currentState == State.Property)
  795. {
  796. WriteIndentSpace();
  797. }
  798. // don't indent a property when it is the first token to be written (i.e. at the start)
  799. if ((_currentState == State.Array || _currentState == State.ArrayStart || _currentState == State.Constructor || _currentState == State.ConstructorStart)
  800. || (tokenBeingWritten == JsonToken.PropertyName && _currentState != State.Start))
  801. {
  802. WriteIndent();
  803. }
  804. }
  805. _currentState = newState;
  806. }
  807. #region WriteValue methods
  808. /// <summary>
  809. /// Writes a null value.
  810. /// </summary>
  811. public virtual void WriteNull()
  812. {
  813. InternalWriteValue(JsonToken.Null);
  814. }
  815. /// <summary>
  816. /// Writes an undefined value.
  817. /// </summary>
  818. public virtual void WriteUndefined()
  819. {
  820. InternalWriteValue(JsonToken.Undefined);
  821. }
  822. /// <summary>
  823. /// Writes raw JSON without changing the writer's state.
  824. /// </summary>
  825. /// <param name="json">The raw JSON to write.</param>
  826. public virtual void WriteRaw(string json)
  827. {
  828. InternalWriteRaw();
  829. }
  830. /// <summary>
  831. /// Writes raw JSON where a value is expected and updates the writer's state.
  832. /// </summary>
  833. /// <param name="json">The raw JSON to write.</param>
  834. public virtual void WriteRawValue(string json)
  835. {
  836. // hack. want writer to change state as if a value had been written
  837. UpdateScopeWithFinishedValue();
  838. AutoComplete(JsonToken.Undefined);
  839. WriteRaw(json);
  840. }
  841. /// <summary>
  842. /// Writes a <see cref="String"/> value.
  843. /// </summary>
  844. /// <param name="value">The <see cref="String"/> value to write.</param>
  845. public virtual void WriteValue(string value)
  846. {
  847. InternalWriteValue(JsonToken.String);
  848. }
  849. /// <summary>
  850. /// Writes a <see cref="Int32"/> value.
  851. /// </summary>
  852. /// <param name="value">The <see cref="Int32"/> value to write.</param>
  853. public virtual void WriteValue(int value)
  854. {
  855. InternalWriteValue(JsonToken.Integer);
  856. }
  857. /// <summary>
  858. /// Writes a <see cref="UInt32"/> value.
  859. /// </summary>
  860. /// <param name="value">The <see cref="UInt32"/> value to write.</param>
  861. public virtual void WriteValue(uint value)
  862. {
  863. InternalWriteValue(JsonToken.Integer);
  864. }
  865. /// <summary>
  866. /// Writes a <see cref="Int64"/> value.
  867. /// </summary>
  868. /// <param name="value">The <see cref="Int64"/> value to write.</param>
  869. public virtual void WriteValue(long value)
  870. {
  871. InternalWriteValue(JsonToken.Integer);
  872. }
  873. /// <summary>
  874. /// Writes a <see cref="UInt64"/> value.
  875. /// </summary>
  876. /// <param name="value">The <see cref="UInt64"/> value to write.</param>
  877. public virtual void WriteValue(ulong value)
  878. {
  879. InternalWriteValue(JsonToken.Integer);
  880. }
  881. /// <summary>
  882. /// Writes a <see cref="Single"/> value.
  883. /// </summary>
  884. /// <param name="value">The <see cref="Single"/> value to write.</param>
  885. public virtual void WriteValue(float value)
  886. {
  887. InternalWriteValue(JsonToken.Float);
  888. }
  889. /// <summary>
  890. /// Writes a <see cref="Double"/> value.
  891. /// </summary>
  892. /// <param name="value">The <see cref="Double"/> value to write.</param>
  893. public virtual void WriteValue(double value)
  894. {
  895. InternalWriteValue(JsonToken.Float);
  896. }
  897. /// <summary>
  898. /// Writes a <see cref="Boolean"/> value.
  899. /// </summary>
  900. /// <param name="value">The <see cref="Boolean"/> value to write.</param>
  901. public virtual void WriteValue(bool value)
  902. {
  903. InternalWriteValue(JsonToken.Boolean);
  904. }
  905. /// <summary>
  906. /// Writes a <see cref="Int16"/> value.
  907. /// </summary>
  908. /// <param name="value">The <see cref="Int16"/> value to write.</param>
  909. public virtual void WriteValue(short value)
  910. {
  911. InternalWriteValue(JsonToken.Integer);
  912. }
  913. /// <summary>
  914. /// Writes a <see cref="UInt16"/> value.
  915. /// </summary>
  916. /// <param name="value">The <see cref="UInt16"/> value to write.</param>
  917. public virtual void WriteValue(ushort value)
  918. {
  919. InternalWriteValue(JsonToken.Integer);
  920. }
  921. /// <summary>
  922. /// Writes a <see cref="Char"/> value.
  923. /// </summary>
  924. /// <param name="value">The <see cref="Char"/> value to write.</param>
  925. public virtual void WriteValue(char value)
  926. {
  927. InternalWriteValue(JsonToken.String);
  928. }
  929. /// <summary>
  930. /// Writes a <see cref="Byte"/> value.
  931. /// </summary>
  932. /// <param name="value">The <see cref="Byte"/> value to write.</param>
  933. public virtual void WriteValue(byte value)
  934. {
  935. InternalWriteValue(JsonToken.Integer);
  936. }
  937. /// <summary>
  938. /// Writes a <see cref="SByte"/> value.
  939. /// </summary>
  940. /// <param name="value">The <see cref="SByte"/> value to write.</param>
  941. public virtual void WriteValue(sbyte value)
  942. {
  943. InternalWriteValue(JsonToken.Integer);
  944. }
  945. /// <summary>
  946. /// Writes a <see cref="Decimal"/> value.
  947. /// </summary>
  948. /// <param name="value">The <see cref="Decimal"/> value to write.</param>
  949. public virtual void WriteValue(decimal value)
  950. {
  951. InternalWriteValue(JsonToken.Float);
  952. }
  953. /// <summary>
  954. /// Writes a <see cref="DateTime"/> value.
  955. /// </summary>
  956. /// <param name="value">The <see cref="DateTime"/> value to write.</param>
  957. public virtual void WriteValue(DateTime value)
  958. {
  959. InternalWriteValue(JsonToken.Date);
  960. }
  961. #if !NET20
  962. /// <summary>
  963. /// Writes a <see cref="DateTimeOffset"/> value.
  964. /// </summary>
  965. /// <param name="value">The <see cref="DateTimeOffset"/> value to write.</param>
  966. public virtual void WriteValue(DateTimeOffset value)
  967. {
  968. InternalWriteValue(JsonToken.Date);
  969. }
  970. #endif
  971. /// <summary>
  972. /// Writes a <see cref="Guid"/> value.
  973. /// </summary>
  974. /// <param name="value">The <see cref="Guid"/> value to write.</param>
  975. public virtual void WriteValue(Guid value)
  976. {
  977. InternalWriteValue(JsonToken.String);
  978. }
  979. /// <summary>
  980. /// Writes a <see cref="TimeSpan"/> value.
  981. /// </summary>
  982. /// <param name="value">The <see cref="TimeSpan"/> value to write.</param>
  983. public virtual void WriteValue(TimeSpan value)
  984. {
  985. InternalWriteValue(JsonToken.String);
  986. }
  987. /// <summary>
  988. /// Writes a <see cref="Nullable{T}"/> of <see cref="Int32"/> value.
  989. /// </summary>
  990. /// <param name="value">The <see cref="Nullable{T}"/> of <see cref="Int32"/> value to write.</param>
  991. public virtual void WriteValue(int? value)
  992. {
  993. if (value == null)
  994. {
  995. WriteNull();
  996. }
  997. else
  998. {
  999. WriteValue(value.GetValueOrDefault());
  1000. }
  1001. }
  1002. /// <summary>
  1003. /// Writes a <see cref="Nullable{T}"/> of <see cref="UInt32"/> value.
  1004. /// </summary>
  1005. /// <param name="value">The <see cref="Nullable{T}"/> of <see cref="UInt32"/> value to write.</param>
  1006. public virtual void WriteValue(uint? value)
  1007. {
  1008. if (value == null)
  1009. {
  1010. WriteNull();
  1011. }
  1012. else
  1013. {
  1014. WriteValue(value.GetValueOrDefault());
  1015. }
  1016. }
  1017. /// <summary>
  1018. /// Writes a <see cref="Nullable{T}"/> of <see cref="Int64"/> value.
  1019. /// </summary>
  1020. /// <param name="value">The <see cref="Nullable{T}"/> of <see cref="Int64"/> value to write.</param>
  1021. public virtual void WriteValue(long? value)
  1022. {
  1023. if (value == null)
  1024. {
  1025. WriteNull();
  1026. }
  1027. else
  1028. {
  1029. WriteValue(value.GetValueOrDefault());
  1030. }
  1031. }
  1032. /// <summary>
  1033. /// Writes a <see cref="Nullable{T}"/> of <see cref="UInt64"/> value.
  1034. /// </summary>
  1035. /// <param name="value">The <see cref="Nullable{T}"/> of <see cref="UInt64"/> value to write.</param>
  1036. public virtual void WriteValue(ulong? value)
  1037. {
  1038. if (value == null)
  1039. {
  1040. WriteNull();
  1041. }
  1042. else
  1043. {
  1044. WriteValue(value.GetValueOrDefault());
  1045. }
  1046. }
  1047. /// <summary>
  1048. /// Writes a <see cref="Nullable{T}"/> of <see cref="Single"/> value.
  1049. /// </summary>
  1050. /// <param name="value">The <see cref="Nullable{T}"/> of <see cref="Single"/> value to write.</param>
  1051. public virtual void WriteValue(float? value)
  1052. {
  1053. if (value == null)
  1054. {
  1055. WriteNull();
  1056. }
  1057. else
  1058. {
  1059. WriteValue(value.GetValueOrDefault());
  1060. }
  1061. }
  1062. /// <summary>
  1063. /// Writes a <see cref="Nullable{T}"/> of <see cref="Double"/> value.
  1064. /// </summary>
  1065. /// <param name="value">The <see cref="Nullable{T}"/> of <see cref="Double"/> value to write.</param>
  1066. public virtual void WriteValue(double? value)
  1067. {
  1068. if (value == null)
  1069. {
  1070. WriteNull();
  1071. }
  1072. else
  1073. {
  1074. WriteValue(value.GetValueOrDefault());
  1075. }
  1076. }
  1077. /// <summary>
  1078. /// Writes a <see cref="Nullable{T}"/> of <see cref="Boolean"/> value.
  1079. /// </summary>
  1080. /// <param name="value">The <see cref="Nullable{T}"/> of <see cref="Boolean"/> value to write.</param>
  1081. public virtual void WriteValue(bool? value)
  1082. {
  1083. if (value == null)
  1084. {
  1085. WriteNull();
  1086. }
  1087. else
  1088. {
  1089. WriteValue(value.GetValueOrDefault());
  1090. }
  1091. }
  1092. /// <summary>
  1093. /// Writes a <see cref="Nullable{T}"/> of <see cref="Int16"/> value.
  1094. /// </summary>
  1095. /// <param name="value">The <see cref="Nullable{T}"/> of <see cref="Int16"/> value to write.</param>
  1096. public virtual void WriteValue(short? value)
  1097. {
  1098. if (value == null)
  1099. {
  1100. WriteNull();
  1101. }
  1102. else
  1103. {
  1104. WriteValue(value.GetValueOrDefault());
  1105. }
  1106. }
  1107. /// <summary>
  1108. /// Writes a <see cref="Nullable{T}"/> of <see cref="UInt16"/> value.
  1109. /// </summary>
  1110. /// <param name="value">The <see cref="Nullable{T}"/> of <see cref="UInt16"/> value to write.</param>
  1111. public virtual void WriteValue(ushort? value)
  1112. {
  1113. if (value == null)
  1114. {
  1115. WriteNull();
  1116. }
  1117. else
  1118. {
  1119. WriteValue(value.GetValueOrDefault());
  1120. }
  1121. }
  1122. /// <summary>
  1123. /// Writes a <see cref="Nullable{T}"/> of <see cref="Char"/> value.
  1124. /// </summary>
  1125. /// <param name="value">The <see cref="Nullable{T}"/> of <see cref="Char"/> value to write.</param>
  1126. public virtual void WriteValue(char? value)
  1127. {
  1128. if (value == null)
  1129. {
  1130. WriteNull();
  1131. }
  1132. else
  1133. {
  1134. WriteValue(value.GetValueOrDefault());
  1135. }
  1136. }
  1137. /// <summary>
  1138. /// Writes a <see cref="Nullable{T}"/> of <see cref="Byte"/> value.
  1139. /// </summary>
  1140. /// <param name="value">The <see cref="Nullable{T}"/> of <see cref="Byte"/> value to write.</param>
  1141. public virtual void WriteValue(byte? value)
  1142. {
  1143. if (value == null)
  1144. {
  1145. WriteNull();
  1146. }
  1147. else
  1148. {
  1149. WriteValue(value.GetValueOrDefault());
  1150. }
  1151. }
  1152. /// <summary>
  1153. /// Writes a <see cref="Nullable{T}"/> of <see cref="SByte"/> value.
  1154. /// </summary>
  1155. /// <param name="value">The <see cref="Nullable{T}"/> of <see cref="SByte"/> value to write.</param>
  1156. public virtual void WriteValue(sbyte? value)
  1157. {
  1158. if (value == null)
  1159. {
  1160. WriteNull();
  1161. }
  1162. else
  1163. {
  1164. WriteValue(value.GetValueOrDefault());
  1165. }
  1166. }
  1167. /// <summary>
  1168. /// Writes a <see cref="Nullable{T}"/> of <see cref="Decimal"/> value.
  1169. /// </summary>
  1170. /// <param name="value">The <see cref="Nullable{T}"/> of <see cref="Decimal"/> value to write.</param>
  1171. public virtual void WriteValue(decimal? value)
  1172. {
  1173. if (value == null)
  1174. {
  1175. WriteNull();
  1176. }
  1177. else
  1178. {
  1179. WriteValue(value.GetValueOrDefault());
  1180. }
  1181. }
  1182. /// <summary>
  1183. /// Writes a <see cref="Nullable{T}"/> of <see cref="DateTime"/> value.
  1184. /// </summary>
  1185. /// <param name="value">The <see cref="Nullable{T}"/> of <see cref="DateTime"/> value to write.</param>
  1186. public virtual void WriteValue(DateTime? value)
  1187. {
  1188. if (value == null)
  1189. {
  1190. WriteNull();
  1191. }
  1192. else
  1193. {
  1194. WriteValue(value.GetValueOrDefault());
  1195. }
  1196. }
  1197. #if !NET20
  1198. /// <summary>
  1199. /// Writes a <see cref="Nullable{T}"/> of <see cref="DateTimeOffset"/> value.
  1200. /// </summary>
  1201. /// <param name="value">The <see cref="Nullable{T}"/> of <see cref="DateTimeOffset"/> value to write.</param>
  1202. public virtual void WriteValue(DateTimeOffset? value)
  1203. {
  1204. if (value == null)
  1205. {
  1206. WriteNull();
  1207. }
  1208. else
  1209. {
  1210. WriteValue(value.GetValueOrDefault());
  1211. }
  1212. }
  1213. #endif
  1214. /// <summary>
  1215. /// Writes a <see cref="Nullable{T}"/> of <see cref="Guid"/> value.
  1216. /// </summary>
  1217. /// <param name="value">The <see cref="Nullable{T}"/> of <see cref="Guid"/> value to write.</param>
  1218. public virtual void WriteValue(Guid? value)
  1219. {
  1220. if (value == null)
  1221. {
  1222. WriteNull();
  1223. }
  1224. else
  1225. {
  1226. WriteValue(value.GetValueOrDefault());
  1227. }
  1228. }
  1229. /// <summary>
  1230. /// Writes a <see cref="Nullable{T}"/> of <see cref="TimeSpan"/> value.
  1231. /// </summary>
  1232. /// <param name="value">The <see cref="Nullable{T}"/> of <see cref="TimeSpan"/> value to write.</param>
  1233. public virtual void WriteValue(TimeSpan? value)
  1234. {
  1235. if (value == null)
  1236. {
  1237. WriteNull();
  1238. }
  1239. else
  1240. {
  1241. WriteValue(value.GetValueOrDefault());
  1242. }
  1243. }
  1244. /// <summary>
  1245. /// Writes a <see cref="Byte"/>[] value.
  1246. /// </summary>
  1247. /// <param name="value">The <see cref="Byte"/>[] value to write.</param>
  1248. public virtual void WriteValue(byte[] value)
  1249. {
  1250. if (value == null)
  1251. {
  1252. WriteNull();
  1253. }
  1254. else
  1255. {
  1256. InternalWriteValue(JsonToken.Bytes);
  1257. }
  1258. }
  1259. /// <summary>
  1260. /// Writes a <see cref="Uri"/> value.
  1261. /// </summary>
  1262. /// <param name="value">The <see cref="Uri"/> value to write.</param>
  1263. public virtual void WriteValue(Uri value)
  1264. {
  1265. if (value == null)
  1266. {
  1267. WriteNull();
  1268. }
  1269. else
  1270. {
  1271. InternalWriteValue(JsonToken.String);
  1272. }
  1273. }
  1274. /// <summary>
  1275. /// Writes a <see cref="Object"/> value.
  1276. /// An error will raised if the value cannot be written as a single JSON token.
  1277. /// </summary>
  1278. /// <param name="value">The <see cref="Object"/> value to write.</param>
  1279. public virtual void WriteValue(object value)
  1280. {
  1281. if (value == null)
  1282. {
  1283. WriteNull();
  1284. }
  1285. else
  1286. {
  1287. #if HAVE_BIG_INTEGER
  1288. // this is here because adding a WriteValue(BigInteger) to JsonWriter will
  1289. // mean the user has to add a reference to System.Numerics.dll
  1290. if (value is BigInteger)
  1291. {
  1292. throw CreateUnsupportedTypeException(this, value);
  1293. }
  1294. #endif
  1295. WriteValue(this, ConvertUtils.GetTypeCode(value.GetType()), value);
  1296. }
  1297. }
  1298. #endregion
  1299. /// <summary>
  1300. /// Writes a comment <c>/*...*/</c> containing the specified text.
  1301. /// </summary>
  1302. /// <param name="text">Text to place inside the comment.</param>
  1303. public virtual void WriteComment(string text)
  1304. {
  1305. InternalWriteComment();
  1306. }
  1307. /// <summary>
  1308. /// Writes the given white space.
  1309. /// </summary>
  1310. /// <param name="ws">The string of white space characters.</param>
  1311. public virtual void WriteWhitespace(string ws)
  1312. {
  1313. InternalWriteWhitespace(ws);
  1314. }
  1315. void IDisposable.Dispose()
  1316. {
  1317. Dispose(true);
  1318. GC.SuppressFinalize(this);
  1319. }
  1320. /// <summary>
  1321. /// Releases unmanaged and - optionally - managed resources.
  1322. /// </summary>
  1323. /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
  1324. protected virtual void Dispose(bool disposing)
  1325. {
  1326. if (_currentState != State.Closed && disposing)
  1327. {
  1328. Close();
  1329. }
  1330. }
  1331. internal static void WriteValue(JsonWriter writer, PrimitiveTypeCode typeCode, object value)
  1332. {
  1333. while (true)
  1334. {
  1335. switch (typeCode)
  1336. {
  1337. case PrimitiveTypeCode.Char:
  1338. writer.WriteValue((char)value);
  1339. return;
  1340. case PrimitiveTypeCode.CharNullable:
  1341. writer.WriteValue((value == null) ? (char?)null : (char)value);
  1342. return;
  1343. case PrimitiveTypeCode.Boolean:
  1344. writer.WriteValue((bool)value);
  1345. return;
  1346. case PrimitiveTypeCode.BooleanNullable:
  1347. writer.WriteValue((value == null) ? (bool?)null : (bool)value);
  1348. return;
  1349. case PrimitiveTypeCode.SByte:
  1350. writer.WriteValue((sbyte)value);
  1351. return;
  1352. case PrimitiveTypeCode.SByteNullable:
  1353. writer.WriteValue((value == null) ? (sbyte?)null : (sbyte)value);
  1354. return;
  1355. case PrimitiveTypeCode.Int16:
  1356. writer.WriteValue((short)value);
  1357. return;
  1358. case PrimitiveTypeCode.Int16Nullable:
  1359. writer.WriteValue((value == null) ? (short?)null : (short)value);
  1360. return;
  1361. case PrimitiveTypeCode.UInt16:
  1362. writer.WriteValue((ushort)value);
  1363. return;
  1364. case PrimitiveTypeCode.UInt16Nullable:
  1365. writer.WriteValue((value == null) ? (ushort?)null : (ushort)value);
  1366. return;
  1367. case PrimitiveTypeCode.Int32:
  1368. writer.WriteValue((int)value);
  1369. return;
  1370. case PrimitiveTypeCode.Int32Nullable:
  1371. writer.WriteValue((value == null) ? (int?)null : (int)value);
  1372. return;
  1373. case PrimitiveTypeCode.Byte:
  1374. writer.WriteValue((byte)value);
  1375. return;
  1376. case PrimitiveTypeCode.ByteNullable:
  1377. writer.WriteValue((value == null) ? (byte?)null : (byte)value);
  1378. return;
  1379. case PrimitiveTypeCode.UInt32:
  1380. writer.WriteValue((uint)value);
  1381. return;
  1382. case PrimitiveTypeCode.UInt32Nullable:
  1383. writer.WriteValue((value == null) ? (uint?)null : (uint)value);
  1384. return;
  1385. case PrimitiveTypeCode.Int64:
  1386. writer.WriteValue((long)value);
  1387. return;
  1388. case PrimitiveTypeCode.Int64Nullable:
  1389. writer.WriteValue((value == null) ? (long?)null : (long)value);
  1390. return;
  1391. case PrimitiveTypeCode.UInt64:
  1392. writer.WriteValue((ulong)value);
  1393. return;
  1394. case PrimitiveTypeCode.UInt64Nullable:
  1395. writer.WriteValue((value == null) ? (ulong?)null : (ulong)value);
  1396. return;
  1397. case PrimitiveTypeCode.Single:
  1398. writer.WriteValue((float)value);
  1399. return;
  1400. case PrimitiveTypeCode.SingleNullable:
  1401. writer.WriteValue((value == null) ? (float?)null : (float)value);
  1402. return;
  1403. case PrimitiveTypeCode.Double:
  1404. writer.WriteValue((double)value);
  1405. return;
  1406. case PrimitiveTypeCode.DoubleNullable:
  1407. writer.WriteValue((value == null) ? (double?)null : (double)value);
  1408. return;
  1409. case PrimitiveTypeCode.DateTime:
  1410. writer.WriteValue((DateTime)value);
  1411. return;
  1412. case PrimitiveTypeCode.DateTimeNullable:
  1413. writer.WriteValue((value == null) ? (DateTime?)null : (DateTime)value);
  1414. return;
  1415. #if !NET20
  1416. case PrimitiveTypeCode.DateTimeOffset:
  1417. writer.WriteValue((DateTimeOffset)value);
  1418. return;
  1419. case PrimitiveTypeCode.DateTimeOffsetNullable:
  1420. writer.WriteValue((value == null) ? (DateTimeOffset?)null : (DateTimeOffset)value);
  1421. return;
  1422. #endif
  1423. case PrimitiveTypeCode.Decimal:
  1424. writer.WriteValue((decimal)value);
  1425. return;
  1426. case PrimitiveTypeCode.DecimalNullable:
  1427. writer.WriteValue((value == null) ? (decimal?)null : (decimal)value);
  1428. return;
  1429. case PrimitiveTypeCode.Guid:
  1430. writer.WriteValue((Guid)value);
  1431. return;
  1432. case PrimitiveTypeCode.GuidNullable:
  1433. writer.WriteValue((value == null) ? (Guid?)null : (Guid)value);
  1434. return;
  1435. case PrimitiveTypeCode.TimeSpan:
  1436. writer.WriteValue((TimeSpan)value);
  1437. return;
  1438. case PrimitiveTypeCode.TimeSpanNullable:
  1439. writer.WriteValue((value == null) ? (TimeSpan?)null : (TimeSpan)value);
  1440. return;
  1441. #if HAVE_BIG_INTEGER
  1442. case PrimitiveTypeCode.BigInteger:
  1443. // this will call to WriteValue(object)
  1444. writer.WriteValue((BigInteger)value);
  1445. return;
  1446. case PrimitiveTypeCode.BigIntegerNullable:
  1447. // this will call to WriteValue(object)
  1448. writer.WriteValue((value == null) ? (BigInteger?)null : (BigInteger)value);
  1449. return;
  1450. #endif
  1451. case PrimitiveTypeCode.Uri:
  1452. writer.WriteValue((Uri)value);
  1453. return;
  1454. case PrimitiveTypeCode.String:
  1455. writer.WriteValue((string)value);
  1456. return;
  1457. case PrimitiveTypeCode.Bytes:
  1458. writer.WriteValue((byte[])value);
  1459. return;
  1460. case PrimitiveTypeCode.DBNull:
  1461. writer.WriteNull();
  1462. return;
  1463. default:
  1464. if (value is IConvertible convertible)
  1465. {
  1466. ResolveConvertibleValue(convertible, out typeCode, out value);
  1467. continue;
  1468. }
  1469. // write an unknown null value, fix https://github.com/JamesNK/Newtonsoft.Json/issues/1460
  1470. if (value == null)
  1471. {
  1472. writer.WriteNull();
  1473. return;
  1474. }
  1475. throw CreateUnsupportedTypeException(writer, value);
  1476. }
  1477. }
  1478. }
  1479. private static void ResolveConvertibleValue(IConvertible convertible, out PrimitiveTypeCode typeCode, out object value)
  1480. {
  1481. // the value is a non-standard IConvertible
  1482. // convert to the underlying value and retry
  1483. TypeInformation typeInformation = ConvertUtils.GetTypeInformation(convertible);
  1484. // if convertible has an underlying typecode of Object then attempt to convert it to a string
  1485. typeCode = typeInformation.TypeCode == PrimitiveTypeCode.Object ? PrimitiveTypeCode.String : typeInformation.TypeCode;
  1486. Type resolvedType = typeInformation.TypeCode == PrimitiveTypeCode.Object ? typeof(string) : typeInformation.Type;
  1487. value = convertible.ToType(resolvedType, CultureInfo.InvariantCulture);
  1488. }
  1489. private static JsonWriterException CreateUnsupportedTypeException(JsonWriter writer, object value)
  1490. {
  1491. return JsonWriterException.Create(writer, "Unsupported type: {0}. Use the JsonSerializer class to get the object's JSON representation.".FormatWith(CultureInfo.InvariantCulture, value.GetType()), null);
  1492. }
  1493. /// <summary>
  1494. /// Sets the state of the <see cref="JsonWriter"/>.
  1495. /// </summary>
  1496. /// <param name="token">The <see cref="JsonToken"/> being written.</param>
  1497. /// <param name="value">The value being written.</param>
  1498. protected void SetWriteState(JsonToken token, object value)
  1499. {
  1500. switch (token)
  1501. {
  1502. case JsonToken.StartObject:
  1503. InternalWriteStart(token, JsonContainerType.Object);
  1504. break;
  1505. case JsonToken.StartArray:
  1506. InternalWriteStart(token, JsonContainerType.Array);
  1507. break;
  1508. case JsonToken.StartConstructor:
  1509. InternalWriteStart(token, JsonContainerType.Constructor);
  1510. break;
  1511. case JsonToken.PropertyName:
  1512. if (!(value is string))
  1513. {
  1514. throw new ArgumentException("A name is required when setting property name state.", nameof(value));
  1515. }
  1516. InternalWritePropertyName((string)value);
  1517. break;
  1518. case JsonToken.Comment:
  1519. InternalWriteComment();
  1520. break;
  1521. case JsonToken.Raw:
  1522. InternalWriteRaw();
  1523. break;
  1524. case JsonToken.Integer:
  1525. case JsonToken.Float:
  1526. case JsonToken.String:
  1527. case JsonToken.Boolean:
  1528. case JsonToken.Date:
  1529. case JsonToken.Bytes:
  1530. case JsonToken.Null:
  1531. case JsonToken.Undefined:
  1532. InternalWriteValue(token);
  1533. break;
  1534. case JsonToken.EndObject:
  1535. InternalWriteEnd(JsonContainerType.Object);
  1536. break;
  1537. case JsonToken.EndArray:
  1538. InternalWriteEnd(JsonContainerType.Array);
  1539. break;
  1540. case JsonToken.EndConstructor:
  1541. InternalWriteEnd(JsonContainerType.Constructor);
  1542. break;
  1543. default:
  1544. throw new ArgumentOutOfRangeException(nameof(token));
  1545. }
  1546. }
  1547. internal void InternalWriteEnd(JsonContainerType container)
  1548. {
  1549. AutoCompleteClose(container);
  1550. }
  1551. internal void InternalWritePropertyName(string name)
  1552. {
  1553. _currentPosition.PropertyName = name;
  1554. AutoComplete(JsonToken.PropertyName);
  1555. }
  1556. internal void InternalWriteRaw()
  1557. {
  1558. }
  1559. internal void InternalWriteStart(JsonToken token, JsonContainerType container)
  1560. {
  1561. UpdateScopeWithFinishedValue();
  1562. AutoComplete(token);
  1563. Push(container);
  1564. }
  1565. internal void InternalWriteValue(JsonToken token)
  1566. {
  1567. UpdateScopeWithFinishedValue();
  1568. AutoComplete(token);
  1569. }
  1570. internal void InternalWriteWhitespace(string ws)
  1571. {
  1572. if (ws != null)
  1573. {
  1574. if (!StringUtils.IsWhiteSpace(ws))
  1575. {
  1576. throw JsonWriterException.Create(this, "Only white space characters should be used.", null);
  1577. }
  1578. }
  1579. }
  1580. internal void InternalWriteComment()
  1581. {
  1582. AutoComplete(JsonToken.Comment);
  1583. }
  1584. }
  1585. }