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

  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. [CLSCompliant(false)]
  262. public override void WriteValue(uint value)
  263. {
  264. base.WriteValue(value);
  265. AddValue(value, JsonToken.Integer);
  266. }
  267. /// <summary>
  268. /// Writes a <see cref="Int64"/> value.
  269. /// </summary>
  270. /// <param name="value">The <see cref="Int64"/> value to write.</param>
  271. public override void WriteValue(long value)
  272. {
  273. base.WriteValue(value);
  274. AddValue(value, JsonToken.Integer);
  275. }
  276. /// <summary>
  277. /// Writes a <see cref="UInt64"/> value.
  278. /// </summary>
  279. /// <param name="value">The <see cref="UInt64"/> value to write.</param>
  280. [CLSCompliant(false)]
  281. public override void WriteValue(ulong value)
  282. {
  283. base.WriteValue(value);
  284. AddValue(value, JsonToken.Integer);
  285. }
  286. /// <summary>
  287. /// Writes a <see cref="Single"/> value.
  288. /// </summary>
  289. /// <param name="value">The <see cref="Single"/> value to write.</param>
  290. public override void WriteValue(float value)
  291. {
  292. base.WriteValue(value);
  293. AddValue(value, JsonToken.Float);
  294. }
  295. /// <summary>
  296. /// Writes a <see cref="Double"/> value.
  297. /// </summary>
  298. /// <param name="value">The <see cref="Double"/> value to write.</param>
  299. public override void WriteValue(double value)
  300. {
  301. base.WriteValue(value);
  302. AddValue(value, JsonToken.Float);
  303. }
  304. /// <summary>
  305. /// Writes a <see cref="Boolean"/> value.
  306. /// </summary>
  307. /// <param name="value">The <see cref="Boolean"/> value to write.</param>
  308. public override void WriteValue(bool value)
  309. {
  310. base.WriteValue(value);
  311. AddValue(value, JsonToken.Boolean);
  312. }
  313. /// <summary>
  314. /// Writes a <see cref="Int16"/> value.
  315. /// </summary>
  316. /// <param name="value">The <see cref="Int16"/> value to write.</param>
  317. public override void WriteValue(short value)
  318. {
  319. base.WriteValue(value);
  320. AddValue(value, JsonToken.Integer);
  321. }
  322. /// <summary>
  323. /// Writes a <see cref="UInt16"/> value.
  324. /// </summary>
  325. /// <param name="value">The <see cref="UInt16"/> value to write.</param>
  326. [CLSCompliant(false)]
  327. public override void WriteValue(ushort value)
  328. {
  329. base.WriteValue(value);
  330. AddValue(value, JsonToken.Integer);
  331. }
  332. /// <summary>
  333. /// Writes a <see cref="Char"/> value.
  334. /// </summary>
  335. /// <param name="value">The <see cref="Char"/> value to write.</param>
  336. public override void WriteValue(char value)
  337. {
  338. base.WriteValue(value);
  339. string s;
  340. #if HAVE_CHAR_TO_STRING_WITH_CULTURE
  341. s = value.ToString(CultureInfo.InvariantCulture);
  342. #else
  343. s = value.ToString();
  344. #endif
  345. AddValue(s, JsonToken.String);
  346. }
  347. /// <summary>
  348. /// Writes a <see cref="Byte"/> value.
  349. /// </summary>
  350. /// <param name="value">The <see cref="Byte"/> value to write.</param>
  351. public override void WriteValue(byte value)
  352. {
  353. base.WriteValue(value);
  354. AddValue(value, JsonToken.Integer);
  355. }
  356. /// <summary>
  357. /// Writes a <see cref="SByte"/> value.
  358. /// </summary>
  359. /// <param name="value">The <see cref="SByte"/> value to write.</param>
  360. [CLSCompliant(false)]
  361. public override void WriteValue(sbyte value)
  362. {
  363. base.WriteValue(value);
  364. AddValue(value, JsonToken.Integer);
  365. }
  366. /// <summary>
  367. /// Writes a <see cref="Decimal"/> value.
  368. /// </summary>
  369. /// <param name="value">The <see cref="Decimal"/> value to write.</param>
  370. public override void WriteValue(decimal value)
  371. {
  372. base.WriteValue(value);
  373. AddValue(value, JsonToken.Float);
  374. }
  375. /// <summary>
  376. /// Writes a <see cref="DateTime"/> value.
  377. /// </summary>
  378. /// <param name="value">The <see cref="DateTime"/> value to write.</param>
  379. public override void WriteValue(DateTime value)
  380. {
  381. base.WriteValue(value);
  382. value = DateTimeUtils.EnsureDateTime(value, DateTimeZoneHandling);
  383. AddValue(value, JsonToken.Date);
  384. }
  385. #if !NET20
  386. /// <summary>
  387. /// Writes a <see cref="DateTimeOffset"/> value.
  388. /// </summary>
  389. /// <param name="value">The <see cref="DateTimeOffset"/> value to write.</param>
  390. public override void WriteValue(DateTimeOffset value)
  391. {
  392. base.WriteValue(value);
  393. AddValue(value, JsonToken.Date);
  394. }
  395. #endif
  396. /// <summary>
  397. /// Writes a <see cref="Byte"/>[] value.
  398. /// </summary>
  399. /// <param name="value">The <see cref="Byte"/>[] value to write.</param>
  400. public override void WriteValue(byte[] value)
  401. {
  402. base.WriteValue(value);
  403. AddValue(value, JsonToken.Bytes);
  404. }
  405. /// <summary>
  406. /// Writes a <see cref="TimeSpan"/> value.
  407. /// </summary>
  408. /// <param name="value">The <see cref="TimeSpan"/> value to write.</param>
  409. public override void WriteValue(TimeSpan value)
  410. {
  411. base.WriteValue(value);
  412. AddValue(value, JsonToken.String);
  413. }
  414. /// <summary>
  415. /// Writes a <see cref="Guid"/> value.
  416. /// </summary>
  417. /// <param name="value">The <see cref="Guid"/> value to write.</param>
  418. public override void WriteValue(Guid value)
  419. {
  420. base.WriteValue(value);
  421. AddValue(value, JsonToken.String);
  422. }
  423. /// <summary>
  424. /// Writes a <see cref="Uri"/> value.
  425. /// </summary>
  426. /// <param name="value">The <see cref="Uri"/> value to write.</param>
  427. public override void WriteValue(Uri value)
  428. {
  429. base.WriteValue(value);
  430. AddValue(value, JsonToken.String);
  431. }
  432. #endregion
  433. internal override void WriteToken(JsonReader reader, bool writeChildren, bool writeDateConstructorAsDate, bool writeComments)
  434. {
  435. // cloning the token rather than reading then writing it doesn't lose some type information, e.g. Guid, byte[], etc
  436. if (reader is JTokenReader tokenReader && writeChildren && writeDateConstructorAsDate && writeComments)
  437. {
  438. if (tokenReader.TokenType == JsonToken.None)
  439. {
  440. if (!tokenReader.Read())
  441. {
  442. return;
  443. }
  444. }
  445. JToken value = tokenReader.CurrentToken.CloneToken();
  446. if (_parent != null)
  447. {
  448. _parent.Add(value);
  449. _current = _parent.Last;
  450. // if the writer was in a property then move out of it and up to its parent object
  451. if (_parent.Type == JTokenType.Property)
  452. {
  453. _parent = _parent.Parent;
  454. InternalWriteValue(JsonToken.Null);
  455. }
  456. }
  457. else
  458. {
  459. _current = value;
  460. if (_token == null && _value == null)
  461. {
  462. _token = value as JContainer;
  463. _value = value as JValue;
  464. }
  465. }
  466. tokenReader.Skip();
  467. }
  468. else
  469. {
  470. base.WriteToken(reader, writeChildren, writeDateConstructorAsDate, writeComments);
  471. }
  472. }
  473. }
  474. }