BsonDocumentWriter.cs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551
  1. /* Copyright 2010-present MongoDB Inc.
  2. *
  3. * Licensed under the Apache License, Version 2.0 (the "License");
  4. * you may not use this file except in compliance with the License.
  5. * You may obtain a copy of the License at
  6. *
  7. * http://www.apache.org/licenses/LICENSE-2.0
  8. *
  9. * Unless required by applicable law or agreed to in writing, software
  10. * distributed under the License is distributed on an "AS IS" BASIS,
  11. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. * See the License for the specific language governing permissions and
  13. * limitations under the License.
  14. */
  15. using System;
  16. namespace MongoDB.Bson.IO
  17. {
  18. /// <summary>
  19. /// Represents a BSON writer to a BsonDocument.
  20. /// </summary>
  21. public class BsonDocumentWriter : BsonWriter
  22. {
  23. // private fields
  24. private BsonDocument _document;
  25. private BsonDocumentWriterContext _context;
  26. // constructors
  27. /// <summary>
  28. /// Initializes a new instance of the BsonDocumentWriter class.
  29. /// </summary>
  30. /// <param name="document">The document to write to (normally starts out as an empty document).</param>
  31. public BsonDocumentWriter(BsonDocument document)
  32. : this(document, BsonDocumentWriterSettings.Defaults)
  33. {
  34. }
  35. /// <summary>
  36. /// Initializes a new instance of the BsonDocumentWriter class.
  37. /// </summary>
  38. /// <param name="document">The document to write to (normally starts out as an empty document).</param>
  39. /// <param name="settings">The settings.</param>
  40. public BsonDocumentWriter(BsonDocument document, BsonDocumentWriterSettings settings)
  41. : base(settings)
  42. {
  43. if (document == null)
  44. {
  45. throw new ArgumentNullException("document");
  46. }
  47. _document = document;
  48. _context = null;
  49. State = BsonWriterState.Initial;
  50. }
  51. // public properties
  52. /// <summary>
  53. /// Gets the BsonDocument being written to.
  54. /// </summary>
  55. public BsonDocument Document
  56. {
  57. get { return _document; }
  58. }
  59. /// <inheritdoc />
  60. public override long Position => 0L;
  61. // public methods
  62. /// <summary>
  63. /// Closes the writer.
  64. /// </summary>
  65. public override void Close()
  66. {
  67. // Close can be called on Disposed objects
  68. _context = null;
  69. State = BsonWriterState.Closed;
  70. }
  71. /// <summary>
  72. /// Flushes any pending data to the output destination.
  73. /// </summary>
  74. public override void Flush()
  75. {
  76. if (Disposed) { throw new ObjectDisposedException("BsonDocumentWriter"); }
  77. }
  78. /// <summary>
  79. /// Writes BSON binary data to the writer.
  80. /// </summary>
  81. /// <param name="binaryData">The binary data.</param>
  82. public override void WriteBinaryData(BsonBinaryData binaryData)
  83. {
  84. if (Disposed) { throw new ObjectDisposedException("BsonDocumentWriter"); }
  85. if (State != BsonWriterState.Value)
  86. {
  87. ThrowInvalidState("WriteBinaryData", BsonWriterState.Value);
  88. }
  89. WriteValue(binaryData);
  90. State = GetNextState();
  91. }
  92. /// <summary>
  93. /// Writes a BSON Boolean to the writer.
  94. /// </summary>
  95. /// <param name="value">The Boolean value.</param>
  96. public override void WriteBoolean(bool value)
  97. {
  98. if (Disposed) { throw new ObjectDisposedException("BsonDocumentWriter"); }
  99. if (State != BsonWriterState.Value)
  100. {
  101. ThrowInvalidState("WriteBoolean", BsonWriterState.Value);
  102. }
  103. WriteValue(value);
  104. State = GetNextState();
  105. }
  106. /// <summary>
  107. /// Writes BSON binary data to the writer.
  108. /// </summary>
  109. /// <param name="bytes">The bytes.</param>
  110. public override void WriteBytes(byte[] bytes)
  111. {
  112. if (Disposed) { throw new ObjectDisposedException("BsonDocumentWriter"); }
  113. if (State != BsonWriterState.Value)
  114. {
  115. ThrowInvalidState("WriteBytes", BsonWriterState.Value);
  116. }
  117. WriteValue(new BsonBinaryData(bytes, BsonBinarySubType.Binary));
  118. State = GetNextState();
  119. }
  120. /// <summary>
  121. /// Writes a BSON DateTime to the writer.
  122. /// </summary>
  123. /// <param name="value">The number of milliseconds since the Unix epoch.</param>
  124. public override void WriteDateTime(long value)
  125. {
  126. if (Disposed) { throw new ObjectDisposedException("BsonDocumentWriter"); }
  127. if (State != BsonWriterState.Value)
  128. {
  129. ThrowInvalidState("WriteDateTime", BsonWriterState.Value);
  130. }
  131. WriteValue(new BsonDateTime(value));
  132. State = GetNextState();
  133. }
  134. /// <inheritdoc />
  135. public override void WriteDecimal128(Decimal128 value)
  136. {
  137. if (Disposed) { throw new ObjectDisposedException("BsonDocumentWriter"); }
  138. if (State != BsonWriterState.Value)
  139. {
  140. ThrowInvalidState(nameof(WriteDecimal128), BsonWriterState.Value);
  141. }
  142. WriteValue(new BsonDecimal128(value));
  143. State = GetNextState();
  144. }
  145. /// <summary>
  146. /// Writes a BSON Double to the writer.
  147. /// </summary>
  148. /// <param name="value">The Double value.</param>
  149. public override void WriteDouble(double value)
  150. {
  151. if (Disposed) { throw new ObjectDisposedException("BsonDocumentWriter"); }
  152. if (State != BsonWriterState.Value)
  153. {
  154. ThrowInvalidState("WriteDouble", BsonWriterState.Value);
  155. }
  156. WriteValue(value);
  157. State = GetNextState();
  158. }
  159. /// <summary>
  160. /// Writes the end of a BSON array to the writer.
  161. /// </summary>
  162. public override void WriteEndArray()
  163. {
  164. if (Disposed) { throw new ObjectDisposedException("BsonDocumentWriter"); }
  165. if (State != BsonWriterState.Value)
  166. {
  167. ThrowInvalidState("WriteEndArray", BsonWriterState.Value);
  168. }
  169. if (_context.ContextType != ContextType.Array)
  170. {
  171. ThrowInvalidContextType("WriteEndArray", _context.ContextType, ContextType.Array);
  172. }
  173. base.WriteEndArray();
  174. var array = _context.Array;
  175. _context = _context.ParentContext;
  176. WriteValue(array);
  177. State = GetNextState();
  178. }
  179. /// <summary>
  180. /// Writes the end of a BSON document to the writer.
  181. /// </summary>
  182. public override void WriteEndDocument()
  183. {
  184. if (Disposed) { throw new ObjectDisposedException("BsonDocumentWriter"); }
  185. if (State != BsonWriterState.Name)
  186. {
  187. ThrowInvalidState("WriteEndDocument", BsonWriterState.Name);
  188. }
  189. if (_context.ContextType != ContextType.Document && _context.ContextType != ContextType.ScopeDocument)
  190. {
  191. ThrowInvalidContextType("WriteEndDocument", _context.ContextType, ContextType.Document, ContextType.ScopeDocument);
  192. }
  193. base.WriteEndDocument();
  194. if (_context.ContextType == ContextType.ScopeDocument)
  195. {
  196. var scope = _context.Document;
  197. _context = _context.ParentContext;
  198. var code = _context.Code;
  199. _context = _context.ParentContext;
  200. WriteValue(new BsonJavaScriptWithScope(code, scope));
  201. }
  202. else
  203. {
  204. var document = _context.Document;
  205. _context = _context.ParentContext;
  206. if (_context != null)
  207. {
  208. WriteValue(document);
  209. }
  210. }
  211. if (_context == null)
  212. {
  213. State = BsonWriterState.Done;
  214. }
  215. else
  216. {
  217. State = GetNextState();
  218. }
  219. }
  220. /// <summary>
  221. /// Writes a BSON Int32 to the writer.
  222. /// </summary>
  223. /// <param name="value">The Int32 value.</param>
  224. public override void WriteInt32(int value)
  225. {
  226. if (Disposed) { throw new ObjectDisposedException("BsonDocumentWriter"); }
  227. if (State != BsonWriterState.Value)
  228. {
  229. ThrowInvalidState("WriteInt32", BsonWriterState.Value);
  230. }
  231. WriteValue(value);
  232. State = GetNextState();
  233. }
  234. /// <summary>
  235. /// Writes a BSON Int64 to the writer.
  236. /// </summary>
  237. /// <param name="value">The Int64 value.</param>
  238. public override void WriteInt64(long value)
  239. {
  240. if (Disposed) { throw new ObjectDisposedException("BsonDocumentWriter"); }
  241. if (State != BsonWriterState.Value)
  242. {
  243. ThrowInvalidState("WriteInt64", BsonWriterState.Value);
  244. }
  245. WriteValue(value);
  246. State = GetNextState();
  247. }
  248. /// <summary>
  249. /// Writes a BSON JavaScript to the writer.
  250. /// </summary>
  251. /// <param name="code">The JavaScript code.</param>
  252. public override void WriteJavaScript(string code)
  253. {
  254. if (Disposed) { throw new ObjectDisposedException("BsonDocumentWriter"); }
  255. if (State != BsonWriterState.Value)
  256. {
  257. ThrowInvalidState("WriteJavaScript", BsonWriterState.Value);
  258. }
  259. WriteValue(new BsonJavaScript(code));
  260. State = GetNextState();
  261. }
  262. /// <summary>
  263. /// Writes a BSON JavaScript to the writer (call WriteStartDocument to start writing the scope).
  264. /// </summary>
  265. /// <param name="code">The JavaScript code.</param>
  266. public override void WriteJavaScriptWithScope(string code)
  267. {
  268. if (Disposed) { throw new ObjectDisposedException("BsonDocumentWriter"); }
  269. if (State != BsonWriterState.Value)
  270. {
  271. ThrowInvalidState("WriteJavaScriptWithScope", BsonWriterState.Value);
  272. }
  273. _context = new BsonDocumentWriterContext(_context, ContextType.JavaScriptWithScope, code);
  274. State = BsonWriterState.ScopeDocument;
  275. }
  276. /// <summary>
  277. /// Writes a BSON MaxKey to the writer.
  278. /// </summary>
  279. public override void WriteMaxKey()
  280. {
  281. if (Disposed) { throw new ObjectDisposedException("BsonDocumentWriter"); }
  282. if (State != BsonWriterState.Value)
  283. {
  284. ThrowInvalidState("WriteMaxKey", BsonWriterState.Value);
  285. }
  286. WriteValue(BsonMaxKey.Value);
  287. State = GetNextState();
  288. }
  289. /// <summary>
  290. /// Writes a BSON MinKey to the writer.
  291. /// </summary>
  292. public override void WriteMinKey()
  293. {
  294. if (Disposed) { throw new ObjectDisposedException("BsonDocumentWriter"); }
  295. if (State != BsonWriterState.Value)
  296. {
  297. ThrowInvalidState("WriteMinKey", BsonWriterState.Value);
  298. }
  299. WriteValue(BsonMinKey.Value);
  300. State = GetNextState();
  301. }
  302. /// <summary>
  303. /// Writes the name of an element to the writer.
  304. /// </summary>
  305. /// <param name="name">The name of the element.</param>
  306. public override void WriteName(string name)
  307. {
  308. base.WriteName(name);
  309. _context.Name = name;
  310. }
  311. /// <summary>
  312. /// Writes a BSON null to the writer.
  313. /// </summary>
  314. public override void WriteNull()
  315. {
  316. if (Disposed) { throw new ObjectDisposedException("BsonDocumentWriter"); }
  317. if (State != BsonWriterState.Value)
  318. {
  319. ThrowInvalidState("WriteNull", BsonWriterState.Value);
  320. }
  321. WriteValue(BsonNull.Value);
  322. State = GetNextState();
  323. }
  324. /// <summary>
  325. /// Writes a BSON ObjectId to the writer.
  326. /// </summary>
  327. /// <param name="objectId">The ObjectId.</param>
  328. public override void WriteObjectId(ObjectId objectId)
  329. {
  330. if (Disposed) { throw new ObjectDisposedException("BsonDocumentWriter"); }
  331. if (State != BsonWriterState.Value)
  332. {
  333. ThrowInvalidState("WriteObjectId", BsonWriterState.Value);
  334. }
  335. WriteValue(objectId);
  336. State = GetNextState();
  337. }
  338. /// <summary>
  339. /// Writes a BSON regular expression to the writer.
  340. /// </summary>
  341. /// <param name="regex">A BsonRegularExpression.</param>
  342. public override void WriteRegularExpression(BsonRegularExpression regex)
  343. {
  344. if (Disposed) { throw new ObjectDisposedException("BsonDocumentWriter"); }
  345. if (State != BsonWriterState.Value)
  346. {
  347. ThrowInvalidState("WriteRegularExpression", BsonWriterState.Value);
  348. }
  349. WriteValue(regex);
  350. State = GetNextState();
  351. }
  352. /// <summary>
  353. /// Writes the start of a BSON array to the writer.
  354. /// </summary>
  355. public override void WriteStartArray()
  356. {
  357. if (Disposed) { throw new ObjectDisposedException("BsonDocumentWriter"); }
  358. if (State != BsonWriterState.Value)
  359. {
  360. ThrowInvalidState("WriteStartArray", BsonWriterState.Value);
  361. }
  362. base.WriteStartArray();
  363. _context = new BsonDocumentWriterContext(_context, ContextType.Array, new BsonArray());
  364. State = BsonWriterState.Value;
  365. }
  366. /// <summary>
  367. /// Writes the start of a BSON document to the writer.
  368. /// </summary>
  369. public override void WriteStartDocument()
  370. {
  371. if (Disposed) { throw new ObjectDisposedException("BsonDocumentWriter"); }
  372. if (State != BsonWriterState.Initial && State != BsonWriterState.Value && State != BsonWriterState.ScopeDocument && State != BsonWriterState.Done)
  373. {
  374. ThrowInvalidState("WriteStartDocument", BsonWriterState.Initial, BsonWriterState.Value, BsonWriterState.ScopeDocument, BsonWriterState.Done);
  375. }
  376. base.WriteStartDocument();
  377. switch (State)
  378. {
  379. case BsonWriterState.Initial:
  380. case BsonWriterState.Done:
  381. _context = new BsonDocumentWriterContext(null, ContextType.Document, _document);
  382. break;
  383. case BsonWriterState.Value:
  384. _context = new BsonDocumentWriterContext(_context, ContextType.Document, new BsonDocument());
  385. break;
  386. case BsonWriterState.ScopeDocument:
  387. _context = new BsonDocumentWriterContext(_context, ContextType.ScopeDocument, new BsonDocument());
  388. break;
  389. default:
  390. throw new BsonInternalException("Unexpected state.");
  391. }
  392. State = BsonWriterState.Name;
  393. }
  394. /// <summary>
  395. /// Writes a BSON String to the writer.
  396. /// </summary>
  397. /// <param name="value">The String value.</param>
  398. public override void WriteString(string value)
  399. {
  400. if (Disposed) { throw new ObjectDisposedException("BsonDocumentWriter"); }
  401. if (State != BsonWriterState.Value)
  402. {
  403. ThrowInvalidState("WriteString", BsonWriterState.Value);
  404. }
  405. WriteValue(value);
  406. State = GetNextState();
  407. }
  408. /// <summary>
  409. /// Writes a BSON Symbol to the writer.
  410. /// </summary>
  411. /// <param name="value">The symbol.</param>
  412. public override void WriteSymbol(string value)
  413. {
  414. if (Disposed) { throw new ObjectDisposedException("BsonDocumentWriter"); }
  415. if (State != BsonWriterState.Value)
  416. {
  417. ThrowInvalidState("WriteSymbol", BsonWriterState.Value);
  418. }
  419. WriteValue(BsonSymbolTable.Lookup(value));
  420. State = GetNextState();
  421. }
  422. /// <summary>
  423. /// Writes a BSON timestamp to the writer.
  424. /// </summary>
  425. /// <param name="value">The combined timestamp/increment value.</param>
  426. public override void WriteTimestamp(long value)
  427. {
  428. if (Disposed) { throw new ObjectDisposedException("BsonDocumentWriter"); }
  429. if (State != BsonWriterState.Value)
  430. {
  431. ThrowInvalidState("WriteTimestamp", BsonWriterState.Value);
  432. }
  433. WriteValue(new BsonTimestamp(value));
  434. State = GetNextState();
  435. }
  436. /// <summary>
  437. /// Writes a BSON undefined to the writer.
  438. /// </summary>
  439. public override void WriteUndefined()
  440. {
  441. if (Disposed) { throw new ObjectDisposedException("BsonDocumentWriter"); }
  442. if (State != BsonWriterState.Value)
  443. {
  444. ThrowInvalidState("WriteUndefined", BsonWriterState.Value);
  445. }
  446. WriteValue(BsonUndefined.Value);
  447. State = GetNextState();
  448. }
  449. // protected methods
  450. /// <summary>
  451. /// Disposes of any resources used by the writer.
  452. /// </summary>
  453. /// <param name="disposing">True if called from Dispose.</param>
  454. protected override void Dispose(bool disposing)
  455. {
  456. if (disposing)
  457. {
  458. try
  459. {
  460. Close();
  461. }
  462. catch { } // ignore exceptions
  463. }
  464. base.Dispose(disposing);
  465. }
  466. // private methods
  467. private BsonWriterState GetNextState()
  468. {
  469. if (_context.ContextType == ContextType.Array)
  470. {
  471. return BsonWriterState.Value;
  472. }
  473. else
  474. {
  475. return BsonWriterState.Name;
  476. }
  477. }
  478. private void WriteValue(BsonValue value)
  479. {
  480. if (_context.ContextType == ContextType.Array)
  481. {
  482. _context.Array.Add(value);
  483. }
  484. else
  485. {
  486. _context.Document.Add(_context.Name, value);
  487. }
  488. }
  489. }
  490. }