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.

1271 lines
42 KiB

  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. using System.Globalization;
  29. #if HAVE_BIG_INTEGER
  30. using System.Numerics;
  31. #endif
  32. using Newtonsoft.Json.Serialization;
  33. using Newtonsoft.Json.Utilities;
  34. namespace Newtonsoft.Json
  35. {
  36. /// <summary>
  37. /// Represents a reader that provides fast, non-cached, forward-only access to serialized JSON data.
  38. /// </summary>
  39. internal abstract partial class JsonReader : IDisposable
  40. {
  41. /// <summary>
  42. /// Specifies the state of the reader.
  43. /// </summary>
  44. protected internal enum State
  45. {
  46. /// <summary>
  47. /// A <see cref="JsonReader"/> read method has not been called.
  48. /// </summary>
  49. Start,
  50. /// <summary>
  51. /// The end of the file has been reached successfully.
  52. /// </summary>
  53. Complete,
  54. /// <summary>
  55. /// Reader is at a property.
  56. /// </summary>
  57. Property,
  58. /// <summary>
  59. /// Reader is at the start of an object.
  60. /// </summary>
  61. ObjectStart,
  62. /// <summary>
  63. /// Reader is in an object.
  64. /// </summary>
  65. Object,
  66. /// <summary>
  67. /// Reader is at the start of an array.
  68. /// </summary>
  69. ArrayStart,
  70. /// <summary>
  71. /// Reader is in an array.
  72. /// </summary>
  73. Array,
  74. /// <summary>
  75. /// The <see cref="JsonReader.Close()"/> method has been called.
  76. /// </summary>
  77. Closed,
  78. /// <summary>
  79. /// Reader has just read a value.
  80. /// </summary>
  81. PostValue,
  82. /// <summary>
  83. /// Reader is at the start of a constructor.
  84. /// </summary>
  85. ConstructorStart,
  86. /// <summary>
  87. /// Reader is in a constructor.
  88. /// </summary>
  89. Constructor,
  90. /// <summary>
  91. /// An error occurred that prevents the read operation from continuing.
  92. /// </summary>
  93. Error,
  94. /// <summary>
  95. /// The end of the file has been reached successfully.
  96. /// </summary>
  97. Finished
  98. }
  99. // current Token data
  100. private JsonToken _tokenType;
  101. private object _value;
  102. internal char _quoteChar;
  103. internal State _currentState;
  104. private JsonPosition _currentPosition;
  105. private CultureInfo _culture;
  106. private DateTimeZoneHandling _dateTimeZoneHandling;
  107. private int? _maxDepth;
  108. private bool _hasExceededMaxDepth;
  109. internal DateParseHandling _dateParseHandling;
  110. internal FloatParseHandling _floatParseHandling;
  111. private string _dateFormatString;
  112. private List<JsonPosition> _stack;
  113. /// <summary>
  114. /// Gets the current reader state.
  115. /// </summary>
  116. /// <value>The current reader state.</value>
  117. protected State CurrentState => _currentState;
  118. /// <summary>
  119. /// Gets or sets a value indicating whether the source should be closed when this reader is closed.
  120. /// </summary>
  121. /// <value>
  122. /// <c>true</c> to close the source when this reader is closed; otherwise <c>false</c>. The default is <c>true</c>.
  123. /// </value>
  124. public bool CloseInput { get; set; }
  125. /// <summary>
  126. /// Gets or sets a value indicating whether multiple pieces of JSON content can
  127. /// be read from a continuous stream without erroring.
  128. /// </summary>
  129. /// <value>
  130. /// <c>true</c> to support reading multiple pieces of JSON content; otherwise <c>false</c>.
  131. /// The default is <c>false</c>.
  132. /// </value>
  133. public bool SupportMultipleContent { get; set; }
  134. /// <summary>
  135. /// Gets the quotation mark character used to enclose the value of a string.
  136. /// </summary>
  137. public virtual char QuoteChar
  138. {
  139. get => _quoteChar;
  140. protected internal set => _quoteChar = value;
  141. }
  142. /// <summary>
  143. /// Gets or sets how <see cref="DateTime"/> time zones are handled when reading JSON.
  144. /// </summary>
  145. public DateTimeZoneHandling DateTimeZoneHandling
  146. {
  147. get => _dateTimeZoneHandling;
  148. set
  149. {
  150. if (value < DateTimeZoneHandling.Local || value > DateTimeZoneHandling.RoundtripKind)
  151. {
  152. throw new ArgumentOutOfRangeException(nameof(value));
  153. }
  154. _dateTimeZoneHandling = value;
  155. }
  156. }
  157. /// <summary>
  158. /// Gets or sets how date formatted strings, e.g. "\/Date(1198908717056)\/" and "2012-03-21T05:40Z", are parsed when reading JSON.
  159. /// </summary>
  160. public DateParseHandling DateParseHandling
  161. {
  162. get => _dateParseHandling;
  163. set
  164. {
  165. if (value < DateParseHandling.None ||
  166. #if !NET20
  167. value > DateParseHandling.DateTimeOffset
  168. #else
  169. value > DateParseHandling.DateTime
  170. #endif
  171. )
  172. {
  173. throw new ArgumentOutOfRangeException(nameof(value));
  174. }
  175. _dateParseHandling = value;
  176. }
  177. }
  178. /// <summary>
  179. /// Gets or sets how floating point numbers, e.g. 1.0 and 9.9, are parsed when reading JSON text.
  180. /// </summary>
  181. public FloatParseHandling FloatParseHandling
  182. {
  183. get => _floatParseHandling;
  184. set
  185. {
  186. if (value < FloatParseHandling.Double || value > FloatParseHandling.Decimal)
  187. {
  188. throw new ArgumentOutOfRangeException(nameof(value));
  189. }
  190. _floatParseHandling = value;
  191. }
  192. }
  193. /// <summary>
  194. /// Gets or sets how custom date formatted strings are parsed when reading JSON.
  195. /// </summary>
  196. public string DateFormatString
  197. {
  198. get => _dateFormatString;
  199. set => _dateFormatString = value;
  200. }
  201. /// <summary>
  202. /// Gets or sets the maximum depth allowed when reading JSON. Reading past this depth will throw a <see cref="JsonReaderException"/>.
  203. /// </summary>
  204. public int? MaxDepth
  205. {
  206. get => _maxDepth;
  207. set
  208. {
  209. if (value <= 0)
  210. {
  211. throw new ArgumentException("Value must be positive.", nameof(value));
  212. }
  213. _maxDepth = value;
  214. }
  215. }
  216. /// <summary>
  217. /// Gets the type of the current JSON token.
  218. /// </summary>
  219. public virtual JsonToken TokenType => _tokenType;
  220. /// <summary>
  221. /// Gets the text value of the current JSON token.
  222. /// </summary>
  223. public virtual object Value => _value;
  224. /// <summary>
  225. /// Gets the .NET type for the current JSON token.
  226. /// </summary>
  227. public virtual Type ValueType => _value?.GetType();
  228. /// <summary>
  229. /// Gets the depth of the current token in the JSON document.
  230. /// </summary>
  231. /// <value>The depth of the current token in the JSON document.</value>
  232. public virtual int Depth
  233. {
  234. get
  235. {
  236. int depth = _stack?.Count ?? 0;
  237. if (JsonTokenUtils.IsStartToken(TokenType) || _currentPosition.Type == JsonContainerType.None)
  238. {
  239. return depth;
  240. }
  241. else
  242. {
  243. return depth + 1;
  244. }
  245. }
  246. }
  247. /// <summary>
  248. /// Gets the path of the current JSON token.
  249. /// </summary>
  250. public virtual string Path
  251. {
  252. get
  253. {
  254. if (_currentPosition.Type == JsonContainerType.None)
  255. {
  256. return string.Empty;
  257. }
  258. bool insideContainer = (_currentState != State.ArrayStart
  259. && _currentState != State.ConstructorStart
  260. && _currentState != State.ObjectStart);
  261. JsonPosition? current = insideContainer ? (JsonPosition?)_currentPosition : null;
  262. return JsonPosition.BuildPath(_stack, current);
  263. }
  264. }
  265. /// <summary>
  266. /// Gets or sets the culture used when reading JSON. Defaults to <see cref="CultureInfo.InvariantCulture"/>.
  267. /// </summary>
  268. public CultureInfo Culture
  269. {
  270. get => _culture ?? CultureInfo.InvariantCulture;
  271. set => _culture = value;
  272. }
  273. internal JsonPosition GetPosition(int depth)
  274. {
  275. if (_stack != null && depth < _stack.Count)
  276. {
  277. return _stack[depth];
  278. }
  279. return _currentPosition;
  280. }
  281. /// <summary>
  282. /// Initializes a new instance of the <see cref="JsonReader"/> class.
  283. /// </summary>
  284. protected JsonReader()
  285. {
  286. _currentState = State.Start;
  287. _dateTimeZoneHandling = DateTimeZoneHandling.RoundtripKind;
  288. _dateParseHandling = DateParseHandling.DateTime;
  289. _floatParseHandling = FloatParseHandling.Double;
  290. CloseInput = true;
  291. }
  292. private void Push(JsonContainerType value)
  293. {
  294. UpdateScopeWithFinishedValue();
  295. if (_currentPosition.Type == JsonContainerType.None)
  296. {
  297. _currentPosition = new JsonPosition(value);
  298. }
  299. else
  300. {
  301. if (_stack == null)
  302. {
  303. _stack = new List<JsonPosition>();
  304. }
  305. _stack.Add(_currentPosition);
  306. _currentPosition = new JsonPosition(value);
  307. // this is a little hacky because Depth increases when first property/value is written but only testing here is faster/simpler
  308. if (_maxDepth != null && Depth + 1 > _maxDepth && !_hasExceededMaxDepth)
  309. {
  310. _hasExceededMaxDepth = true;
  311. throw JsonReaderException.Create(this, "The reader's MaxDepth of {0} has been exceeded.".FormatWith(CultureInfo.InvariantCulture, _maxDepth));
  312. }
  313. }
  314. }
  315. private JsonContainerType Pop()
  316. {
  317. JsonPosition oldPosition;
  318. if (_stack != null && _stack.Count > 0)
  319. {
  320. oldPosition = _currentPosition;
  321. _currentPosition = _stack[_stack.Count - 1];
  322. _stack.RemoveAt(_stack.Count - 1);
  323. }
  324. else
  325. {
  326. oldPosition = _currentPosition;
  327. _currentPosition = new JsonPosition();
  328. }
  329. if (_maxDepth != null && Depth <= _maxDepth)
  330. {
  331. _hasExceededMaxDepth = false;
  332. }
  333. return oldPosition.Type;
  334. }
  335. private JsonContainerType Peek()
  336. {
  337. return _currentPosition.Type;
  338. }
  339. /// <summary>
  340. /// Reads the next JSON token from the source.
  341. /// </summary>
  342. /// <returns><c>true</c> if the next token was read successfully; <c>false</c> if there are no more tokens to read.</returns>
  343. public abstract bool Read();
  344. /// <summary>
  345. /// Reads the next JSON token from the source as a <see cref="Nullable{T}"/> of <see cref="Int32"/>.
  346. /// </summary>
  347. /// <returns>A <see cref="Nullable{T}"/> of <see cref="Int32"/>. This method will return <c>null</c> at the end of an array.</returns>
  348. public virtual int? ReadAsInt32()
  349. {
  350. JsonToken t = GetContentToken();
  351. switch (t)
  352. {
  353. case JsonToken.None:
  354. case JsonToken.Null:
  355. case JsonToken.EndArray:
  356. return null;
  357. case JsonToken.Integer:
  358. case JsonToken.Float:
  359. object v = Value;
  360. if (v is int i)
  361. {
  362. return i;
  363. }
  364. #if HAVE_BIG_INTEGER
  365. if (v is BigInteger value)
  366. {
  367. i = (int)value;
  368. }
  369. else
  370. #endif
  371. {
  372. try
  373. {
  374. i = Convert.ToInt32(v, CultureInfo.InvariantCulture);
  375. }
  376. catch (Exception ex)
  377. {
  378. // handle error for large integer overflow exceptions
  379. throw JsonReaderException.Create(this, "Could not convert to integer: {0}.".FormatWith(CultureInfo.InvariantCulture, v), ex);
  380. }
  381. }
  382. SetToken(JsonToken.Integer, i, false);
  383. return i;
  384. case JsonToken.String:
  385. string s = (string)Value;
  386. return ReadInt32String(s);
  387. }
  388. throw JsonReaderException.Create(this, "Error reading integer. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, t));
  389. }
  390. internal int? ReadInt32String(string s)
  391. {
  392. if (string.IsNullOrEmpty(s))
  393. {
  394. SetToken(JsonToken.Null, null, false);
  395. return null;
  396. }
  397. if (int.TryParse(s, NumberStyles.Integer, Culture, out int i))
  398. {
  399. SetToken(JsonToken.Integer, i, false);
  400. return i;
  401. }
  402. else
  403. {
  404. SetToken(JsonToken.String, s, false);
  405. throw JsonReaderException.Create(this, "Could not convert string to integer: {0}.".FormatWith(CultureInfo.InvariantCulture, s));
  406. }
  407. }
  408. /// <summary>
  409. /// Reads the next JSON token from the source as a <see cref="String"/>.
  410. /// </summary>
  411. /// <returns>A <see cref="String"/>. This method will return <c>null</c> at the end of an array.</returns>
  412. public virtual string ReadAsString()
  413. {
  414. JsonToken t = GetContentToken();
  415. switch (t)
  416. {
  417. case JsonToken.None:
  418. case JsonToken.Null:
  419. case JsonToken.EndArray:
  420. return null;
  421. case JsonToken.String:
  422. return (string)Value;
  423. }
  424. if (JsonTokenUtils.IsPrimitiveToken(t))
  425. {
  426. object v = Value;
  427. if (v != null)
  428. {
  429. string s;
  430. if (v is IFormattable formattable)
  431. {
  432. s = formattable.ToString(null, Culture);
  433. }
  434. else
  435. {
  436. Uri uri = v as Uri;
  437. s = uri != null ? uri.OriginalString : v.ToString();
  438. }
  439. SetToken(JsonToken.String, s, false);
  440. return s;
  441. }
  442. }
  443. throw JsonReaderException.Create(this, "Error reading string. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, t));
  444. }
  445. /// <summary>
  446. /// Reads the next JSON token from the source as a <see cref="Byte"/>[].
  447. /// </summary>
  448. /// <returns>A <see cref="Byte"/>[] or <c>null</c> if the next JSON token is null. This method will return <c>null</c> at the end of an array.</returns>
  449. public virtual byte[] ReadAsBytes()
  450. {
  451. JsonToken t = GetContentToken();
  452. switch (t)
  453. {
  454. case JsonToken.StartObject:
  455. {
  456. ReadIntoWrappedTypeObject();
  457. byte[] data = ReadAsBytes();
  458. ReaderReadAndAssert();
  459. if (TokenType != JsonToken.EndObject)
  460. {
  461. throw JsonReaderException.Create(this, "Error reading bytes. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType));
  462. }
  463. SetToken(JsonToken.Bytes, data, false);
  464. return data;
  465. }
  466. case JsonToken.String:
  467. {
  468. // attempt to convert possible base 64 or GUID string to bytes
  469. // GUID has to have format 00000000-0000-0000-0000-000000000000
  470. string s = (string)Value;
  471. byte[] data;
  472. if (s.Length == 0)
  473. {
  474. data = CollectionUtils.ArrayEmpty<byte>();
  475. }
  476. else if (ConvertUtils.TryConvertGuid(s, out Guid g1))
  477. {
  478. data = g1.ToByteArray();
  479. }
  480. else
  481. {
  482. data = Convert.FromBase64String(s);
  483. }
  484. SetToken(JsonToken.Bytes, data, false);
  485. return data;
  486. }
  487. case JsonToken.None:
  488. case JsonToken.Null:
  489. case JsonToken.EndArray:
  490. return null;
  491. case JsonToken.Bytes:
  492. if (Value is Guid g2)
  493. {
  494. byte[] data = g2.ToByteArray();
  495. SetToken(JsonToken.Bytes, data, false);
  496. return data;
  497. }
  498. return (byte[])Value;
  499. case JsonToken.StartArray:
  500. return ReadArrayIntoByteArray();
  501. }
  502. throw JsonReaderException.Create(this, "Error reading bytes. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, t));
  503. }
  504. internal byte[] ReadArrayIntoByteArray()
  505. {
  506. List<byte> buffer = new List<byte>();
  507. while (true)
  508. {
  509. if (!Read())
  510. {
  511. SetToken(JsonToken.None);
  512. }
  513. if (ReadArrayElementIntoByteArrayReportDone(buffer))
  514. {
  515. byte[] d = buffer.ToArray();
  516. SetToken(JsonToken.Bytes, d, false);
  517. return d;
  518. }
  519. }
  520. }
  521. private bool ReadArrayElementIntoByteArrayReportDone(List<byte> buffer)
  522. {
  523. switch (TokenType)
  524. {
  525. case JsonToken.None:
  526. throw JsonReaderException.Create(this, "Unexpected end when reading bytes.");
  527. case JsonToken.Integer:
  528. buffer.Add(Convert.ToByte(Value, CultureInfo.InvariantCulture));
  529. return false;
  530. case JsonToken.EndArray:
  531. return true;
  532. case JsonToken.Comment:
  533. return false;
  534. default:
  535. throw JsonReaderException.Create(this, "Unexpected token when reading bytes: {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType));
  536. }
  537. }
  538. /// <summary>
  539. /// Reads the next JSON token from the source as a <see cref="Nullable{T}"/> of <see cref="Double"/>.
  540. /// </summary>
  541. /// <returns>A <see cref="Nullable{T}"/> of <see cref="Double"/>. This method will return <c>null</c> at the end of an array.</returns>
  542. public virtual double? ReadAsDouble()
  543. {
  544. JsonToken t = GetContentToken();
  545. switch (t)
  546. {
  547. case JsonToken.None:
  548. case JsonToken.Null:
  549. case JsonToken.EndArray:
  550. return null;
  551. case JsonToken.Integer:
  552. case JsonToken.Float:
  553. object v = Value;
  554. if (v is double d)
  555. {
  556. return d;
  557. }
  558. #if HAVE_BIG_INTEGER
  559. if (v is BigInteger value)
  560. {
  561. d = (double)value;
  562. }
  563. else
  564. #endif
  565. {
  566. d = Convert.ToDouble(v, CultureInfo.InvariantCulture);
  567. }
  568. SetToken(JsonToken.Float, d, false);
  569. return (double)d;
  570. case JsonToken.String:
  571. return ReadDoubleString((string)Value);
  572. }
  573. throw JsonReaderException.Create(this, "Error reading double. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, t));
  574. }
  575. internal double? ReadDoubleString(string s)
  576. {
  577. if (string.IsNullOrEmpty(s))
  578. {
  579. SetToken(JsonToken.Null, null, false);
  580. return null;
  581. }
  582. if (double.TryParse(s, NumberStyles.Float | NumberStyles.AllowThousands, Culture, out double d))
  583. {
  584. SetToken(JsonToken.Float, d, false);
  585. return d;
  586. }
  587. else
  588. {
  589. SetToken(JsonToken.String, s, false);
  590. throw JsonReaderException.Create(this, "Could not convert string to double: {0}.".FormatWith(CultureInfo.InvariantCulture, s));
  591. }
  592. }
  593. /// <summary>
  594. /// Reads the next JSON token from the source as a <see cref="Nullable{T}"/> of <see cref="Boolean"/>.
  595. /// </summary>
  596. /// <returns>A <see cref="Nullable{T}"/> of <see cref="Boolean"/>. This method will return <c>null</c> at the end of an array.</returns>
  597. public virtual bool? ReadAsBoolean()
  598. {
  599. JsonToken t = GetContentToken();
  600. switch (t)
  601. {
  602. case JsonToken.None:
  603. case JsonToken.Null:
  604. case JsonToken.EndArray:
  605. return null;
  606. case JsonToken.Integer:
  607. case JsonToken.Float:
  608. bool b;
  609. #if HAVE_BIG_INTEGER
  610. if (Value is BigInteger integer)
  611. {
  612. b = integer != 0;
  613. }
  614. else
  615. #endif
  616. {
  617. b = Convert.ToBoolean(Value, CultureInfo.InvariantCulture);
  618. }
  619. SetToken(JsonToken.Boolean, b, false);
  620. return b;
  621. case JsonToken.String:
  622. return ReadBooleanString((string)Value);
  623. case JsonToken.Boolean:
  624. return (bool)Value;
  625. }
  626. throw JsonReaderException.Create(this, "Error reading boolean. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, t));
  627. }
  628. internal bool? ReadBooleanString(string s)
  629. {
  630. if (string.IsNullOrEmpty(s))
  631. {
  632. SetToken(JsonToken.Null, null, false);
  633. return null;
  634. }
  635. if (bool.TryParse(s, out bool b))
  636. {
  637. SetToken(JsonToken.Boolean, b, false);
  638. return b;
  639. }
  640. else
  641. {
  642. SetToken(JsonToken.String, s, false);
  643. throw JsonReaderException.Create(this, "Could not convert string to boolean: {0}.".FormatWith(CultureInfo.InvariantCulture, s));
  644. }
  645. }
  646. /// <summary>
  647. /// Reads the next JSON token from the source as a <see cref="Nullable{T}"/> of <see cref="Decimal"/>.
  648. /// </summary>
  649. /// <returns>A <see cref="Nullable{T}"/> of <see cref="Decimal"/>. This method will return <c>null</c> at the end of an array.</returns>
  650. public virtual decimal? ReadAsDecimal()
  651. {
  652. JsonToken t = GetContentToken();
  653. switch (t)
  654. {
  655. case JsonToken.None:
  656. case JsonToken.Null:
  657. case JsonToken.EndArray:
  658. return null;
  659. case JsonToken.Integer:
  660. case JsonToken.Float:
  661. object v = Value;
  662. if (v is decimal d)
  663. {
  664. return d;
  665. }
  666. #if HAVE_BIG_INTEGER
  667. if (v is BigInteger value)
  668. {
  669. d = (decimal)value;
  670. }
  671. else
  672. #endif
  673. {
  674. try
  675. {
  676. d = Convert.ToDecimal(v, CultureInfo.InvariantCulture);
  677. }
  678. catch (Exception ex)
  679. {
  680. // handle error for large integer overflow exceptions
  681. throw JsonReaderException.Create(this, "Could not convert to decimal: {0}.".FormatWith(CultureInfo.InvariantCulture, v), ex);
  682. }
  683. }
  684. SetToken(JsonToken.Float, d, false);
  685. return d;
  686. case JsonToken.String:
  687. return ReadDecimalString((string)Value);
  688. }
  689. throw JsonReaderException.Create(this, "Error reading decimal. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, t));
  690. }
  691. internal decimal? ReadDecimalString(string s)
  692. {
  693. if (string.IsNullOrEmpty(s))
  694. {
  695. SetToken(JsonToken.Null, null, false);
  696. return null;
  697. }
  698. if (decimal.TryParse(s, NumberStyles.Number, Culture, out decimal d))
  699. {
  700. SetToken(JsonToken.Float, d, false);
  701. return d;
  702. }
  703. else
  704. {
  705. SetToken(JsonToken.String, s, false);
  706. throw JsonReaderException.Create(this, "Could not convert string to decimal: {0}.".FormatWith(CultureInfo.InvariantCulture, s));
  707. }
  708. }
  709. /// <summary>
  710. /// Reads the next JSON token from the source as a <see cref="Nullable{T}"/> of <see cref="DateTime"/>.
  711. /// </summary>
  712. /// <returns>A <see cref="Nullable{T}"/> of <see cref="DateTime"/>. This method will return <c>null</c> at the end of an array.</returns>
  713. public virtual DateTime? ReadAsDateTime()
  714. {
  715. switch (GetContentToken())
  716. {
  717. case JsonToken.None:
  718. case JsonToken.Null:
  719. case JsonToken.EndArray:
  720. return null;
  721. case JsonToken.Date:
  722. #if !NET20
  723. if (Value is DateTimeOffset offset)
  724. {
  725. SetToken(JsonToken.Date, offset.DateTime, false);
  726. }
  727. #endif
  728. return (DateTime)Value;
  729. case JsonToken.String:
  730. string s = (string)Value;
  731. return ReadDateTimeString(s);
  732. }
  733. throw JsonReaderException.Create(this, "Error reading date. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType));
  734. }
  735. internal DateTime? ReadDateTimeString(string s)
  736. {
  737. if (string.IsNullOrEmpty(s))
  738. {
  739. SetToken(JsonToken.Null, null, false);
  740. return null;
  741. }
  742. if (DateTimeUtils.TryParseDateTime(s, DateTimeZoneHandling, _dateFormatString, Culture, out DateTime dt))
  743. {
  744. dt = DateTimeUtils.EnsureDateTime(dt, DateTimeZoneHandling);
  745. SetToken(JsonToken.Date, dt, false);
  746. return dt;
  747. }
  748. if (DateTime.TryParse(s, Culture, DateTimeStyles.RoundtripKind, out dt))
  749. {
  750. dt = DateTimeUtils.EnsureDateTime(dt, DateTimeZoneHandling);
  751. SetToken(JsonToken.Date, dt, false);
  752. return dt;
  753. }
  754. throw JsonReaderException.Create(this, "Could not convert string to DateTime: {0}.".FormatWith(CultureInfo.InvariantCulture, s));
  755. }
  756. #if !NET20
  757. /// <summary>
  758. /// Reads the next JSON token from the source as a <see cref="Nullable{T}"/> of <see cref="DateTimeOffset"/>.
  759. /// </summary>
  760. /// <returns>A <see cref="Nullable{T}"/> of <see cref="DateTimeOffset"/>. This method will return <c>null</c> at the end of an array.</returns>
  761. public virtual DateTimeOffset? ReadAsDateTimeOffset()
  762. {
  763. JsonToken t = GetContentToken();
  764. switch (t)
  765. {
  766. case JsonToken.None:
  767. case JsonToken.Null:
  768. case JsonToken.EndArray:
  769. return null;
  770. case JsonToken.Date:
  771. if (Value is DateTime time)
  772. {
  773. SetToken(JsonToken.Date, new DateTimeOffset(time), false);
  774. }
  775. return (DateTimeOffset)Value;
  776. case JsonToken.String:
  777. string s = (string)Value;
  778. return ReadDateTimeOffsetString(s);
  779. default:
  780. throw JsonReaderException.Create(this, "Error reading date. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, t));
  781. }
  782. }
  783. internal DateTimeOffset? ReadDateTimeOffsetString(string s)
  784. {
  785. if (string.IsNullOrEmpty(s))
  786. {
  787. SetToken(JsonToken.Null, null, false);
  788. return null;
  789. }
  790. if (DateTimeUtils.TryParseDateTimeOffset(s, _dateFormatString, Culture, out DateTimeOffset dt))
  791. {
  792. SetToken(JsonToken.Date, dt, false);
  793. return dt;
  794. }
  795. if (DateTimeOffset.TryParse(s, Culture, DateTimeStyles.RoundtripKind, out dt))
  796. {
  797. SetToken(JsonToken.Date, dt, false);
  798. return dt;
  799. }
  800. SetToken(JsonToken.String, s, false);
  801. throw JsonReaderException.Create(this, "Could not convert string to DateTimeOffset: {0}.".FormatWith(CultureInfo.InvariantCulture, s));
  802. }
  803. #endif
  804. internal void ReaderReadAndAssert()
  805. {
  806. if (!Read())
  807. {
  808. throw CreateUnexpectedEndException();
  809. }
  810. }
  811. internal JsonReaderException CreateUnexpectedEndException()
  812. {
  813. return JsonReaderException.Create(this, "Unexpected end when reading JSON.");
  814. }
  815. internal void ReadIntoWrappedTypeObject()
  816. {
  817. ReaderReadAndAssert();
  818. if (Value != null && Value.ToString() == JsonTypeReflector.TypePropertyName)
  819. {
  820. ReaderReadAndAssert();
  821. if (Value != null && Value.ToString().StartsWith("System.Byte[]", StringComparison.Ordinal))
  822. {
  823. ReaderReadAndAssert();
  824. if (Value.ToString() == JsonTypeReflector.ValuePropertyName)
  825. {
  826. return;
  827. }
  828. }
  829. }
  830. throw JsonReaderException.Create(this, "Error reading bytes. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, JsonToken.StartObject));
  831. }
  832. /// <summary>
  833. /// Skips the children of the current token.
  834. /// </summary>
  835. public void Skip()
  836. {
  837. if (TokenType == JsonToken.PropertyName)
  838. {
  839. Read();
  840. }
  841. if (JsonTokenUtils.IsStartToken(TokenType))
  842. {
  843. int depth = Depth;
  844. while (Read() && (depth < Depth))
  845. {
  846. }
  847. }
  848. }
  849. /// <summary>
  850. /// Sets the current token.
  851. /// </summary>
  852. /// <param name="newToken">The new token.</param>
  853. protected void SetToken(JsonToken newToken)
  854. {
  855. SetToken(newToken, null, true);
  856. }
  857. /// <summary>
  858. /// Sets the current token and value.
  859. /// </summary>
  860. /// <param name="newToken">The new token.</param>
  861. /// <param name="value">The value.</param>
  862. protected void SetToken(JsonToken newToken, object value)
  863. {
  864. SetToken(newToken, value, true);
  865. }
  866. /// <summary>
  867. /// Sets the current token and value.
  868. /// </summary>
  869. /// <param name="newToken">The new token.</param>
  870. /// <param name="value">The value.</param>
  871. /// <param name="updateIndex">A flag indicating whether the position index inside an array should be updated.</param>
  872. protected void SetToken(JsonToken newToken, object value, bool updateIndex)
  873. {
  874. _tokenType = newToken;
  875. _value = value;
  876. switch (newToken)
  877. {
  878. case JsonToken.StartObject:
  879. _currentState = State.ObjectStart;
  880. Push(JsonContainerType.Object);
  881. break;
  882. case JsonToken.StartArray:
  883. _currentState = State.ArrayStart;
  884. Push(JsonContainerType.Array);
  885. break;
  886. case JsonToken.StartConstructor:
  887. _currentState = State.ConstructorStart;
  888. Push(JsonContainerType.Constructor);
  889. break;
  890. case JsonToken.EndObject:
  891. ValidateEnd(JsonToken.EndObject);
  892. break;
  893. case JsonToken.EndArray:
  894. ValidateEnd(JsonToken.EndArray);
  895. break;
  896. case JsonToken.EndConstructor:
  897. ValidateEnd(JsonToken.EndConstructor);
  898. break;
  899. case JsonToken.PropertyName:
  900. _currentState = State.Property;
  901. _currentPosition.PropertyName = (string)value;
  902. break;
  903. case JsonToken.Undefined:
  904. case JsonToken.Integer:
  905. case JsonToken.Float:
  906. case JsonToken.Boolean:
  907. case JsonToken.Null:
  908. case JsonToken.Date:
  909. case JsonToken.String:
  910. case JsonToken.Raw:
  911. case JsonToken.Bytes:
  912. SetPostValueState(updateIndex);
  913. break;
  914. }
  915. }
  916. internal void SetPostValueState(bool updateIndex)
  917. {
  918. if (Peek() != JsonContainerType.None || SupportMultipleContent)
  919. {
  920. _currentState = State.PostValue;
  921. }
  922. else
  923. {
  924. SetFinished();
  925. }
  926. if (updateIndex)
  927. {
  928. UpdateScopeWithFinishedValue();
  929. }
  930. }
  931. private void UpdateScopeWithFinishedValue()
  932. {
  933. if (_currentPosition.HasIndex)
  934. {
  935. _currentPosition.Position++;
  936. }
  937. }
  938. private void ValidateEnd(JsonToken endToken)
  939. {
  940. JsonContainerType currentObject = Pop();
  941. if (GetTypeForCloseToken(endToken) != currentObject)
  942. {
  943. throw JsonReaderException.Create(this, "JsonToken {0} is not valid for closing JsonType {1}.".FormatWith(CultureInfo.InvariantCulture, endToken, currentObject));
  944. }
  945. if (Peek() != JsonContainerType.None || SupportMultipleContent)
  946. {
  947. _currentState = State.PostValue;
  948. }
  949. else
  950. {
  951. SetFinished();
  952. }
  953. }
  954. /// <summary>
  955. /// Sets the state based on current token type.
  956. /// </summary>
  957. protected void SetStateBasedOnCurrent()
  958. {
  959. JsonContainerType currentObject = Peek();
  960. switch (currentObject)
  961. {
  962. case JsonContainerType.Object:
  963. _currentState = State.Object;
  964. break;
  965. case JsonContainerType.Array:
  966. _currentState = State.Array;
  967. break;
  968. case JsonContainerType.Constructor:
  969. _currentState = State.Constructor;
  970. break;
  971. case JsonContainerType.None:
  972. SetFinished();
  973. break;
  974. default:
  975. throw JsonReaderException.Create(this, "While setting the reader state back to current object an unexpected JsonType was encountered: {0}".FormatWith(CultureInfo.InvariantCulture, currentObject));
  976. }
  977. }
  978. private void SetFinished()
  979. {
  980. _currentState = SupportMultipleContent ? State.Start : State.Finished;
  981. }
  982. private JsonContainerType GetTypeForCloseToken(JsonToken token)
  983. {
  984. switch (token)
  985. {
  986. case JsonToken.EndObject:
  987. return JsonContainerType.Object;
  988. case JsonToken.EndArray:
  989. return JsonContainerType.Array;
  990. case JsonToken.EndConstructor:
  991. return JsonContainerType.Constructor;
  992. default:
  993. throw JsonReaderException.Create(this, "Not a valid close JsonToken: {0}".FormatWith(CultureInfo.InvariantCulture, token));
  994. }
  995. }
  996. void IDisposable.Dispose()
  997. {
  998. Dispose(true);
  999. GC.SuppressFinalize(this);
  1000. }
  1001. /// <summary>
  1002. /// Releases unmanaged and - optionally - managed resources.
  1003. /// </summary>
  1004. /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
  1005. protected virtual void Dispose(bool disposing)
  1006. {
  1007. if (_currentState != State.Closed && disposing)
  1008. {
  1009. Close();
  1010. }
  1011. }
  1012. /// <summary>
  1013. /// Changes the reader's state to <see cref="JsonReader.State.Closed"/>.
  1014. /// If <see cref="JsonReader.CloseInput"/> is set to <c>true</c>, the source is also closed.
  1015. /// </summary>
  1016. public virtual void Close()
  1017. {
  1018. _currentState = State.Closed;
  1019. _tokenType = JsonToken.None;
  1020. _value = null;
  1021. }
  1022. internal void ReadAndAssert()
  1023. {
  1024. if (!Read())
  1025. {
  1026. throw JsonSerializationException.Create(this, "Unexpected end when reading JSON.");
  1027. }
  1028. }
  1029. internal void ReadForTypeAndAssert(JsonContract contract, bool hasConverter)
  1030. {
  1031. if (!ReadForType(contract, hasConverter))
  1032. {
  1033. throw JsonSerializationException.Create(this, "Unexpected end when reading JSON.");
  1034. }
  1035. }
  1036. internal bool ReadForType(JsonContract contract, bool hasConverter)
  1037. {
  1038. // don't read properties with converters as a specific value
  1039. // the value might be a string which will then get converted which will error if read as date for example
  1040. if (hasConverter)
  1041. {
  1042. return Read();
  1043. }
  1044. ReadType t = contract?.InternalReadType ?? ReadType.Read;
  1045. switch (t)
  1046. {
  1047. case ReadType.Read:
  1048. return ReadAndMoveToContent();
  1049. case ReadType.ReadAsInt32:
  1050. ReadAsInt32();
  1051. break;
  1052. case ReadType.ReadAsInt64:
  1053. bool result = ReadAndMoveToContent();
  1054. if (TokenType == JsonToken.Undefined)
  1055. {
  1056. throw JsonReaderException.Create(this, "An undefined token is not a valid {0}.".FormatWith(CultureInfo.InvariantCulture, contract?.UnderlyingType ?? typeof(long)));
  1057. }
  1058. return result;
  1059. case ReadType.ReadAsDecimal:
  1060. ReadAsDecimal();
  1061. break;
  1062. case ReadType.ReadAsDouble:
  1063. ReadAsDouble();
  1064. break;
  1065. case ReadType.ReadAsBytes:
  1066. ReadAsBytes();
  1067. break;
  1068. case ReadType.ReadAsBoolean:
  1069. ReadAsBoolean();
  1070. break;
  1071. case ReadType.ReadAsString:
  1072. ReadAsString();
  1073. break;
  1074. case ReadType.ReadAsDateTime:
  1075. ReadAsDateTime();
  1076. break;
  1077. #if !NET20
  1078. case ReadType.ReadAsDateTimeOffset:
  1079. ReadAsDateTimeOffset();
  1080. break;
  1081. #endif
  1082. default:
  1083. throw new ArgumentOutOfRangeException();
  1084. }
  1085. return (TokenType != JsonToken.None);
  1086. }
  1087. internal bool ReadAndMoveToContent()
  1088. {
  1089. return Read() && MoveToContent();
  1090. }
  1091. internal bool MoveToContent()
  1092. {
  1093. JsonToken t = TokenType;
  1094. while (t == JsonToken.None || t == JsonToken.Comment)
  1095. {
  1096. if (!Read())
  1097. {
  1098. return false;
  1099. }
  1100. t = TokenType;
  1101. }
  1102. return true;
  1103. }
  1104. private JsonToken GetContentToken()
  1105. {
  1106. JsonToken t;
  1107. do
  1108. {
  1109. if (!Read())
  1110. {
  1111. SetToken(JsonToken.None);
  1112. return JsonToken.None;
  1113. }
  1114. else
  1115. {
  1116. t = TokenType;
  1117. }
  1118. } while (t == JsonToken.Comment);
  1119. return t;
  1120. }
  1121. }
  1122. }