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.

535 lines
18 KiB

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