BsonDocumentWriter.cs 18 KB

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