BsonWriter.cs 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910
  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. using System.IO;
  17. using System.Linq;
  18. using MongoDB.Bson.Serialization;
  19. using MongoDB.Bson.Serialization.Serializers;
  20. namespace MongoDB.Bson.IO
  21. {
  22. /// <summary>
  23. /// Represents a BSON writer for some external format (see subclasses).
  24. /// </summary>
  25. public abstract class BsonWriter : IDisposable
  26. {
  27. // private fields
  28. private bool _disposed = false;
  29. private BsonWriterSettings _settings;
  30. private BsonWriterState _state;
  31. private string _name;
  32. private bool _checkElementNames;
  33. private bool _checkUpdateDocument;
  34. private int _serializationDepth;
  35. // constructors
  36. /// <summary>
  37. /// Initializes a new instance of the BsonWriter class.
  38. /// </summary>
  39. /// <param name="settings">The writer settings.</param>
  40. protected BsonWriter(BsonWriterSettings settings)
  41. {
  42. if (settings == null)
  43. {
  44. throw new ArgumentNullException("settings");
  45. }
  46. _settings = settings.FrozenCopy();
  47. _state = BsonWriterState.Initial;
  48. }
  49. // public properties
  50. /// <summary>
  51. /// Gets or sets whether to check element names (no periods or leading $).
  52. /// </summary>
  53. public bool CheckElementNames
  54. {
  55. get { return _checkElementNames; }
  56. set { _checkElementNames = value; }
  57. }
  58. /// <summary>
  59. /// Gets or sets whether to check an update document (turns CheckElementNames on if first element name does *not* start with $).
  60. /// </summary>
  61. public bool CheckUpdateDocument
  62. {
  63. get { return _checkUpdateDocument; }
  64. set { _checkUpdateDocument = value; }
  65. }
  66. /// <summary>
  67. /// Gets the current serialization depth.
  68. /// </summary>
  69. public int SerializationDepth
  70. {
  71. get { return _serializationDepth; }
  72. }
  73. /// <summary>
  74. /// Gets the settings of the writer.
  75. /// </summary>
  76. public BsonWriterSettings Settings
  77. {
  78. get { return _settings; }
  79. }
  80. /// <summary>
  81. /// Gets the current state of the writer.
  82. /// </summary>
  83. public BsonWriterState State
  84. {
  85. get { return _state; }
  86. protected set { _state = value; }
  87. }
  88. // protected properties
  89. /// <summary>
  90. /// Gets whether the BsonWriter has been disposed.
  91. /// </summary>
  92. public bool Disposed
  93. {
  94. get { return _disposed; }
  95. }
  96. // protected properties
  97. /// <summary>
  98. /// Gets the name of the element being written.
  99. /// </summary>
  100. protected string Name
  101. {
  102. get { return _name; }
  103. }
  104. // public static methods
  105. /// <summary>
  106. /// Creates a BsonWriter to a BsonBuffer.
  107. /// </summary>
  108. /// <param name="settings">Optional BsonBinaryWriterSettings.</param>
  109. /// <returns>A BsonWriter.</returns>
  110. public static BsonWriter Create(BsonBinaryWriterSettings settings)
  111. {
  112. return new BsonBinaryWriter(null, null, settings);
  113. }
  114. /// <summary>
  115. /// Creates a BsonWriter to a BsonBuffer.
  116. /// </summary>
  117. /// <param name="buffer">A BsonBuffer.</param>
  118. /// <returns>A BsonWriter.</returns>
  119. public static BsonWriter Create(BsonBuffer buffer)
  120. {
  121. return new BsonBinaryWriter(null, buffer, BsonBinaryWriterSettings.Defaults);
  122. }
  123. /// <summary>
  124. /// Creates a BsonWriter to a BsonBuffer.
  125. /// </summary>
  126. /// <param name="buffer">A BsonBuffer.</param>
  127. /// <param name="settings">Optional BsonBinaryWriterSettings.</param>
  128. /// <returns>A BsonWriter.</returns>
  129. public static BsonWriter Create(BsonBuffer buffer, BsonBinaryWriterSettings settings)
  130. {
  131. return new BsonBinaryWriter(null, buffer, settings);
  132. }
  133. /// <summary>
  134. /// Creates a BsonWriter to a BsonDocument.
  135. /// </summary>
  136. /// <param name="document">A BsonDocument.</param>
  137. /// <returns>A BsonWriter.</returns>
  138. public static BsonWriter Create(BsonDocument document)
  139. {
  140. return Create(document, BsonDocumentWriterSettings.Defaults);
  141. }
  142. /// <summary>
  143. /// Creates a BsonWriter to a BsonDocument.
  144. /// </summary>
  145. /// <param name="document">A BsonDocument.</param>
  146. /// <param name="settings">The settings.</param>
  147. /// <returns>A BsonWriter.</returns>
  148. public static BsonWriter Create(BsonDocument document, BsonDocumentWriterSettings settings)
  149. {
  150. return new BsonDocumentWriter(document, settings);
  151. }
  152. /// <summary>
  153. /// Creates a BsonWriter to a BSON Stream.
  154. /// </summary>
  155. /// <param name="stream">A Stream.</param>
  156. /// <returns>A BsonWriter.</returns>
  157. public static BsonWriter Create(Stream stream)
  158. {
  159. return Create(stream, BsonBinaryWriterSettings.Defaults);
  160. }
  161. /// <summary>
  162. /// Creates a BsonWriter to a BSON Stream.
  163. /// </summary>
  164. /// <param name="stream">A Stream.</param>
  165. /// <param name="settings">Optional BsonBinaryWriterSettings.</param>
  166. /// <returns>A BsonWriter.</returns>
  167. public static BsonWriter Create(Stream stream, BsonBinaryWriterSettings settings)
  168. {
  169. return new BsonBinaryWriter(stream, null, settings);
  170. }
  171. /// <summary>
  172. /// Creates a BsonWriter to a JSON TextWriter.
  173. /// </summary>
  174. /// <param name="writer">A TextWriter.</param>
  175. /// <returns>A BsonWriter.</returns>
  176. public static BsonWriter Create(TextWriter writer)
  177. {
  178. return new JsonWriter(writer, JsonWriterSettings.Defaults);
  179. }
  180. /// <summary>
  181. /// Creates a BsonWriter to a JSON TextWriter.
  182. /// </summary>
  183. /// <param name="writer">A TextWriter.</param>
  184. /// <param name="settings">Optional JsonWriterSettings.</param>
  185. /// <returns>A BsonWriter.</returns>
  186. public static BsonWriter Create(TextWriter writer, JsonWriterSettings settings)
  187. {
  188. return new JsonWriter(writer, settings);
  189. }
  190. // public methods
  191. /// <summary>
  192. /// Closes the writer.
  193. /// </summary>
  194. public abstract void Close();
  195. /// <summary>
  196. /// Disposes of any resources used by the writer.
  197. /// </summary>
  198. public void Dispose()
  199. {
  200. if (!_disposed)
  201. {
  202. Dispose(true);
  203. _disposed = true;
  204. }
  205. }
  206. /// <summary>
  207. /// Flushes any pending data to the output destination.
  208. /// </summary>
  209. public abstract void Flush();
  210. /// <summary>
  211. /// Writes BSON binary data to the writer.
  212. /// </summary>
  213. /// <param name="binaryData">The binary data.</param>
  214. public abstract void WriteBinaryData(BsonBinaryData binaryData);
  215. /// <summary>
  216. /// Writes a BSON binary data element to the writer.
  217. /// </summary>
  218. /// <param name="bytes">The binary data.</param>
  219. /// <param name="subType">The binary data subtype.</param>
  220. [Obsolete("Use WriteBinaryData(BsonBinaryData binaryData) instead.")]
  221. public void WriteBinaryData(byte[] bytes, BsonBinarySubType subType)
  222. {
  223. var guidRepresentation = (subType == BsonBinarySubType.UuidStandard) ? GuidRepresentation.Standard : GuidRepresentation.Unspecified;
  224. WriteBinaryData(bytes, subType, guidRepresentation);
  225. }
  226. /// <summary>
  227. /// Writes BSON binary data to the writer.
  228. /// </summary>
  229. /// <param name="bytes">The binary data.</param>
  230. /// <param name="subType">The binary data subtype.</param>
  231. /// <param name="guidRepresentation">The respresentation for Guids.</param>
  232. [Obsolete("Use WriteBinaryData(BsonBinaryData binaryData) instead.")]
  233. public void WriteBinaryData(
  234. byte[] bytes,
  235. BsonBinarySubType subType,
  236. GuidRepresentation guidRepresentation)
  237. {
  238. var binaryData = new BsonBinaryData(bytes, subType, guidRepresentation);
  239. WriteBinaryData(binaryData);
  240. }
  241. /// <summary>
  242. /// Writes a BSON binary data element to the writer.
  243. /// </summary>
  244. /// <param name="name">The name of the element.</param>
  245. /// <param name="binaryData">The binary data.</param>
  246. public void WriteBinaryData(string name, BsonBinaryData binaryData)
  247. {
  248. WriteName(name);
  249. WriteBinaryData(binaryData);
  250. }
  251. /// <summary>
  252. /// Writes a BSON binary data element to the writer.
  253. /// </summary>
  254. /// <param name="name">The name of the element.</param>
  255. /// <param name="bytes">The binary data.</param>
  256. /// <param name="subType">The binary data subtype.</param>
  257. [Obsolete("Use WriteBinaryData(string name, BsonBinaryData binaryData) instead.")]
  258. public void WriteBinaryData(string name, byte[] bytes, BsonBinarySubType subType)
  259. {
  260. WriteName(name);
  261. WriteBinaryData(bytes, subType);
  262. }
  263. /// <summary>
  264. /// Writes a BSON binary data element to the writer.
  265. /// </summary>
  266. /// <param name="name">The name of the element.</param>
  267. /// <param name="bytes">The binary data.</param>
  268. /// <param name="subType">The binary data subtype.</param>
  269. /// <param name="guidRepresentation">The representation for Guids.</param>
  270. [Obsolete("Use WriteBinaryData(string name, BsonBinaryData binaryData) instead.")]
  271. public void WriteBinaryData(
  272. string name,
  273. byte[] bytes,
  274. BsonBinarySubType subType,
  275. GuidRepresentation guidRepresentation)
  276. {
  277. WriteName(name);
  278. WriteBinaryData(bytes, subType, guidRepresentation);
  279. }
  280. /// <summary>
  281. /// Writes a BSON Boolean to the writer.
  282. /// </summary>
  283. /// <param name="value">The Boolean value.</param>
  284. public abstract void WriteBoolean(bool value);
  285. /// <summary>
  286. /// Writes a BSON Boolean element to the writer.
  287. /// </summary>
  288. /// <param name="name">The name of the element.</param>
  289. /// <param name="value">The Boolean value.</param>
  290. public void WriteBoolean(string name, bool value)
  291. {
  292. WriteName(name);
  293. WriteBoolean(value);
  294. }
  295. /// <summary>
  296. /// Writes BSON binary data to the writer.
  297. /// </summary>
  298. /// <param name="bytes">The bytes.</param>
  299. public abstract void WriteBytes(byte[] bytes);
  300. /// <summary>
  301. /// Writes a BSON binary data element to the writer.
  302. /// </summary>
  303. /// <param name="name">The name of the element.</param>
  304. /// <param name="bytes">The bytes.</param>
  305. public void WriteBytes(string name, byte[] bytes)
  306. {
  307. WriteName(name);
  308. WriteBytes(bytes);
  309. }
  310. /// <summary>
  311. /// Writes a BSON DateTime to the writer.
  312. /// </summary>
  313. /// <param name="value">The number of milliseconds since the Unix epoch.</param>
  314. public abstract void WriteDateTime(long value);
  315. /// <summary>
  316. /// Writes a BSON DateTime element to the writer.
  317. /// </summary>
  318. /// <param name="name">The name of the element.</param>
  319. /// <param name="value">The number of milliseconds since the Unix epoch.</param>
  320. public void WriteDateTime(string name, long value)
  321. {
  322. WriteName(name);
  323. WriteDateTime(value);
  324. }
  325. /// <summary>
  326. /// Writes a BSON Double to the writer.
  327. /// </summary>
  328. /// <param name="value">The Double value.</param>
  329. public abstract void WriteDouble(double value);
  330. /// <summary>
  331. /// Writes a BSON Double element to the writer.
  332. /// </summary>
  333. /// <param name="name">The name of the element.</param>
  334. /// <param name="value">The Double value.</param>
  335. public void WriteDouble(string name, double value)
  336. {
  337. WriteName(name);
  338. WriteDouble(value);
  339. }
  340. /// <summary>
  341. /// Writes the end of a BSON array to the writer.
  342. /// </summary>
  343. public virtual void WriteEndArray()
  344. {
  345. _serializationDepth--;
  346. }
  347. /// <summary>
  348. /// Writes the end of a BSON document to the writer.
  349. /// </summary>
  350. public virtual void WriteEndDocument()
  351. {
  352. _serializationDepth--;
  353. }
  354. /// <summary>
  355. /// Writes a BSON Int32 to the writer.
  356. /// </summary>
  357. /// <param name="value">The Int32 value.</param>
  358. public abstract void WriteInt32(int value);
  359. /// <summary>
  360. /// Writes a BSON Int32 element to the writer.
  361. /// </summary>
  362. /// <param name="name">The name of the element.</param>
  363. /// <param name="value">The Int32 value.</param>
  364. public void WriteInt32(string name, int value)
  365. {
  366. WriteName(name);
  367. WriteInt32(value);
  368. }
  369. /// <summary>
  370. /// Writes a BSON Int64 to the writer.
  371. /// </summary>
  372. /// <param name="value">The Int64 value.</param>
  373. public abstract void WriteInt64(long value);
  374. /// <summary>
  375. /// Writes a BSON Int64 element to the writer.
  376. /// </summary>
  377. /// <param name="name">The name of the element.</param>
  378. /// <param name="value">The Int64 value.</param>
  379. public void WriteInt64(string name, long value)
  380. {
  381. WriteName(name);
  382. WriteInt64(value);
  383. }
  384. /// <summary>
  385. /// Writes a BSON JavaScript to the writer.
  386. /// </summary>
  387. /// <param name="code">The JavaScript code.</param>
  388. public abstract void WriteJavaScript(string code);
  389. /// <summary>
  390. /// Writes a BSON JavaScript element to the writer.
  391. /// </summary>
  392. /// <param name="name">The name of the element.</param>
  393. /// <param name="code">The JavaScript code.</param>
  394. public void WriteJavaScript(string name, string code)
  395. {
  396. WriteName(name);
  397. WriteJavaScript(code);
  398. }
  399. /// <summary>
  400. /// Writes a BSON JavaScript to the writer (call WriteStartDocument to start writing the scope).
  401. /// </summary>
  402. /// <param name="code">The JavaScript code.</param>
  403. public abstract void WriteJavaScriptWithScope(string code);
  404. /// <summary>
  405. /// Writes a BSON JavaScript element to the writer (call WriteStartDocument to start writing the scope).
  406. /// </summary>
  407. /// <param name="name">The name of the element.</param>
  408. /// <param name="code">The JavaScript code.</param>
  409. public void WriteJavaScriptWithScope(string name, string code)
  410. {
  411. WriteName(name);
  412. WriteJavaScriptWithScope(code);
  413. }
  414. /// <summary>
  415. /// Writes a BSON MaxKey to the writer.
  416. /// </summary>
  417. public abstract void WriteMaxKey();
  418. /// <summary>
  419. /// Writes a BSON MaxKey element to the writer.
  420. /// </summary>
  421. /// <param name="name">The name of the element.</param>
  422. public void WriteMaxKey(string name)
  423. {
  424. WriteName(name);
  425. WriteMaxKey();
  426. }
  427. /// <summary>
  428. /// Writes a BSON MinKey to the writer.
  429. /// </summary>
  430. public abstract void WriteMinKey();
  431. /// <summary>
  432. /// Writes a BSON MinKey element to the writer.
  433. /// </summary>
  434. /// <param name="name">The name of the element.</param>
  435. public void WriteMinKey(string name)
  436. {
  437. WriteName(name);
  438. WriteMinKey();
  439. }
  440. /// <summary>
  441. /// Writes the name of an element to the writer.
  442. /// </summary>
  443. /// <param name="name">The name of the element.</param>
  444. public virtual void WriteName(string name)
  445. {
  446. if (name == null)
  447. {
  448. throw new ArgumentNullException("name");
  449. }
  450. if (name.IndexOf('\0') != -1)
  451. {
  452. throw new ArgumentException("Element names cannot contain nulls.", "name");
  453. }
  454. if (_disposed) { throw new ObjectDisposedException(this.GetType().Name); }
  455. if (_state != BsonWriterState.Name)
  456. {
  457. ThrowInvalidState("WriteName", BsonWriterState.Name);
  458. }
  459. CheckElementName(name);
  460. _name = name;
  461. _state = BsonWriterState.Value;
  462. }
  463. /// <summary>
  464. /// Writes a BSON null to the writer.
  465. /// </summary>
  466. public abstract void WriteNull();
  467. /// <summary>
  468. /// Writes a BSON null element to the writer.
  469. /// </summary>
  470. /// <param name="name">The name of the element.</param>
  471. public void WriteNull(string name)
  472. {
  473. WriteName(name);
  474. WriteNull();
  475. }
  476. /// <summary>
  477. /// Writes a BSON ObjectId to the writer.
  478. /// </summary>
  479. /// <param name="objectId">The ObjectId.</param>
  480. public abstract void WriteObjectId(ObjectId objectId);
  481. /// <summary>
  482. /// Writes a BSON ObjectId to the writer.
  483. /// </summary>
  484. /// <param name="timestamp">The timestamp.</param>
  485. /// <param name="machine">The machine hash.</param>
  486. /// <param name="pid">The PID.</param>
  487. /// <param name="increment">The increment.</param>
  488. [Obsolete("Use WriteObjectId(ObjectId objectId) instead.")]
  489. public void WriteObjectId(int timestamp, int machine, short pid, int increment)
  490. {
  491. var objectId = new ObjectId(timestamp, machine, pid, increment);
  492. WriteObjectId(objectId);
  493. }
  494. /// <summary>
  495. /// Writes a BSON ObjectId element to the writer.
  496. /// </summary>
  497. /// <param name="name">The name of the element.</param>
  498. /// <param name="objectId">The ObjectId.</param>
  499. public void WriteObjectId(string name, ObjectId objectId)
  500. {
  501. WriteName(name);
  502. WriteObjectId(objectId);
  503. }
  504. /// <summary>
  505. /// Writes a BSON ObjectId element to the writer.
  506. /// </summary>
  507. /// <param name="name">The name of the element.</param>
  508. /// <param name="timestamp">The timestamp.</param>
  509. /// <param name="machine">The machine hash.</param>
  510. /// <param name="pid">The PID.</param>
  511. /// <param name="increment">The increment.</param>
  512. [Obsolete("Use WriteObjectId(string name, ObjectId objectId) instead.")]
  513. public void WriteObjectId(string name, int timestamp, int machine, short pid, int increment)
  514. {
  515. WriteName(name);
  516. WriteObjectId(timestamp, machine, pid, increment);
  517. }
  518. /// <summary>
  519. /// Writes a raw BSON array.
  520. /// </summary>
  521. /// <param name="slice">The byte buffer containing the raw BSON array.</param>
  522. public virtual void WriteRawBsonArray(IByteBuffer slice)
  523. {
  524. // overridden in BsonBinaryWriter
  525. using (var bsonBuffer = new BsonBuffer())
  526. {
  527. BsonArray array;
  528. // wrap the array in a fake document so we can deserialize it
  529. var arrayLength = slice.Length;
  530. var documentLength = arrayLength + 8;
  531. bsonBuffer.WriteInt32(documentLength);
  532. bsonBuffer.WriteByte((byte)BsonType.Array);
  533. bsonBuffer.WriteByte((byte)'x');
  534. bsonBuffer.WriteByte((byte)0);
  535. bsonBuffer.ByteBuffer.WriteBytes(slice);
  536. bsonBuffer.WriteByte((byte)0);
  537. bsonBuffer.Position = 0;
  538. using (var bsonReader = new BsonBinaryReader(bsonBuffer, true, BsonBinaryReaderSettings.Defaults))
  539. {
  540. bsonReader.ReadStartDocument();
  541. bsonReader.ReadName("x");
  542. array = (BsonArray)BsonArraySerializer.Instance.Deserialize(bsonReader, typeof(BsonArray), null);
  543. bsonReader.ReadEndDocument();
  544. }
  545. BsonArraySerializer.Instance.Serialize(this, typeof(BsonArray), array, null);
  546. }
  547. }
  548. /// <summary>
  549. /// Writes a raw BSON array.
  550. /// </summary>
  551. /// <param name="name">The name.</param>
  552. /// <param name="slice">The byte buffer containing the raw BSON array.</param>
  553. public void WriteRawBsonArray(string name, IByteBuffer slice)
  554. {
  555. WriteName(name);
  556. WriteRawBsonArray(slice);
  557. }
  558. /// <summary>
  559. /// Writes a raw BSON document.
  560. /// </summary>
  561. /// <param name="slice">The byte buffer containing the raw BSON document.</param>
  562. public virtual void WriteRawBsonDocument(IByteBuffer slice)
  563. {
  564. // overridden in BsonBinaryWriter
  565. using (var bsonReader = new BsonBinaryReader(new BsonBuffer(slice, false), true, BsonBinaryReaderSettings.Defaults))
  566. {
  567. var document = BsonSerializer.Deserialize<BsonDocument>(bsonReader);
  568. BsonDocumentSerializer.Instance.Serialize(this, typeof(BsonDocument), document, null);
  569. }
  570. }
  571. /// <summary>
  572. /// Writes a raw BSON document.
  573. /// </summary>
  574. /// <param name="name">The name.</param>
  575. /// <param name="slice">The byte buffer containing the raw BSON document.</param>
  576. public void WriteRawBsonDocument(string name, IByteBuffer slice)
  577. {
  578. WriteName(name);
  579. WriteRawBsonDocument(slice);
  580. }
  581. /// <summary>
  582. /// Writes a BSON regular expression to the writer.
  583. /// </summary>
  584. /// <param name="regex">A BsonRegularExpression.</param>
  585. public abstract void WriteRegularExpression(BsonRegularExpression regex);
  586. /// <summary>
  587. /// Writes a BSON regular expression to the writer.
  588. /// </summary>
  589. /// <param name="pattern">A regular expression pattern.</param>
  590. /// <param name="options">A regular expression options.</param>
  591. [Obsolete("Use WriteRegularExpression(BsonRegularExpression regex) instead.")]
  592. public void WriteRegularExpression(string pattern, string options)
  593. {
  594. var regex = new BsonRegularExpression(pattern, options);
  595. WriteRegularExpression(regex);
  596. }
  597. /// <summary>
  598. /// Writes a BSON regular expression element to the writer.
  599. /// </summary>
  600. /// <param name="name">The name of the element.</param>
  601. /// <param name="regex">A BsonRegularExpression.</param>
  602. public void WriteRegularExpression(string name, BsonRegularExpression regex)
  603. {
  604. WriteName(name);
  605. WriteRegularExpression(regex);
  606. }
  607. /// <summary>
  608. /// Writes a BSON regular expression element to the writer.
  609. /// </summary>
  610. /// <param name="name">The name of the element.</param>
  611. /// <param name="pattern">A regular expression pattern.</param>
  612. /// <param name="options">A regular expression options.</param>
  613. [Obsolete("Use WriteRegularExpression(string name, BsonRegularExpression regex) instead.")]
  614. public void WriteRegularExpression(string name, string pattern, string options)
  615. {
  616. WriteName(name);
  617. WriteRegularExpression(pattern, options);
  618. }
  619. /// <summary>
  620. /// Writes the start of a BSON array to the writer.
  621. /// </summary>
  622. public virtual void WriteStartArray()
  623. {
  624. _serializationDepth++;
  625. if (_serializationDepth > _settings.MaxSerializationDepth)
  626. {
  627. throw new BsonSerializationException("Maximum serialization depth exceeded (does the object being serialized have a circular reference?).");
  628. }
  629. }
  630. /// <summary>
  631. /// Writes the start of a BSON array element to the writer.
  632. /// </summary>
  633. /// <param name="name">The name of the element.</param>
  634. public void WriteStartArray(string name)
  635. {
  636. WriteName(name);
  637. WriteStartArray();
  638. }
  639. /// <summary>
  640. /// Writes the start of a BSON document to the writer.
  641. /// </summary>
  642. public virtual void WriteStartDocument()
  643. {
  644. _serializationDepth++;
  645. if (_serializationDepth > _settings.MaxSerializationDepth)
  646. {
  647. throw new BsonSerializationException("Maximum serialization depth exceeded (does the object being serialized have a circular reference?).");
  648. }
  649. }
  650. /// <summary>
  651. /// Writes the start of a BSON document element to the writer.
  652. /// </summary>
  653. /// <param name="name">The name of the element.</param>
  654. public void WriteStartDocument(string name)
  655. {
  656. WriteName(name);
  657. WriteStartDocument();
  658. }
  659. /// <summary>
  660. /// Writes a BSON String to the writer.
  661. /// </summary>
  662. /// <param name="value">The String value.</param>
  663. public abstract void WriteString(string value);
  664. /// <summary>
  665. /// Writes a BSON String element to the writer.
  666. /// </summary>
  667. /// <param name="name">The name of the element.</param>
  668. /// <param name="value">The String value.</param>
  669. public void WriteString(string name, string value)
  670. {
  671. WriteName(name);
  672. WriteString(value);
  673. }
  674. /// <summary>
  675. /// Writes a BSON Symbol to the writer.
  676. /// </summary>
  677. /// <param name="value">The symbol.</param>
  678. public abstract void WriteSymbol(string value);
  679. /// <summary>
  680. /// Writes a BSON Symbol element to the writer.
  681. /// </summary>
  682. /// <param name="name">The name of the element.</param>
  683. /// <param name="value">The symbol.</param>
  684. public void WriteSymbol(string name, string value)
  685. {
  686. WriteName(name);
  687. WriteSymbol(value);
  688. }
  689. /// <summary>
  690. /// Writes a BSON timestamp to the writer.
  691. /// </summary>
  692. /// <param name="value">The combined timestamp/increment value.</param>
  693. public abstract void WriteTimestamp(long value);
  694. /// <summary>
  695. /// Writes a BSON timestamp element to the writer.
  696. /// </summary>
  697. /// <param name="name">The name of the element.</param>
  698. /// <param name="value">The combined timestamp/increment value.</param>
  699. public void WriteTimestamp(string name, long value)
  700. {
  701. WriteName(name);
  702. WriteTimestamp(value);
  703. }
  704. /// <summary>
  705. /// Writes a BSON undefined to the writer.
  706. /// </summary>
  707. public abstract void WriteUndefined();
  708. /// <summary>
  709. /// Writes a BSON undefined element to the writer.
  710. /// </summary>
  711. /// <param name="name">The name of the element.</param>
  712. public void WriteUndefined(string name)
  713. {
  714. WriteName(name);
  715. WriteUndefined();
  716. }
  717. // protected methods
  718. /// <summary>
  719. /// Checks that the element name is valid.
  720. /// </summary>
  721. /// <param name="name">The element name to be checked.</param>
  722. protected void CheckElementName(string name)
  723. {
  724. if (_checkUpdateDocument)
  725. {
  726. _checkElementNames = name == "" || name[0] != '$';
  727. _checkUpdateDocument = false;
  728. return;
  729. }
  730. if (_checkElementNames)
  731. {
  732. if (name == "")
  733. {
  734. var message = "Element name '' is not valid because it is an empty string.";
  735. throw new BsonSerializationException(message);
  736. }
  737. if (name[0] == '$')
  738. {
  739. // a few element names starting with $ have to be allowed for historical reasons
  740. switch (name)
  741. {
  742. case "$code":
  743. case "$db":
  744. case "$id":
  745. case "$ref":
  746. case "$scope":
  747. break;
  748. default:
  749. var message = string.Format("Element name '{0}' is not valid because it starts with a '$'.", name);
  750. throw new BsonSerializationException(message);
  751. }
  752. }
  753. if (name.IndexOf('.') != -1)
  754. {
  755. var message = string.Format("Element name '{0}' is not valid because it contains a '.'.", name);
  756. throw new BsonSerializationException(message);
  757. }
  758. }
  759. }
  760. /// <summary>
  761. /// Disposes of any resources used by the writer.
  762. /// </summary>
  763. /// <param name="disposing">True if called from Dispose.</param>
  764. protected virtual void Dispose(bool disposing)
  765. {
  766. }
  767. /// <summary>
  768. /// Throws an InvalidOperationException when the method called is not valid for the current ContextType.
  769. /// </summary>
  770. /// <param name="methodName">The name of the method.</param>
  771. /// <param name="actualContextType">The actual ContextType.</param>
  772. /// <param name="validContextTypes">The valid ContextTypes.</param>
  773. protected void ThrowInvalidContextType(
  774. string methodName,
  775. ContextType actualContextType,
  776. params ContextType[] validContextTypes)
  777. {
  778. var validContextTypesString = string.Join(" or ", validContextTypes.Select(c => c.ToString()).ToArray());
  779. var message = string.Format(
  780. "{0} can only be called when ContextType is {1}, not when ContextType is {2}.",
  781. methodName, validContextTypesString, actualContextType);
  782. throw new InvalidOperationException(message);
  783. }
  784. /// <summary>
  785. /// Throws an InvalidOperationException when the method called is not valid for the current state.
  786. /// </summary>
  787. /// <param name="methodName">The name of the method.</param>
  788. /// <param name="validStates">The valid states.</param>
  789. protected void ThrowInvalidState(string methodName, params BsonWriterState[] validStates)
  790. {
  791. string message;
  792. if (_state == BsonWriterState.Initial || _state == BsonWriterState.ScopeDocument || _state == BsonWriterState.Done)
  793. {
  794. if (!methodName.StartsWith("End", StringComparison.Ordinal) && methodName != "WriteName")
  795. {
  796. var typeName = methodName.Substring(5);
  797. if (typeName.StartsWith("Start", StringComparison.Ordinal))
  798. {
  799. typeName = typeName.Substring(5);
  800. }
  801. var article = "A";
  802. if (new char[] { 'A', 'E', 'I', 'O', 'U' }.Contains(typeName[0]))
  803. {
  804. article = "An";
  805. }
  806. message = string.Format(
  807. "{0} {1} value cannot be written to the root level of a BSON document.",
  808. article, typeName);
  809. throw new InvalidOperationException(message);
  810. }
  811. }
  812. var validStatesString = string.Join(" or ", validStates.Select(s => s.ToString()).ToArray());
  813. message = string.Format(
  814. "{0} can only be called when State is {1}, not when State is {2}",
  815. methodName, validStatesString, _state);
  816. throw new InvalidOperationException(message);
  817. }
  818. }
  819. }