BsonDocumentWriter.cs 18 KB

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