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.

531 lines
17 KiB

4 years ago
4 years ago
4 years ago
4 years ago
  1. #region License
  2. // Copyright (c) 2007 James Newton-King
  3. //
  4. // Permission is hereby granted, free of charge, to any person
  5. // obtaining a copy of this software and associated documentation
  6. // files (the "Software"), to deal in the Software without
  7. // restriction, including without limitation the rights to use,
  8. // copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. // copies of the Software, and to permit persons to whom the
  10. // Software is furnished to do so, subject to the following
  11. // conditions:
  12. //
  13. // The above copyright notice and this permission notice shall be
  14. // included in all copies or substantial portions of the Software.
  15. //
  16. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  17. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
  18. // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  19. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  20. // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  21. // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  22. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  23. // OTHER DEALINGS IN THE SOFTWARE.
  24. #endregion
  25. using System;
  26. using System.Globalization;
  27. #if HAVE_BIG_INTEGER
  28. using System.Numerics;
  29. #endif
  30. using Newtonsoft.Json.Utilities;
  31. namespace Newtonsoft.Json.Linq
  32. {
  33. /// <summary>
  34. /// Represents a writer that provides a fast, non-cached, forward-only way of generating JSON data.
  35. /// </summary>
  36. internal partial class JTokenWriter : JsonWriter
  37. {
  38. private JContainer _token;
  39. private JContainer _parent;
  40. // used when writer is writing single value and the value has no containing parent
  41. private JValue _value;
  42. private JToken _current;
  43. /// <summary>
  44. /// Gets the <see cref="JToken"/> at the writer's current position.
  45. /// </summary>
  46. public JToken CurrentToken => _current;
  47. /// <summary>
  48. /// Gets the token being written.
  49. /// </summary>
  50. /// <value>The token being written.</value>
  51. public JToken Token
  52. {
  53. get
  54. {
  55. if (_token != null)
  56. {
  57. return _token;
  58. }
  59. return _value;
  60. }
  61. }
  62. /// <summary>
  63. /// Initializes a new instance of the <see cref="JTokenWriter"/> class writing to the given <see cref="JContainer"/>.
  64. /// </summary>
  65. /// <param name="container">The container being written to.</param>
  66. public JTokenWriter(JContainer container)
  67. {
  68. ValidationUtils.ArgumentNotNull(container, nameof(container));
  69. _token = container;
  70. _parent = container;
  71. }
  72. /// <summary>
  73. /// Initializes a new instance of the <see cref="JTokenWriter"/> class.
  74. /// </summary>
  75. public JTokenWriter()
  76. {
  77. }
  78. /// <summary>
  79. /// Flushes whatever is in the buffer to the underlying <see cref="JContainer"/>.
  80. /// </summary>
  81. public override void Flush()
  82. {
  83. }
  84. /// <summary>
  85. /// Closes this writer.
  86. /// If <see cref="JsonWriter.AutoCompleteOnClose"/> is set to <c>true</c>, the JSON is auto-completed.
  87. /// </summary>
  88. /// <remarks>
  89. /// Setting <see cref="JsonWriter.CloseOutput"/> to <c>true</c> has no additional effect, since the underlying <see cref="JContainer"/> is a type that cannot be closed.
  90. /// </remarks>
  91. public override void Close()
  92. {
  93. base.Close();
  94. }
  95. /// <summary>
  96. /// Writes the beginning of a JSON object.
  97. /// </summary>
  98. public override void WriteStartObject()
  99. {
  100. base.WriteStartObject();
  101. AddParent(new JObject());
  102. }
  103. private void AddParent(JContainer container)
  104. {
  105. if (_parent == null)
  106. {
  107. _token = container;
  108. }
  109. else
  110. {
  111. _parent.AddAndSkipParentCheck(container);
  112. }
  113. _parent = container;
  114. _current = container;
  115. }
  116. private void RemoveParent()
  117. {
  118. _current = _parent;
  119. _parent = _parent.Parent;
  120. if (_parent != null && _parent.Type == JTokenType.Property)
  121. {
  122. _parent = _parent.Parent;
  123. }
  124. }
  125. /// <summary>
  126. /// Writes the beginning of a JSON array.
  127. /// </summary>
  128. public override void WriteStartArray()
  129. {
  130. base.WriteStartArray();
  131. AddParent(new JArray());
  132. }
  133. /// <summary>
  134. /// Writes the start of a constructor with the given name.
  135. /// </summary>
  136. /// <param name="name">The name of the constructor.</param>
  137. public override void WriteStartConstructor(string name)
  138. {
  139. base.WriteStartConstructor(name);
  140. AddParent(new JConstructor(name));
  141. }
  142. /// <summary>
  143. /// Writes the end.
  144. /// </summary>
  145. /// <param name="token">The token.</param>
  146. protected override void WriteEnd(JsonToken token)
  147. {
  148. RemoveParent();
  149. }
  150. /// <summary>
  151. /// Writes the property name of a name/value pair on a JSON object.
  152. /// </summary>
  153. /// <param name="name">The name of the property.</param>
  154. public override void WritePropertyName(string name)
  155. {
  156. // avoid duplicate property name exception
  157. // last property name wins
  158. (_parent as JObject)?.Remove(name);
  159. AddParent(new JProperty(name));
  160. // don't set state until after in case of an error
  161. // incorrect state will cause issues if writer is disposed when closing open properties
  162. base.WritePropertyName(name);
  163. }
  164. private void AddValue(object value, JsonToken token)
  165. {
  166. AddValue(new JValue(value), token);
  167. }
  168. internal void AddValue(JValue value, JsonToken token)
  169. {
  170. if (_parent != null)
  171. {
  172. _parent.Add(value);
  173. _current = _parent.Last;
  174. if (_parent.Type == JTokenType.Property)
  175. {
  176. _parent = _parent.Parent;
  177. }
  178. }
  179. else
  180. {
  181. _value = value ?? JValue.CreateNull();
  182. _current = _value;
  183. }
  184. }
  185. #region WriteValue methods
  186. /// <summary>
  187. /// Writes a <see cref="Object"/> value.
  188. /// An error will be raised if the value cannot be written as a single JSON token.
  189. /// </summary>
  190. /// <param name="value">The <see cref="Object"/> value to write.</param>
  191. public override void WriteValue(object value)
  192. {
  193. #if HAVE_BIG_INTEGER
  194. if (value is BigInteger)
  195. {
  196. InternalWriteValue(JsonToken.Integer);
  197. AddValue(value, JsonToken.Integer);
  198. }
  199. else
  200. #endif
  201. {
  202. base.WriteValue(value);
  203. }
  204. }
  205. /// <summary>
  206. /// Writes a null value.
  207. /// </summary>
  208. public override void WriteNull()
  209. {
  210. base.WriteNull();
  211. AddValue(null, JsonToken.Null);
  212. }
  213. /// <summary>
  214. /// Writes an undefined value.
  215. /// </summary>
  216. public override void WriteUndefined()
  217. {
  218. base.WriteUndefined();
  219. AddValue(null, JsonToken.Undefined);
  220. }
  221. /// <summary>
  222. /// Writes raw JSON.
  223. /// </summary>
  224. /// <param name="json">The raw JSON to write.</param>
  225. public override void WriteRaw(string json)
  226. {
  227. base.WriteRaw(json);
  228. AddValue(new JRaw(json), JsonToken.Raw);
  229. }
  230. /// <summary>
  231. /// Writes a comment <c>/*...*/</c> containing the specified text.
  232. /// </summary>
  233. /// <param name="text">Text to place inside the comment.</param>
  234. public override void WriteComment(string text)
  235. {
  236. base.WriteComment(text);
  237. AddValue(JValue.CreateComment(text), JsonToken.Comment);
  238. }
  239. /// <summary>
  240. /// Writes a <see cref="String"/> value.
  241. /// </summary>
  242. /// <param name="value">The <see cref="String"/> value to write.</param>
  243. public override void WriteValue(string value)
  244. {
  245. base.WriteValue(value);
  246. AddValue(value, JsonToken.String);
  247. }
  248. /// <summary>
  249. /// Writes a <see cref="Int32"/> value.
  250. /// </summary>
  251. /// <param name="value">The <see cref="Int32"/> value to write.</param>
  252. public override void WriteValue(int value)
  253. {
  254. base.WriteValue(value);
  255. AddValue(value, JsonToken.Integer);
  256. }
  257. /// <summary>
  258. /// Writes a <see cref="UInt32"/> value.
  259. /// </summary>
  260. /// <param name="value">The <see cref="UInt32"/> value to write.</param>
  261. public override void WriteValue(uint value)
  262. {
  263. base.WriteValue(value);
  264. AddValue(value, JsonToken.Integer);
  265. }
  266. /// <summary>
  267. /// Writes a <see cref="Int64"/> value.
  268. /// </summary>
  269. /// <param name="value">The <see cref="Int64"/> value to write.</param>
  270. public override void WriteValue(long value)
  271. {
  272. base.WriteValue(value);
  273. AddValue(value, JsonToken.Integer);
  274. }
  275. /// <summary>
  276. /// Writes a <see cref="UInt64"/> value.
  277. /// </summary>
  278. /// <param name="value">The <see cref="UInt64"/> value to write.</param>
  279. public override void WriteValue(ulong value)
  280. {
  281. base.WriteValue(value);
  282. AddValue(value, JsonToken.Integer);
  283. }
  284. /// <summary>
  285. /// Writes a <see cref="Single"/> value.
  286. /// </summary>
  287. /// <param name="value">The <see cref="Single"/> value to write.</param>
  288. public override void WriteValue(float value)
  289. {
  290. base.WriteValue(value);
  291. AddValue(value, JsonToken.Float);
  292. }
  293. /// <summary>
  294. /// Writes a <see cref="Double"/> value.
  295. /// </summary>
  296. /// <param name="value">The <see cref="Double"/> value to write.</param>
  297. public override void WriteValue(double value)
  298. {
  299. base.WriteValue(value);
  300. AddValue(value, JsonToken.Float);
  301. }
  302. /// <summary>
  303. /// Writes a <see cref="Boolean"/> value.
  304. /// </summary>
  305. /// <param name="value">The <see cref="Boolean"/> value to write.</param>
  306. public override void WriteValue(bool value)
  307. {
  308. base.WriteValue(value);
  309. AddValue(value, JsonToken.Boolean);
  310. }
  311. /// <summary>
  312. /// Writes a <see cref="Int16"/> value.
  313. /// </summary>
  314. /// <param name="value">The <see cref="Int16"/> value to write.</param>
  315. public override void WriteValue(short value)
  316. {
  317. base.WriteValue(value);
  318. AddValue(value, JsonToken.Integer);
  319. }
  320. /// <summary>
  321. /// Writes a <see cref="UInt16"/> value.
  322. /// </summary>
  323. /// <param name="value">The <see cref="UInt16"/> value to write.</param>
  324. public override void WriteValue(ushort value)
  325. {
  326. base.WriteValue(value);
  327. AddValue(value, JsonToken.Integer);
  328. }
  329. /// <summary>
  330. /// Writes a <see cref="Char"/> value.
  331. /// </summary>
  332. /// <param name="value">The <see cref="Char"/> value to write.</param>
  333. public override void WriteValue(char value)
  334. {
  335. base.WriteValue(value);
  336. string s;
  337. #if HAVE_CHAR_TO_STRING_WITH_CULTURE
  338. s = value.ToString(CultureInfo.InvariantCulture);
  339. #else
  340. s = value.ToString();
  341. #endif
  342. AddValue(s, JsonToken.String);
  343. }
  344. /// <summary>
  345. /// Writes a <see cref="Byte"/> value.
  346. /// </summary>
  347. /// <param name="value">The <see cref="Byte"/> value to write.</param>
  348. public override void WriteValue(byte value)
  349. {
  350. base.WriteValue(value);
  351. AddValue(value, JsonToken.Integer);
  352. }
  353. /// <summary>
  354. /// Writes a <see cref="SByte"/> value.
  355. /// </summary>
  356. /// <param name="value">The <see cref="SByte"/> value to write.</param>
  357. public override void WriteValue(sbyte value)
  358. {
  359. base.WriteValue(value);
  360. AddValue(value, JsonToken.Integer);
  361. }
  362. /// <summary>
  363. /// Writes a <see cref="Decimal"/> value.
  364. /// </summary>
  365. /// <param name="value">The <see cref="Decimal"/> value to write.</param>
  366. public override void WriteValue(decimal value)
  367. {
  368. base.WriteValue(value);
  369. AddValue(value, JsonToken.Float);
  370. }
  371. /// <summary>
  372. /// Writes a <see cref="DateTime"/> value.
  373. /// </summary>
  374. /// <param name="value">The <see cref="DateTime"/> value to write.</param>
  375. public override void WriteValue(DateTime value)
  376. {
  377. base.WriteValue(value);
  378. value = DateTimeUtils.EnsureDateTime(value, DateTimeZoneHandling);
  379. AddValue(value, JsonToken.Date);
  380. }
  381. #if !NET20
  382. /// <summary>
  383. /// Writes a <see cref="DateTimeOffset"/> value.
  384. /// </summary>
  385. /// <param name="value">The <see cref="DateTimeOffset"/> value to write.</param>
  386. public override void WriteValue(DateTimeOffset value)
  387. {
  388. base.WriteValue(value);
  389. AddValue(value, JsonToken.Date);
  390. }
  391. #endif
  392. /// <summary>
  393. /// Writes a <see cref="Byte"/>[] value.
  394. /// </summary>
  395. /// <param name="value">The <see cref="Byte"/>[] value to write.</param>
  396. public override void WriteValue(byte[] value)
  397. {
  398. base.WriteValue(value);
  399. AddValue(value, JsonToken.Bytes);
  400. }
  401. /// <summary>
  402. /// Writes a <see cref="TimeSpan"/> value.
  403. /// </summary>
  404. /// <param name="value">The <see cref="TimeSpan"/> value to write.</param>
  405. public override void WriteValue(TimeSpan value)
  406. {
  407. base.WriteValue(value);
  408. AddValue(value, JsonToken.String);
  409. }
  410. /// <summary>
  411. /// Writes a <see cref="Guid"/> value.
  412. /// </summary>
  413. /// <param name="value">The <see cref="Guid"/> value to write.</param>
  414. public override void WriteValue(Guid value)
  415. {
  416. base.WriteValue(value);
  417. AddValue(value, JsonToken.String);
  418. }
  419. /// <summary>
  420. /// Writes a <see cref="Uri"/> value.
  421. /// </summary>
  422. /// <param name="value">The <see cref="Uri"/> value to write.</param>
  423. public override void WriteValue(Uri value)
  424. {
  425. base.WriteValue(value);
  426. AddValue(value, JsonToken.String);
  427. }
  428. #endregion
  429. internal override void WriteToken(JsonReader reader, bool writeChildren, bool writeDateConstructorAsDate, bool writeComments)
  430. {
  431. // cloning the token rather than reading then writing it doesn't lose some type information, e.g. Guid, byte[], etc
  432. if (reader is JTokenReader tokenReader && writeChildren && writeDateConstructorAsDate && writeComments)
  433. {
  434. if (tokenReader.TokenType == JsonToken.None)
  435. {
  436. if (!tokenReader.Read())
  437. {
  438. return;
  439. }
  440. }
  441. JToken value = tokenReader.CurrentToken.CloneToken();
  442. if (_parent != null)
  443. {
  444. _parent.Add(value);
  445. _current = _parent.Last;
  446. // if the writer was in a property then move out of it and up to its parent object
  447. if (_parent.Type == JTokenType.Property)
  448. {
  449. _parent = _parent.Parent;
  450. InternalWriteValue(JsonToken.Null);
  451. }
  452. }
  453. else
  454. {
  455. _current = value;
  456. if (_token == null && _value == null)
  457. {
  458. _token = value as JContainer;
  459. _value = value as JValue;
  460. }
  461. }
  462. tokenReader.Skip();
  463. }
  464. else
  465. {
  466. base.WriteToken(reader, writeChildren, writeDateConstructorAsDate, writeComments);
  467. }
  468. }
  469. }
  470. }