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.

1768 lines
77 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. #if HAVE_ASYNC
  26. using System;
  27. using System.Globalization;
  28. using System.Threading;
  29. #if HAVE_BIG_INTEGER
  30. using System.Numerics;
  31. #endif
  32. using System.Threading.Tasks;
  33. using Newtonsoft.Json.Serialization;
  34. using Newtonsoft.Json.Utilities;
  35. namespace Newtonsoft.Json
  36. {
  37. internal partial class JsonTextReader
  38. {
  39. // It's not safe to perform the async methods here in a derived class as if the synchronous equivalent
  40. // has been overriden then the asychronous method will no longer be doing the same operation
  41. #if HAVE_ASYNC // Double-check this isn't included inappropriately.
  42. private readonly bool _safeAsync;
  43. #endif
  44. /// <summary>
  45. /// Asynchronously reads the next JSON token from the source.
  46. /// </summary>
  47. /// <param name="cancellationToken">The token to monitor for cancellation requests. The default value is <see cref="CancellationToken.None"/>.</param>
  48. /// <returns>A <see cref="Task{TResult}"/> that represents the asynchronous read. The <see cref="Task{TResult}.Result"/>
  49. /// property returns <c>true</c> if the next token was read successfully; <c>false</c> if there are no more tokens to read.</returns>
  50. /// <remarks>Derived classes must override this method to get asynchronous behaviour. Otherwise it will
  51. /// execute synchronously, returning an already-completed task.</remarks>
  52. public override Task<bool> ReadAsync(CancellationToken cancellationToken = default(CancellationToken))
  53. {
  54. return _safeAsync ? DoReadAsync(cancellationToken) : base.ReadAsync(cancellationToken);
  55. }
  56. internal Task<bool> DoReadAsync(CancellationToken cancellationToken)
  57. {
  58. EnsureBuffer();
  59. while (true)
  60. {
  61. switch (_currentState)
  62. {
  63. case State.Start:
  64. case State.Property:
  65. case State.Array:
  66. case State.ArrayStart:
  67. case State.Constructor:
  68. case State.ConstructorStart:
  69. return ParseValueAsync(cancellationToken);
  70. case State.Object:
  71. case State.ObjectStart:
  72. return ParseObjectAsync(cancellationToken);
  73. case State.PostValue:
  74. Task<bool> task = ParsePostValueAsync(false, cancellationToken);
  75. if (task.IsCompletedSucessfully())
  76. {
  77. if (task.Result)
  78. {
  79. return AsyncUtils.True;
  80. }
  81. }
  82. else
  83. {
  84. return DoReadAsync(task, cancellationToken);
  85. }
  86. break;
  87. case State.Finished:
  88. return ReadFromFinishedAsync(cancellationToken);
  89. default:
  90. throw JsonReaderException.Create(this, "Unexpected state: {0}.".FormatWith(CultureInfo.InvariantCulture, CurrentState));
  91. }
  92. }
  93. }
  94. private async Task<bool> DoReadAsync(Task<bool> task, CancellationToken cancellationToken)
  95. {
  96. bool result = await task.ConfigureAwait(false);
  97. if (result)
  98. {
  99. return true;
  100. }
  101. return await DoReadAsync(cancellationToken).ConfigureAwait(false);
  102. }
  103. private async Task<bool> ParsePostValueAsync(bool ignoreComments, CancellationToken cancellationToken)
  104. {
  105. while (true)
  106. {
  107. char currentChar = _chars[_charPos];
  108. switch (currentChar)
  109. {
  110. case '\0':
  111. if (_charsUsed == _charPos)
  112. {
  113. if (await ReadDataAsync(false, cancellationToken).ConfigureAwait(false) == 0)
  114. {
  115. _currentState = State.Finished;
  116. return false;
  117. }
  118. }
  119. else
  120. {
  121. _charPos++;
  122. }
  123. break;
  124. case '}':
  125. _charPos++;
  126. SetToken(JsonToken.EndObject);
  127. return true;
  128. case ']':
  129. _charPos++;
  130. SetToken(JsonToken.EndArray);
  131. return true;
  132. case ')':
  133. _charPos++;
  134. SetToken(JsonToken.EndConstructor);
  135. return true;
  136. case '/':
  137. await ParseCommentAsync(!ignoreComments, cancellationToken).ConfigureAwait(false);
  138. if (!ignoreComments)
  139. {
  140. return true;
  141. }
  142. break;
  143. case ',':
  144. _charPos++;
  145. // finished parsing
  146. SetStateBasedOnCurrent();
  147. return false;
  148. case ' ':
  149. case StringUtils.Tab:
  150. // eat
  151. _charPos++;
  152. break;
  153. case StringUtils.CarriageReturn:
  154. await ProcessCarriageReturnAsync(false, cancellationToken).ConfigureAwait(false);
  155. break;
  156. case StringUtils.LineFeed:
  157. ProcessLineFeed();
  158. break;
  159. default:
  160. if (char.IsWhiteSpace(currentChar))
  161. {
  162. // eat
  163. _charPos++;
  164. }
  165. else
  166. {
  167. // handle multiple content without comma delimiter
  168. if (SupportMultipleContent && Depth == 0)
  169. {
  170. SetStateBasedOnCurrent();
  171. return false;
  172. }
  173. throw JsonReaderException.Create(this, "After parsing a value an unexpected character was encountered: {0}.".FormatWith(CultureInfo.InvariantCulture, currentChar));
  174. }
  175. break;
  176. }
  177. }
  178. }
  179. private async Task<bool> ReadFromFinishedAsync(CancellationToken cancellationToken)
  180. {
  181. if (await EnsureCharsAsync(0, false, cancellationToken).ConfigureAwait(false))
  182. {
  183. await EatWhitespaceAsync(cancellationToken).ConfigureAwait(false);
  184. if (_isEndOfFile)
  185. {
  186. SetToken(JsonToken.None);
  187. return false;
  188. }
  189. if (_chars[_charPos] == '/')
  190. {
  191. await ParseCommentAsync(true, cancellationToken).ConfigureAwait(false);
  192. return true;
  193. }
  194. throw JsonReaderException.Create(this, "Additional text encountered after finished reading JSON content: {0}.".FormatWith(CultureInfo.InvariantCulture, _chars[_charPos]));
  195. }
  196. SetToken(JsonToken.None);
  197. return false;
  198. }
  199. private Task<int> ReadDataAsync(bool append, CancellationToken cancellationToken)
  200. {
  201. return ReadDataAsync(append, 0, cancellationToken);
  202. }
  203. private async Task<int> ReadDataAsync(bool append, int charsRequired, CancellationToken cancellationToken)
  204. {
  205. if (_isEndOfFile)
  206. {
  207. return 0;
  208. }
  209. PrepareBufferForReadData(append, charsRequired);
  210. int charsRead = await _reader.ReadAsync(_chars, _charsUsed, _chars.Length - _charsUsed - 1, cancellationToken).ConfigureAwait(false);
  211. _charsUsed += charsRead;
  212. if (charsRead == 0)
  213. {
  214. _isEndOfFile = true;
  215. }
  216. _chars[_charsUsed] = '\0';
  217. return charsRead;
  218. }
  219. private async Task<bool> ParseValueAsync(CancellationToken cancellationToken)
  220. {
  221. while (true)
  222. {
  223. char currentChar = _chars[_charPos];
  224. switch (currentChar)
  225. {
  226. case '\0':
  227. if (_charsUsed == _charPos)
  228. {
  229. if (await ReadDataAsync(false, cancellationToken).ConfigureAwait(false) == 0)
  230. {
  231. return false;
  232. }
  233. }
  234. else
  235. {
  236. _charPos++;
  237. }
  238. break;
  239. case '"':
  240. case '\'':
  241. await ParseStringAsync(currentChar, ReadType.Read, cancellationToken).ConfigureAwait(false);
  242. return true;
  243. case 't':
  244. await ParseTrueAsync(cancellationToken).ConfigureAwait(false);
  245. return true;
  246. case 'f':
  247. await ParseFalseAsync(cancellationToken).ConfigureAwait(false);
  248. return true;
  249. case 'n':
  250. if (await EnsureCharsAsync(1, true, cancellationToken).ConfigureAwait(false))
  251. {
  252. switch (_chars[_charPos + 1])
  253. {
  254. case 'u':
  255. await ParseNullAsync(cancellationToken).ConfigureAwait(false);
  256. break;
  257. case 'e':
  258. await ParseConstructorAsync(cancellationToken).ConfigureAwait(false);
  259. break;
  260. default:
  261. throw CreateUnexpectedCharacterException(_chars[_charPos]);
  262. }
  263. }
  264. else
  265. {
  266. _charPos++;
  267. throw CreateUnexpectedEndException();
  268. }
  269. return true;
  270. case 'N':
  271. await ParseNumberNaNAsync(ReadType.Read, cancellationToken).ConfigureAwait(false);
  272. return true;
  273. case 'I':
  274. await ParseNumberPositiveInfinityAsync(ReadType.Read, cancellationToken).ConfigureAwait(false);
  275. return true;
  276. case '-':
  277. if (await EnsureCharsAsync(1, true, cancellationToken).ConfigureAwait(false) && _chars[_charPos + 1] == 'I')
  278. {
  279. await ParseNumberNegativeInfinityAsync(ReadType.Read, cancellationToken).ConfigureAwait(false);
  280. }
  281. else
  282. {
  283. await ParseNumberAsync(ReadType.Read, cancellationToken).ConfigureAwait(false);
  284. }
  285. return true;
  286. case '/':
  287. await ParseCommentAsync(true, cancellationToken).ConfigureAwait(false);
  288. return true;
  289. case 'u':
  290. await ParseUndefinedAsync(cancellationToken).ConfigureAwait(false);
  291. return true;
  292. case '{':
  293. _charPos++;
  294. SetToken(JsonToken.StartObject);
  295. return true;
  296. case '[':
  297. _charPos++;
  298. SetToken(JsonToken.StartArray);
  299. return true;
  300. case ']':
  301. _charPos++;
  302. SetToken(JsonToken.EndArray);
  303. return true;
  304. case ',':
  305. // don't increment position, the next call to read will handle comma
  306. // this is done to handle multiple empty comma values
  307. SetToken(JsonToken.Undefined);
  308. return true;
  309. case ')':
  310. _charPos++;
  311. SetToken(JsonToken.EndConstructor);
  312. return true;
  313. case StringUtils.CarriageReturn:
  314. await ProcessCarriageReturnAsync(false, cancellationToken).ConfigureAwait(false);
  315. break;
  316. case StringUtils.LineFeed:
  317. ProcessLineFeed();
  318. break;
  319. case ' ':
  320. case StringUtils.Tab:
  321. // eat
  322. _charPos++;
  323. break;
  324. default:
  325. if (char.IsWhiteSpace(currentChar))
  326. {
  327. // eat
  328. _charPos++;
  329. break;
  330. }
  331. if (char.IsNumber(currentChar) || currentChar == '-' || currentChar == '.')
  332. {
  333. await ParseNumberAsync(ReadType.Read, cancellationToken).ConfigureAwait(false);
  334. return true;
  335. }
  336. throw CreateUnexpectedCharacterException(currentChar);
  337. }
  338. }
  339. }
  340. private async Task ReadStringIntoBufferAsync(char quote, CancellationToken cancellationToken)
  341. {
  342. int charPos = _charPos;
  343. int initialPosition = _charPos;
  344. int lastWritePosition = _charPos;
  345. _stringBuffer.Position = 0;
  346. while (true)
  347. {
  348. switch (_chars[charPos++])
  349. {
  350. case '\0':
  351. if (_charsUsed == charPos - 1)
  352. {
  353. charPos--;
  354. if (await ReadDataAsync(true, cancellationToken).ConfigureAwait(false) == 0)
  355. {
  356. _charPos = charPos;
  357. throw JsonReaderException.Create(this, "Unterminated string. Expected delimiter: {0}.".FormatWith(CultureInfo.InvariantCulture, quote));
  358. }
  359. }
  360. break;
  361. case '\\':
  362. _charPos = charPos;
  363. if (!await EnsureCharsAsync(0, true, cancellationToken).ConfigureAwait(false))
  364. {
  365. throw JsonReaderException.Create(this, "Unterminated string. Expected delimiter: {0}.".FormatWith(CultureInfo.InvariantCulture, quote));
  366. }
  367. // start of escape sequence
  368. int escapeStartPos = charPos - 1;
  369. char currentChar = _chars[charPos];
  370. charPos++;
  371. char writeChar;
  372. switch (currentChar)
  373. {
  374. case 'b':
  375. writeChar = '\b';
  376. break;
  377. case 't':
  378. writeChar = '\t';
  379. break;
  380. case 'n':
  381. writeChar = '\n';
  382. break;
  383. case 'f':
  384. writeChar = '\f';
  385. break;
  386. case 'r':
  387. writeChar = '\r';
  388. break;
  389. case '\\':
  390. writeChar = '\\';
  391. break;
  392. case '"':
  393. case '\'':
  394. case '/':
  395. writeChar = currentChar;
  396. break;
  397. case 'u':
  398. _charPos = charPos;
  399. writeChar = await ParseUnicodeAsync(cancellationToken).ConfigureAwait(false);
  400. if (StringUtils.IsLowSurrogate(writeChar))
  401. {
  402. // low surrogate with no preceding high surrogate; this char is replaced
  403. writeChar = UnicodeReplacementChar;
  404. }
  405. else if (StringUtils.IsHighSurrogate(writeChar))
  406. {
  407. bool anotherHighSurrogate;
  408. // loop for handling situations where there are multiple consecutive high surrogates
  409. do
  410. {
  411. anotherHighSurrogate = false;
  412. // potential start of a surrogate pair
  413. if (await EnsureCharsAsync(2, true, cancellationToken).ConfigureAwait(false) && _chars[_charPos] == '\\' && _chars[_charPos + 1] == 'u')
  414. {
  415. char highSurrogate = writeChar;
  416. _charPos += 2;
  417. writeChar = await ParseUnicodeAsync(cancellationToken).ConfigureAwait(false);
  418. if (StringUtils.IsLowSurrogate(writeChar))
  419. {
  420. // a valid surrogate pair!
  421. }
  422. else if (StringUtils.IsHighSurrogate(writeChar))
  423. {
  424. // another high surrogate; replace current and start check over
  425. highSurrogate = UnicodeReplacementChar;
  426. anotherHighSurrogate = true;
  427. }
  428. else
  429. {
  430. // high surrogate not followed by low surrogate; original char is replaced
  431. highSurrogate = UnicodeReplacementChar;
  432. }
  433. EnsureBufferNotEmpty();
  434. WriteCharToBuffer(highSurrogate, lastWritePosition, escapeStartPos);
  435. lastWritePosition = _charPos;
  436. }
  437. else
  438. {
  439. // there are not enough remaining chars for the low surrogate or is not follow by unicode sequence
  440. // replace high surrogate and continue on as usual
  441. writeChar = UnicodeReplacementChar;
  442. }
  443. } while (anotherHighSurrogate);
  444. }
  445. charPos = _charPos;
  446. break;
  447. default:
  448. _charPos = charPos;
  449. throw JsonReaderException.Create(this, "Bad JSON escape sequence: {0}.".FormatWith(CultureInfo.InvariantCulture, @"\" + currentChar));
  450. }
  451. EnsureBufferNotEmpty();
  452. WriteCharToBuffer(writeChar, lastWritePosition, escapeStartPos);
  453. lastWritePosition = charPos;
  454. break;
  455. case StringUtils.CarriageReturn:
  456. _charPos = charPos - 1;
  457. await ProcessCarriageReturnAsync(true, cancellationToken).ConfigureAwait(false);
  458. charPos = _charPos;
  459. break;
  460. case StringUtils.LineFeed:
  461. _charPos = charPos - 1;
  462. ProcessLineFeed();
  463. charPos = _charPos;
  464. break;
  465. case '"':
  466. case '\'':
  467. if (_chars[charPos - 1] == quote)
  468. {
  469. FinishReadStringIntoBuffer(charPos - 1, initialPosition, lastWritePosition);
  470. return;
  471. }
  472. break;
  473. }
  474. }
  475. }
  476. private Task ProcessCarriageReturnAsync(bool append, CancellationToken cancellationToken)
  477. {
  478. _charPos++;
  479. Task<bool> task = EnsureCharsAsync(1, append, cancellationToken);
  480. if (task.IsCompletedSucessfully())
  481. {
  482. SetNewLine(task.Result);
  483. return AsyncUtils.CompletedTask;
  484. }
  485. return ProcessCarriageReturnAsync(task);
  486. }
  487. private async Task ProcessCarriageReturnAsync(Task<bool> task)
  488. {
  489. SetNewLine(await task.ConfigureAwait(false));
  490. }
  491. private async Task<char> ParseUnicodeAsync(CancellationToken cancellationToken)
  492. {
  493. return ConvertUnicode(await EnsureCharsAsync(4, true, cancellationToken).ConfigureAwait(false));
  494. }
  495. private Task<bool> EnsureCharsAsync(int relativePosition, bool append, CancellationToken cancellationToken)
  496. {
  497. if (_charPos + relativePosition < _charsUsed)
  498. {
  499. return AsyncUtils.True;
  500. }
  501. if (_isEndOfFile)
  502. {
  503. return AsyncUtils.False;
  504. }
  505. return ReadCharsAsync(relativePosition, append, cancellationToken);
  506. }
  507. private async Task<bool> ReadCharsAsync(int relativePosition, bool append, CancellationToken cancellationToken)
  508. {
  509. int charsRequired = _charPos + relativePosition - _charsUsed + 1;
  510. // it is possible that the TextReader doesn't return all data at once
  511. // repeat read until the required text is returned or the reader is out of content
  512. do
  513. {
  514. int charsRead = await ReadDataAsync(append, charsRequired, cancellationToken).ConfigureAwait(false);
  515. // no more content
  516. if (charsRead == 0)
  517. {
  518. return false;
  519. }
  520. charsRequired -= charsRead;
  521. } while (charsRequired > 0);
  522. return true;
  523. }
  524. private async Task<bool> ParseObjectAsync(CancellationToken cancellationToken)
  525. {
  526. while (true)
  527. {
  528. char currentChar = _chars[_charPos];
  529. switch (currentChar)
  530. {
  531. case '\0':
  532. if (_charsUsed == _charPos)
  533. {
  534. if (await ReadDataAsync(false, cancellationToken).ConfigureAwait(false) == 0)
  535. {
  536. return false;
  537. }
  538. }
  539. else
  540. {
  541. _charPos++;
  542. }
  543. break;
  544. case '}':
  545. SetToken(JsonToken.EndObject);
  546. _charPos++;
  547. return true;
  548. case '/':
  549. await ParseCommentAsync(true, cancellationToken).ConfigureAwait(false);
  550. return true;
  551. case StringUtils.CarriageReturn:
  552. await ProcessCarriageReturnAsync(false, cancellationToken).ConfigureAwait(false);
  553. break;
  554. case StringUtils.LineFeed:
  555. ProcessLineFeed();
  556. break;
  557. case ' ':
  558. case StringUtils.Tab:
  559. // eat
  560. _charPos++;
  561. break;
  562. default:
  563. if (char.IsWhiteSpace(currentChar))
  564. {
  565. // eat
  566. _charPos++;
  567. }
  568. else
  569. {
  570. return await ParsePropertyAsync(cancellationToken).ConfigureAwait(false);
  571. }
  572. break;
  573. }
  574. }
  575. }
  576. private async Task ParseCommentAsync(bool setToken, CancellationToken cancellationToken)
  577. {
  578. // should have already parsed / character before reaching this method
  579. _charPos++;
  580. if (!await EnsureCharsAsync(1, false, cancellationToken).ConfigureAwait(false))
  581. {
  582. throw JsonReaderException.Create(this, "Unexpected end while parsing comment.");
  583. }
  584. bool singlelineComment;
  585. if (_chars[_charPos] == '*')
  586. {
  587. singlelineComment = false;
  588. }
  589. else if (_chars[_charPos] == '/')
  590. {
  591. singlelineComment = true;
  592. }
  593. else
  594. {
  595. throw JsonReaderException.Create(this, "Error parsing comment. Expected: *, got {0}.".FormatWith(CultureInfo.InvariantCulture, _chars[_charPos]));
  596. }
  597. _charPos++;
  598. int initialPosition = _charPos;
  599. while (true)
  600. {
  601. switch (_chars[_charPos])
  602. {
  603. case '\0':
  604. if (_charsUsed == _charPos)
  605. {
  606. if (await ReadDataAsync(true, cancellationToken).ConfigureAwait(false) == 0)
  607. {
  608. if (!singlelineComment)
  609. {
  610. throw JsonReaderException.Create(this, "Unexpected end while parsing comment.");
  611. }
  612. EndComment(setToken, initialPosition, _charPos);
  613. return;
  614. }
  615. }
  616. else
  617. {
  618. _charPos++;
  619. }
  620. break;
  621. case '*':
  622. _charPos++;
  623. if (!singlelineComment)
  624. {
  625. if (await EnsureCharsAsync(0, true, cancellationToken).ConfigureAwait(false))
  626. {
  627. if (_chars[_charPos] == '/')
  628. {
  629. EndComment(setToken, initialPosition, _charPos - 1);
  630. _charPos++;
  631. return;
  632. }
  633. }
  634. }
  635. break;
  636. case StringUtils.CarriageReturn:
  637. if (singlelineComment)
  638. {
  639. EndComment(setToken, initialPosition, _charPos);
  640. return;
  641. }
  642. await ProcessCarriageReturnAsync(true, cancellationToken).ConfigureAwait(false);
  643. break;
  644. case StringUtils.LineFeed:
  645. if (singlelineComment)
  646. {
  647. EndComment(setToken, initialPosition, _charPos);
  648. return;
  649. }
  650. ProcessLineFeed();
  651. break;
  652. default:
  653. _charPos++;
  654. break;
  655. }
  656. }
  657. }
  658. private async Task EatWhitespaceAsync(CancellationToken cancellationToken)
  659. {
  660. while (true)
  661. {
  662. char currentChar = _chars[_charPos];
  663. switch (currentChar)
  664. {
  665. case '\0':
  666. if (_charsUsed == _charPos)
  667. {
  668. if (await ReadDataAsync(false, cancellationToken).ConfigureAwait(false) == 0)
  669. {
  670. return;
  671. }
  672. }
  673. else
  674. {
  675. _charPos++;
  676. }
  677. break;
  678. case StringUtils.CarriageReturn:
  679. await ProcessCarriageReturnAsync(false, cancellationToken).ConfigureAwait(false);
  680. break;
  681. case StringUtils.LineFeed:
  682. ProcessLineFeed();
  683. break;
  684. default:
  685. if (currentChar == ' ' || char.IsWhiteSpace(currentChar))
  686. {
  687. _charPos++;
  688. }
  689. else
  690. {
  691. return;
  692. }
  693. break;
  694. }
  695. }
  696. }
  697. private async Task ParseStringAsync(char quote, ReadType readType, CancellationToken cancellationToken)
  698. {
  699. cancellationToken.ThrowIfCancellationRequested();
  700. _charPos++;
  701. ShiftBufferIfNeeded();
  702. await ReadStringIntoBufferAsync(quote, cancellationToken).ConfigureAwait(false);
  703. ParseReadString(quote, readType);
  704. }
  705. private async Task<bool> MatchValueAsync(string value, CancellationToken cancellationToken)
  706. {
  707. return MatchValue(await EnsureCharsAsync(value.Length - 1, true, cancellationToken).ConfigureAwait(false), value);
  708. }
  709. private async Task<bool> MatchValueWithTrailingSeparatorAsync(string value, CancellationToken cancellationToken)
  710. {
  711. // will match value and then move to the next character, checking that it is a separator character
  712. if (!await MatchValueAsync(value, cancellationToken).ConfigureAwait(false))
  713. {
  714. return false;
  715. }
  716. if (!await EnsureCharsAsync(0, false, cancellationToken).ConfigureAwait(false))
  717. {
  718. return true;
  719. }
  720. return IsSeparator(_chars[_charPos]) || _chars[_charPos] == '\0';
  721. }
  722. private async Task MatchAndSetAsync(string value, JsonToken newToken, object tokenValue, CancellationToken cancellationToken)
  723. {
  724. if (await MatchValueWithTrailingSeparatorAsync(value, cancellationToken).ConfigureAwait(false))
  725. {
  726. SetToken(newToken, tokenValue);
  727. }
  728. else
  729. {
  730. throw JsonReaderException.Create(this, "Error parsing " + newToken.ToString().ToLowerInvariant() + " value.");
  731. }
  732. }
  733. private Task ParseTrueAsync(CancellationToken cancellationToken)
  734. {
  735. return MatchAndSetAsync(JsonConvert.True, JsonToken.Boolean, true, cancellationToken);
  736. }
  737. private Task ParseFalseAsync(CancellationToken cancellationToken)
  738. {
  739. return MatchAndSetAsync(JsonConvert.False, JsonToken.Boolean, false, cancellationToken);
  740. }
  741. private Task ParseNullAsync(CancellationToken cancellationToken)
  742. {
  743. return MatchAndSetAsync(JsonConvert.Null, JsonToken.Null, null, cancellationToken);
  744. }
  745. private async Task ParseConstructorAsync(CancellationToken cancellationToken)
  746. {
  747. if (await MatchValueWithTrailingSeparatorAsync("new", cancellationToken).ConfigureAwait(false))
  748. {
  749. await EatWhitespaceAsync(cancellationToken).ConfigureAwait(false);
  750. int initialPosition = _charPos;
  751. int endPosition;
  752. while (true)
  753. {
  754. char currentChar = _chars[_charPos];
  755. if (currentChar == '\0')
  756. {
  757. if (_charsUsed == _charPos)
  758. {
  759. if (await ReadDataAsync(true, cancellationToken).ConfigureAwait(false) == 0)
  760. {
  761. throw JsonReaderException.Create(this, "Unexpected end while parsing constructor.");
  762. }
  763. }
  764. else
  765. {
  766. endPosition = _charPos;
  767. _charPos++;
  768. break;
  769. }
  770. }
  771. else if (char.IsLetterOrDigit(currentChar))
  772. {
  773. _charPos++;
  774. }
  775. else if (currentChar == StringUtils.CarriageReturn)
  776. {
  777. endPosition = _charPos;
  778. await ProcessCarriageReturnAsync(true, cancellationToken).ConfigureAwait(false);
  779. break;
  780. }
  781. else if (currentChar == StringUtils.LineFeed)
  782. {
  783. endPosition = _charPos;
  784. ProcessLineFeed();
  785. break;
  786. }
  787. else if (char.IsWhiteSpace(currentChar))
  788. {
  789. endPosition = _charPos;
  790. _charPos++;
  791. break;
  792. }
  793. else if (currentChar == '(')
  794. {
  795. endPosition = _charPos;
  796. break;
  797. }
  798. else
  799. {
  800. throw JsonReaderException.Create(this, "Unexpected character while parsing constructor: {0}.".FormatWith(CultureInfo.InvariantCulture, currentChar));
  801. }
  802. }
  803. _stringReference = new StringReference(_chars, initialPosition, endPosition - initialPosition);
  804. string constructorName = _stringReference.ToString();
  805. await EatWhitespaceAsync(cancellationToken).ConfigureAwait(false);
  806. if (_chars[_charPos] != '(')
  807. {
  808. throw JsonReaderException.Create(this, "Unexpected character while parsing constructor: {0}.".FormatWith(CultureInfo.InvariantCulture, _chars[_charPos]));
  809. }
  810. _charPos++;
  811. ClearRecentString();
  812. SetToken(JsonToken.StartConstructor, constructorName);
  813. }
  814. else
  815. {
  816. throw JsonReaderException.Create(this, "Unexpected content while parsing JSON.");
  817. }
  818. }
  819. private async Task<object> ParseNumberNaNAsync(ReadType readType, CancellationToken cancellationToken)
  820. {
  821. return ParseNumberNaN(readType, await MatchValueWithTrailingSeparatorAsync(JsonConvert.NaN, cancellationToken).ConfigureAwait(false));
  822. }
  823. private async Task<object> ParseNumberPositiveInfinityAsync(ReadType readType, CancellationToken cancellationToken)
  824. {
  825. return ParseNumberPositiveInfinity(readType, await MatchValueWithTrailingSeparatorAsync(JsonConvert.PositiveInfinity, cancellationToken).ConfigureAwait(false));
  826. }
  827. private async Task<object> ParseNumberNegativeInfinityAsync(ReadType readType, CancellationToken cancellationToken)
  828. {
  829. return ParseNumberNegativeInfinity(readType, await MatchValueWithTrailingSeparatorAsync(JsonConvert.NegativeInfinity, cancellationToken).ConfigureAwait(false));
  830. }
  831. private async Task ParseNumberAsync(ReadType readType, CancellationToken cancellationToken)
  832. {
  833. ShiftBufferIfNeeded();
  834. char firstChar = _chars[_charPos];
  835. int initialPosition = _charPos;
  836. await ReadNumberIntoBufferAsync(cancellationToken).ConfigureAwait(false);
  837. ParseReadNumber(readType, firstChar, initialPosition);
  838. }
  839. private Task ParseUndefinedAsync(CancellationToken cancellationToken)
  840. {
  841. return MatchAndSetAsync(JsonConvert.Undefined, JsonToken.Undefined, null, cancellationToken);
  842. }
  843. private async Task<bool> ParsePropertyAsync(CancellationToken cancellationToken)
  844. {
  845. char firstChar = _chars[_charPos];
  846. char quoteChar;
  847. if (firstChar == '"' || firstChar == '\'')
  848. {
  849. _charPos++;
  850. quoteChar = firstChar;
  851. ShiftBufferIfNeeded();
  852. await ReadStringIntoBufferAsync(quoteChar, cancellationToken).ConfigureAwait(false);
  853. }
  854. else if (ValidIdentifierChar(firstChar))
  855. {
  856. quoteChar = '\0';
  857. ShiftBufferIfNeeded();
  858. await ParseUnquotedPropertyAsync(cancellationToken).ConfigureAwait(false);
  859. }
  860. else
  861. {
  862. throw JsonReaderException.Create(this, "Invalid property identifier character: {0}.".FormatWith(CultureInfo.InvariantCulture, _chars[_charPos]));
  863. }
  864. string propertyName;
  865. if (NameTable != null)
  866. {
  867. propertyName = NameTable.Get(_stringReference.Chars, _stringReference.StartIndex, _stringReference.Length)
  868. // no match in name table
  869. ?? _stringReference.ToString();
  870. }
  871. else
  872. {
  873. propertyName = _stringReference.ToString();
  874. }
  875. await EatWhitespaceAsync(cancellationToken).ConfigureAwait(false);
  876. if (_chars[_charPos] != ':')
  877. {
  878. throw JsonReaderException.Create(this, "Invalid character after parsing property name. Expected ':' but got: {0}.".FormatWith(CultureInfo.InvariantCulture, _chars[_charPos]));
  879. }
  880. _charPos++;
  881. SetToken(JsonToken.PropertyName, propertyName);
  882. _quoteChar = quoteChar;
  883. ClearRecentString();
  884. return true;
  885. }
  886. private async Task ReadNumberIntoBufferAsync(CancellationToken cancellationToken)
  887. {
  888. int charPos = _charPos;
  889. while (true)
  890. {
  891. char currentChar = _chars[charPos];
  892. if (currentChar == '\0')
  893. {
  894. _charPos = charPos;
  895. if (_charsUsed == charPos)
  896. {
  897. if (await ReadDataAsync(true, cancellationToken).ConfigureAwait(false) == 0)
  898. {
  899. return;
  900. }
  901. }
  902. else
  903. {
  904. return;
  905. }
  906. }
  907. else if (ReadNumberCharIntoBuffer(currentChar, charPos))
  908. {
  909. return;
  910. }
  911. else
  912. {
  913. charPos++;
  914. }
  915. }
  916. }
  917. private async Task ParseUnquotedPropertyAsync(CancellationToken cancellationToken)
  918. {
  919. int initialPosition = _charPos;
  920. // parse unquoted property name until whitespace or colon
  921. while (true)
  922. {
  923. char currentChar = _chars[_charPos];
  924. if (currentChar == '\0')
  925. {
  926. if (_charsUsed == _charPos)
  927. {
  928. if (await ReadDataAsync(true, cancellationToken).ConfigureAwait(false) == 0)
  929. {
  930. throw JsonReaderException.Create(this, "Unexpected end while parsing unquoted property name.");
  931. }
  932. continue;
  933. }
  934. _stringReference = new StringReference(_chars, initialPosition, _charPos - initialPosition);
  935. return;
  936. }
  937. if (ReadUnquotedPropertyReportIfDone(currentChar, initialPosition))
  938. {
  939. return;
  940. }
  941. }
  942. }
  943. private async Task<bool> ReadNullCharAsync(CancellationToken cancellationToken)
  944. {
  945. if (_charsUsed == _charPos)
  946. {
  947. if (await ReadDataAsync(false, cancellationToken).ConfigureAwait(false) == 0)
  948. {
  949. _isEndOfFile = true;
  950. return true;
  951. }
  952. }
  953. else
  954. {
  955. _charPos++;
  956. }
  957. return false;
  958. }
  959. private async Task HandleNullAsync(CancellationToken cancellationToken)
  960. {
  961. if (await EnsureCharsAsync(1, true, cancellationToken).ConfigureAwait(false))
  962. {
  963. if (_chars[_charPos + 1] == 'u')
  964. {
  965. await ParseNullAsync(cancellationToken).ConfigureAwait(false);
  966. return;
  967. }
  968. _charPos += 2;
  969. throw CreateUnexpectedCharacterException(_chars[_charPos - 1]);
  970. }
  971. _charPos = _charsUsed;
  972. throw CreateUnexpectedEndException();
  973. }
  974. private async Task ReadFinishedAsync(CancellationToken cancellationToken)
  975. {
  976. if (await EnsureCharsAsync(0, false, cancellationToken).ConfigureAwait(false))
  977. {
  978. await EatWhitespaceAsync(cancellationToken).ConfigureAwait(false);
  979. if (_isEndOfFile)
  980. {
  981. SetToken(JsonToken.None);
  982. return;
  983. }
  984. if (_chars[_charPos] == '/')
  985. {
  986. await ParseCommentAsync(false, cancellationToken).ConfigureAwait(false);
  987. }
  988. else
  989. {
  990. throw JsonReaderException.Create(this, "Additional text encountered after finished reading JSON content: {0}.".FormatWith(CultureInfo.InvariantCulture, _chars[_charPos]));
  991. }
  992. }
  993. SetToken(JsonToken.None);
  994. }
  995. private async Task<object> ReadStringValueAsync(ReadType readType, CancellationToken cancellationToken)
  996. {
  997. EnsureBuffer();
  998. switch (_currentState)
  999. {
  1000. case State.PostValue:
  1001. if (await ParsePostValueAsync(true, cancellationToken).ConfigureAwait(false))
  1002. {
  1003. return null;
  1004. }
  1005. goto case State.Start;
  1006. case State.Start:
  1007. case State.Property:
  1008. case State.Array:
  1009. case State.ArrayStart:
  1010. case State.Constructor:
  1011. case State.ConstructorStart:
  1012. while (true)
  1013. {
  1014. char currentChar = _chars[_charPos];
  1015. switch (currentChar)
  1016. {
  1017. case '\0':
  1018. if (await ReadNullCharAsync(cancellationToken).ConfigureAwait(false))
  1019. {
  1020. SetToken(JsonToken.None, null, false);
  1021. return null;
  1022. }
  1023. break;
  1024. case '"':
  1025. case '\'':
  1026. await ParseStringAsync(currentChar, readType, cancellationToken).ConfigureAwait(false);
  1027. return FinishReadQuotedStringValue(readType);
  1028. case '-':
  1029. if (await EnsureCharsAsync(1, true, cancellationToken).ConfigureAwait(false) && _chars[_charPos + 1] == 'I')
  1030. {
  1031. return ParseNumberNegativeInfinity(readType);
  1032. }
  1033. else
  1034. {
  1035. await ParseNumberAsync(readType, cancellationToken).ConfigureAwait(false);
  1036. return Value;
  1037. }
  1038. case '.':
  1039. case '0':
  1040. case '1':
  1041. case '2':
  1042. case '3':
  1043. case '4':
  1044. case '5':
  1045. case '6':
  1046. case '7':
  1047. case '8':
  1048. case '9':
  1049. if (readType != ReadType.ReadAsString)
  1050. {
  1051. _charPos++;
  1052. throw CreateUnexpectedCharacterException(currentChar);
  1053. }
  1054. await ParseNumberAsync(ReadType.ReadAsString, cancellationToken).ConfigureAwait(false);
  1055. return Value;
  1056. case 't':
  1057. case 'f':
  1058. if (readType != ReadType.ReadAsString)
  1059. {
  1060. _charPos++;
  1061. throw CreateUnexpectedCharacterException(currentChar);
  1062. }
  1063. string expected = currentChar == 't' ? JsonConvert.True : JsonConvert.False;
  1064. if (!await MatchValueWithTrailingSeparatorAsync(expected, cancellationToken).ConfigureAwait(false))
  1065. {
  1066. throw CreateUnexpectedCharacterException(_chars[_charPos]);
  1067. }
  1068. SetToken(JsonToken.String, expected);
  1069. return expected;
  1070. case 'I':
  1071. return await ParseNumberPositiveInfinityAsync(readType, cancellationToken).ConfigureAwait(false);
  1072. case 'N':
  1073. return await ParseNumberNaNAsync(readType, cancellationToken).ConfigureAwait(false);
  1074. case 'n':
  1075. await HandleNullAsync(cancellationToken).ConfigureAwait(false);
  1076. return null;
  1077. case '/':
  1078. await ParseCommentAsync(false, cancellationToken).ConfigureAwait(false);
  1079. break;
  1080. case ',':
  1081. ProcessValueComma();
  1082. break;
  1083. case ']':
  1084. _charPos++;
  1085. if (_currentState == State.Array || _currentState == State.ArrayStart || _currentState == State.PostValue)
  1086. {
  1087. SetToken(JsonToken.EndArray);
  1088. return null;
  1089. }
  1090. throw CreateUnexpectedCharacterException(currentChar);
  1091. case StringUtils.CarriageReturn:
  1092. await ProcessCarriageReturnAsync(false, cancellationToken).ConfigureAwait(false);
  1093. break;
  1094. case StringUtils.LineFeed:
  1095. ProcessLineFeed();
  1096. break;
  1097. case ' ':
  1098. case StringUtils.Tab:
  1099. // eat
  1100. _charPos++;
  1101. break;
  1102. default:
  1103. _charPos++;
  1104. if (!char.IsWhiteSpace(currentChar))
  1105. {
  1106. throw CreateUnexpectedCharacterException(currentChar);
  1107. }
  1108. // eat
  1109. break;
  1110. }
  1111. }
  1112. case State.Finished:
  1113. await ReadFinishedAsync(cancellationToken).ConfigureAwait(false);
  1114. return null;
  1115. default:
  1116. throw JsonReaderException.Create(this, "Unexpected state: {0}.".FormatWith(CultureInfo.InvariantCulture, CurrentState));
  1117. }
  1118. }
  1119. private async Task<object> ReadNumberValueAsync(ReadType readType, CancellationToken cancellationToken)
  1120. {
  1121. EnsureBuffer();
  1122. switch (_currentState)
  1123. {
  1124. case State.PostValue:
  1125. if (await ParsePostValueAsync(true, cancellationToken).ConfigureAwait(false))
  1126. {
  1127. return null;
  1128. }
  1129. goto case State.Start;
  1130. case State.Start:
  1131. case State.Property:
  1132. case State.Array:
  1133. case State.ArrayStart:
  1134. case State.Constructor:
  1135. case State.ConstructorStart:
  1136. while (true)
  1137. {
  1138. char currentChar = _chars[_charPos];
  1139. switch (currentChar)
  1140. {
  1141. case '\0':
  1142. if (await ReadNullCharAsync(cancellationToken).ConfigureAwait(false))
  1143. {
  1144. SetToken(JsonToken.None, null, false);
  1145. return null;
  1146. }
  1147. break;
  1148. case '"':
  1149. case '\'':
  1150. await ParseStringAsync(currentChar, readType, cancellationToken).ConfigureAwait(false);
  1151. return FinishReadQuotedNumber(readType);
  1152. case 'n':
  1153. await HandleNullAsync(cancellationToken).ConfigureAwait(false);
  1154. return null;
  1155. case 'N':
  1156. return await ParseNumberNaNAsync(readType, cancellationToken).ConfigureAwait(false);
  1157. case 'I':
  1158. return await ParseNumberPositiveInfinityAsync(readType, cancellationToken).ConfigureAwait(false);
  1159. case '-':
  1160. if (await EnsureCharsAsync(1, true, cancellationToken).ConfigureAwait(false) && _chars[_charPos + 1] == 'I')
  1161. {
  1162. return await ParseNumberNegativeInfinityAsync(readType, cancellationToken).ConfigureAwait(false);
  1163. }
  1164. else
  1165. {
  1166. await ParseNumberAsync(readType, cancellationToken).ConfigureAwait(false);
  1167. return Value;
  1168. }
  1169. case '.':
  1170. case '0':
  1171. case '1':
  1172. case '2':
  1173. case '3':
  1174. case '4':
  1175. case '5':
  1176. case '6':
  1177. case '7':
  1178. case '8':
  1179. case '9':
  1180. await ParseNumberAsync(readType, cancellationToken).ConfigureAwait(false);
  1181. return Value;
  1182. case '/':
  1183. await ParseCommentAsync(false, cancellationToken).ConfigureAwait(false);
  1184. break;
  1185. case ',':
  1186. ProcessValueComma();
  1187. break;
  1188. case ']':
  1189. _charPos++;
  1190. if (_currentState == State.Array || _currentState == State.ArrayStart || _currentState == State.PostValue)
  1191. {
  1192. SetToken(JsonToken.EndArray);
  1193. return null;
  1194. }
  1195. throw CreateUnexpectedCharacterException(currentChar);
  1196. case StringUtils.CarriageReturn:
  1197. await ProcessCarriageReturnAsync(false, cancellationToken).ConfigureAwait(false);
  1198. break;
  1199. case StringUtils.LineFeed:
  1200. ProcessLineFeed();
  1201. break;
  1202. case ' ':
  1203. case StringUtils.Tab:
  1204. // eat
  1205. _charPos++;
  1206. break;
  1207. default:
  1208. _charPos++;
  1209. if (!char.IsWhiteSpace(currentChar))
  1210. {
  1211. throw CreateUnexpectedCharacterException(currentChar);
  1212. }
  1213. // eat
  1214. break;
  1215. }
  1216. }
  1217. case State.Finished:
  1218. await ReadFinishedAsync(cancellationToken).ConfigureAwait(false);
  1219. return null;
  1220. default:
  1221. throw JsonReaderException.Create(this, "Unexpected state: {0}.".FormatWith(CultureInfo.InvariantCulture, CurrentState));
  1222. }
  1223. }
  1224. /// <summary>
  1225. /// Asynchronously reads the next JSON token from the source as a <see cref="Nullable{T}"/> of <see cref="bool"/>.
  1226. /// </summary>
  1227. /// <param name="cancellationToken">The token to monitor for cancellation requests. The default value is <see cref="CancellationToken.None"/>.</param>
  1228. /// <returns>A <see cref="Task{TResult}"/> that represents the asynchronous read. The <see cref="Task{TResult}.Result"/>
  1229. /// property returns the <see cref="Nullable{T}"/> of <see cref="bool"/>. This result will be <c>null</c> at the end of an array.</returns>
  1230. /// <remarks>Derived classes must override this method to get asynchronous behaviour. Otherwise it will
  1231. /// execute synchronously, returning an already-completed task.</remarks>
  1232. public override Task<bool?> ReadAsBooleanAsync(CancellationToken cancellationToken = default(CancellationToken))
  1233. {
  1234. return _safeAsync ? DoReadAsBooleanAsync(cancellationToken) : base.ReadAsBooleanAsync(cancellationToken);
  1235. }
  1236. internal async Task<bool?> DoReadAsBooleanAsync(CancellationToken cancellationToken)
  1237. {
  1238. EnsureBuffer();
  1239. switch (_currentState)
  1240. {
  1241. case State.PostValue:
  1242. if (await ParsePostValueAsync(true, cancellationToken).ConfigureAwait(false))
  1243. {
  1244. return null;
  1245. }
  1246. goto case State.Start;
  1247. case State.Start:
  1248. case State.Property:
  1249. case State.Array:
  1250. case State.ArrayStart:
  1251. case State.Constructor:
  1252. case State.ConstructorStart:
  1253. while (true)
  1254. {
  1255. char currentChar = _chars[_charPos];
  1256. switch (currentChar)
  1257. {
  1258. case '\0':
  1259. if (await ReadNullCharAsync(cancellationToken).ConfigureAwait(false))
  1260. {
  1261. SetToken(JsonToken.None, null, false);
  1262. return null;
  1263. }
  1264. break;
  1265. case '"':
  1266. case '\'':
  1267. await ParseStringAsync(currentChar, ReadType.Read, cancellationToken).ConfigureAwait(false);
  1268. return ReadBooleanString(_stringReference.ToString());
  1269. case 'n':
  1270. await HandleNullAsync(cancellationToken).ConfigureAwait(false);
  1271. return null;
  1272. case '-':
  1273. case '.':
  1274. case '0':
  1275. case '1':
  1276. case '2':
  1277. case '3':
  1278. case '4':
  1279. case '5':
  1280. case '6':
  1281. case '7':
  1282. case '8':
  1283. case '9':
  1284. await ParseNumberAsync(ReadType.Read, cancellationToken).ConfigureAwait(false);
  1285. bool b;
  1286. #if HAVE_BIG_INTEGER
  1287. if (Value is BigInteger)
  1288. {
  1289. b = (BigInteger)Value != 0;
  1290. }
  1291. else
  1292. #endif
  1293. {
  1294. b = Convert.ToBoolean(Value, CultureInfo.InvariantCulture);
  1295. }
  1296. SetToken(JsonToken.Boolean, b, false);
  1297. return b;
  1298. case 't':
  1299. case 'f':
  1300. bool isTrue = currentChar == 't';
  1301. if (!await MatchValueWithTrailingSeparatorAsync(isTrue ? JsonConvert.True : JsonConvert.False, cancellationToken).ConfigureAwait(false))
  1302. {
  1303. throw CreateUnexpectedCharacterException(_chars[_charPos]);
  1304. }
  1305. SetToken(JsonToken.Boolean, isTrue);
  1306. return isTrue;
  1307. case '/':
  1308. await ParseCommentAsync(false, cancellationToken).ConfigureAwait(false);
  1309. break;
  1310. case ',':
  1311. ProcessValueComma();
  1312. break;
  1313. case ']':
  1314. _charPos++;
  1315. if (_currentState == State.Array || _currentState == State.ArrayStart || _currentState == State.PostValue)
  1316. {
  1317. SetToken(JsonToken.EndArray);
  1318. return null;
  1319. }
  1320. throw CreateUnexpectedCharacterException(currentChar);
  1321. case StringUtils.CarriageReturn:
  1322. await ProcessCarriageReturnAsync(false, cancellationToken).ConfigureAwait(false);
  1323. break;
  1324. case StringUtils.LineFeed:
  1325. ProcessLineFeed();
  1326. break;
  1327. case ' ':
  1328. case StringUtils.Tab:
  1329. // eat
  1330. _charPos++;
  1331. break;
  1332. default:
  1333. _charPos++;
  1334. if (!char.IsWhiteSpace(currentChar))
  1335. {
  1336. throw CreateUnexpectedCharacterException(currentChar);
  1337. }
  1338. // eat
  1339. break;
  1340. }
  1341. }
  1342. case State.Finished:
  1343. await ReadFinishedAsync(cancellationToken).ConfigureAwait(false);
  1344. return null;
  1345. default:
  1346. throw JsonReaderException.Create(this, "Unexpected state: {0}.".FormatWith(CultureInfo.InvariantCulture, CurrentState));
  1347. }
  1348. }
  1349. /// <summary>
  1350. /// Asynchronously reads the next JSON token from the source as a <see cref="byte"/>[].
  1351. /// </summary>
  1352. /// <param name="cancellationToken">The token to monitor for cancellation requests. The default value is <see cref="CancellationToken.None"/>.</param>
  1353. /// <returns>A <see cref="Task{TResult}"/> that represents the asynchronous read. The <see cref="Task{TResult}.Result"/>
  1354. /// property returns the <see cref="byte"/>[]. This result will be <c>null</c> at the end of an array.</returns>
  1355. /// <remarks>Derived classes must override this method to get asynchronous behaviour. Otherwise it will
  1356. /// execute synchronously, returning an already-completed task.</remarks>
  1357. public override Task<byte[]> ReadAsBytesAsync(CancellationToken cancellationToken = default(CancellationToken))
  1358. {
  1359. return _safeAsync ? DoReadAsBytesAsync(cancellationToken) : base.ReadAsBytesAsync(cancellationToken);
  1360. }
  1361. internal async Task<byte[]> DoReadAsBytesAsync(CancellationToken cancellationToken)
  1362. {
  1363. EnsureBuffer();
  1364. bool isWrapped = false;
  1365. switch (_currentState)
  1366. {
  1367. case State.PostValue:
  1368. if (await ParsePostValueAsync(true, cancellationToken).ConfigureAwait(false))
  1369. {
  1370. return null;
  1371. }
  1372. goto case State.Start;
  1373. case State.Start:
  1374. case State.Property:
  1375. case State.Array:
  1376. case State.ArrayStart:
  1377. case State.Constructor:
  1378. case State.ConstructorStart:
  1379. while (true)
  1380. {
  1381. char currentChar = _chars[_charPos];
  1382. switch (currentChar)
  1383. {
  1384. case '\0':
  1385. if (await ReadNullCharAsync(cancellationToken).ConfigureAwait(false))
  1386. {
  1387. SetToken(JsonToken.None, null, false);
  1388. return null;
  1389. }
  1390. break;
  1391. case '"':
  1392. case '\'':
  1393. await ParseStringAsync(currentChar, ReadType.ReadAsBytes, cancellationToken).ConfigureAwait(false);
  1394. byte[] data = (byte[])Value;
  1395. if (isWrapped)
  1396. {
  1397. await ReaderReadAndAssertAsync(cancellationToken).ConfigureAwait(false);
  1398. if (TokenType != JsonToken.EndObject)
  1399. {
  1400. throw JsonReaderException.Create(this, "Error reading bytes. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType));
  1401. }
  1402. SetToken(JsonToken.Bytes, data, false);
  1403. }
  1404. return data;
  1405. case '{':
  1406. _charPos++;
  1407. SetToken(JsonToken.StartObject);
  1408. await ReadIntoWrappedTypeObjectAsync(cancellationToken).ConfigureAwait(false);
  1409. isWrapped = true;
  1410. break;
  1411. case '[':
  1412. _charPos++;
  1413. SetToken(JsonToken.StartArray);
  1414. return await ReadArrayIntoByteArrayAsync(cancellationToken).ConfigureAwait(false);
  1415. case 'n':
  1416. await HandleNullAsync(cancellationToken).ConfigureAwait(false);
  1417. return null;
  1418. case '/':
  1419. await ParseCommentAsync(false, cancellationToken).ConfigureAwait(false);
  1420. break;
  1421. case ',':
  1422. ProcessValueComma();
  1423. break;
  1424. case ']':
  1425. _charPos++;
  1426. if (_currentState == State.Array || _currentState == State.ArrayStart || _currentState == State.PostValue)
  1427. {
  1428. SetToken(JsonToken.EndArray);
  1429. return null;
  1430. }
  1431. throw CreateUnexpectedCharacterException(currentChar);
  1432. case StringUtils.CarriageReturn:
  1433. await ProcessCarriageReturnAsync(false, cancellationToken).ConfigureAwait(false);
  1434. break;
  1435. case StringUtils.LineFeed:
  1436. ProcessLineFeed();
  1437. break;
  1438. case ' ':
  1439. case StringUtils.Tab:
  1440. // eat
  1441. _charPos++;
  1442. break;
  1443. default:
  1444. _charPos++;
  1445. if (!char.IsWhiteSpace(currentChar))
  1446. {
  1447. throw CreateUnexpectedCharacterException(currentChar);
  1448. }
  1449. // eat
  1450. break;
  1451. }
  1452. }
  1453. case State.Finished:
  1454. await ReadFinishedAsync(cancellationToken).ConfigureAwait(false);
  1455. return null;
  1456. default:
  1457. throw JsonReaderException.Create(this, "Unexpected state: {0}.".FormatWith(CultureInfo.InvariantCulture, CurrentState));
  1458. }
  1459. }
  1460. private async Task ReadIntoWrappedTypeObjectAsync(CancellationToken cancellationToken)
  1461. {
  1462. await ReaderReadAndAssertAsync(cancellationToken).ConfigureAwait(false);
  1463. if (Value != null && Value.ToString() == JsonTypeReflector.TypePropertyName)
  1464. {
  1465. await ReaderReadAndAssertAsync(cancellationToken).ConfigureAwait(false);
  1466. if (Value != null && Value.ToString().StartsWith("System.Byte[]", StringComparison.Ordinal))
  1467. {
  1468. await ReaderReadAndAssertAsync(cancellationToken).ConfigureAwait(false);
  1469. if (Value.ToString() == JsonTypeReflector.ValuePropertyName)
  1470. {
  1471. return;
  1472. }
  1473. }
  1474. }
  1475. throw JsonReaderException.Create(this, "Error reading bytes. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, JsonToken.StartObject));
  1476. }
  1477. /// <summary>
  1478. /// Asynchronously reads the next JSON token from the source as a <see cref="Nullable{T}"/> of <see cref="DateTime"/>.
  1479. /// </summary>
  1480. /// <param name="cancellationToken">The token to monitor for cancellation requests. The default value is <see cref="CancellationToken.None"/>.</param>
  1481. /// <returns>A <see cref="Task{TResult}"/> that represents the asynchronous read. The <see cref="Task{TResult}.Result"/>
  1482. /// property returns the <see cref="Nullable{T}"/> of <see cref="DateTime"/>. This result will be <c>null</c> at the end of an array.</returns>
  1483. /// <remarks>Derived classes must override this method to get asynchronous behaviour. Otherwise it will
  1484. /// execute synchronously, returning an already-completed task.</remarks>
  1485. public override Task<DateTime?> ReadAsDateTimeAsync(CancellationToken cancellationToken = default(CancellationToken))
  1486. {
  1487. return _safeAsync ? DoReadAsDateTimeAsync(cancellationToken) : base.ReadAsDateTimeAsync(cancellationToken);
  1488. }
  1489. internal async Task<DateTime?> DoReadAsDateTimeAsync(CancellationToken cancellationToken)
  1490. {
  1491. return (DateTime?)await ReadStringValueAsync(ReadType.ReadAsDateTime, cancellationToken).ConfigureAwait(false);
  1492. }
  1493. /// <summary>
  1494. /// Asynchronously reads the next JSON token from the source as a <see cref="Nullable{T}"/> of <see cref="DateTimeOffset"/>.
  1495. /// </summary>
  1496. /// <param name="cancellationToken">The token to monitor for cancellation requests. The default value is <see cref="CancellationToken.None"/>.</param>
  1497. /// <returns>A <see cref="Task{TResult}"/> that represents the asynchronous read. The <see cref="Task{TResult}.Result"/>
  1498. /// property returns the <see cref="Nullable{T}"/> of <see cref="DateTimeOffset"/>. This result will be <c>null</c> at the end of an array.</returns>
  1499. /// <remarks>Derived classes must override this method to get asynchronous behaviour. Otherwise it will
  1500. /// execute synchronously, returning an already-completed task.</remarks>
  1501. public override Task<DateTimeOffset?> ReadAsDateTimeOffsetAsync(CancellationToken cancellationToken = default(CancellationToken))
  1502. {
  1503. return _safeAsync ? DoReadAsDateTimeOffsetAsync(cancellationToken) : base.ReadAsDateTimeOffsetAsync(cancellationToken);
  1504. }
  1505. internal async Task<DateTimeOffset?> DoReadAsDateTimeOffsetAsync(CancellationToken cancellationToken)
  1506. {
  1507. return (DateTimeOffset?)await ReadStringValueAsync(ReadType.ReadAsDateTimeOffset, cancellationToken).ConfigureAwait(false);
  1508. }
  1509. /// <summary>
  1510. /// Asynchronously reads the next JSON token from the source as a <see cref="Nullable{T}"/> of <see cref="decimal"/>.
  1511. /// </summary>
  1512. /// <param name="cancellationToken">The token to monitor for cancellation requests. The default value is <see cref="CancellationToken.None"/>.</param>
  1513. /// <returns>A <see cref="Task{TResult}"/> that represents the asynchronous read. The <see cref="Task{TResult}.Result"/>
  1514. /// property returns the <see cref="Nullable{T}"/> of <see cref="decimal"/>. This result will be <c>null</c> at the end of an array.</returns>
  1515. /// <remarks>Derived classes must override this method to get asynchronous behaviour. Otherwise it will
  1516. /// execute synchronously, returning an already-completed task.</remarks>
  1517. public override Task<decimal?> ReadAsDecimalAsync(CancellationToken cancellationToken = default(CancellationToken))
  1518. {
  1519. return _safeAsync ? DoReadAsDecimalAsync(cancellationToken) : base.ReadAsDecimalAsync(cancellationToken);
  1520. }
  1521. internal async Task<decimal?> DoReadAsDecimalAsync(CancellationToken cancellationToken)
  1522. {
  1523. return (decimal?)await ReadNumberValueAsync(ReadType.ReadAsDecimal, cancellationToken).ConfigureAwait(false);
  1524. }
  1525. /// <summary>
  1526. /// Asynchronously reads the next JSON token from the source as a <see cref="Nullable{T}"/> of <see cref="double"/>.
  1527. /// </summary>
  1528. /// <param name="cancellationToken">The token to monitor for cancellation requests. The default value is <see cref="CancellationToken.None"/>.</param>
  1529. /// <returns>A <see cref="Task{TResult}"/> that represents the asynchronous read. The <see cref="Task{TResult}.Result"/>
  1530. /// property returns the <see cref="Nullable{T}"/> of <see cref="double"/>. This result will be <c>null</c> at the end of an array.</returns>
  1531. /// <remarks>Derived classes must override this method to get asynchronous behaviour. Otherwise it will
  1532. /// execute synchronously, returning an already-completed task.</remarks>
  1533. public override Task<double?> ReadAsDoubleAsync(CancellationToken cancellationToken = default(CancellationToken))
  1534. {
  1535. return _safeAsync ? DoReadAsDoubleAsync(cancellationToken) : base.ReadAsDoubleAsync(cancellationToken);
  1536. }
  1537. internal async Task<double?> DoReadAsDoubleAsync(CancellationToken cancellationToken)
  1538. {
  1539. return (double?)await ReadNumberValueAsync(ReadType.ReadAsDouble, cancellationToken).ConfigureAwait(false);
  1540. }
  1541. /// <summary>
  1542. /// Asynchronously reads the next JSON token from the source as a <see cref="Nullable{T}"/> of <see cref="int"/>.
  1543. /// </summary>
  1544. /// <param name="cancellationToken">The token to monitor for cancellation requests. The default value is <see cref="CancellationToken.None"/>.</param>
  1545. /// <returns>A <see cref="Task{TResult}"/> that represents the asynchronous read. The <see cref="Task{TResult}.Result"/>
  1546. /// property returns the <see cref="Nullable{T}"/> of <see cref="int"/>. This result will be <c>null</c> at the end of an array.</returns>
  1547. /// <remarks>Derived classes must override this method to get asynchronous behaviour. Otherwise it will
  1548. /// execute synchronously, returning an already-completed task.</remarks>
  1549. public override Task<int?> ReadAsInt32Async(CancellationToken cancellationToken = default(CancellationToken))
  1550. {
  1551. return _safeAsync ? DoReadAsInt32Async(cancellationToken) : base.ReadAsInt32Async(cancellationToken);
  1552. }
  1553. internal async Task<int?> DoReadAsInt32Async(CancellationToken cancellationToken)
  1554. {
  1555. return (int?)await ReadNumberValueAsync(ReadType.ReadAsInt32, cancellationToken).ConfigureAwait(false);
  1556. }
  1557. /// <summary>
  1558. /// Asynchronously reads the next JSON token from the source as a <see cref="string"/>.
  1559. /// </summary>
  1560. /// <param name="cancellationToken">The token to monitor for cancellation requests. The default value is <see cref="CancellationToken.None"/>.</param>
  1561. /// <returns>A <see cref="Task{TResult}"/> that represents the asynchronous read. The <see cref="Task{TResult}.Result"/>
  1562. /// property returns the <see cref="string"/>. This result will be <c>null</c> at the end of an array.</returns>
  1563. /// <remarks>Derived classes must override this method to get asynchronous behaviour. Otherwise it will
  1564. /// execute synchronously, returning an already-completed task.</remarks>
  1565. public override Task<string> ReadAsStringAsync(CancellationToken cancellationToken = default(CancellationToken))
  1566. {
  1567. return _safeAsync ? DoReadAsStringAsync(cancellationToken) : base.ReadAsStringAsync(cancellationToken);
  1568. }
  1569. internal async Task<string> DoReadAsStringAsync(CancellationToken cancellationToken)
  1570. {
  1571. return (string)await ReadStringValueAsync(ReadType.ReadAsString, cancellationToken).ConfigureAwait(false);
  1572. }
  1573. }
  1574. }
  1575. #endif