BsonBinaryWriter.cs 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763
  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. using System.Collections.Generic;
  17. using System.IO;
  18. namespace MongoDB.Bson.IO
  19. {
  20. /// <summary>
  21. /// Represents a BSON writer to a BSON Stream.
  22. /// </summary>
  23. public class BsonBinaryWriter : BsonWriter
  24. {
  25. // private fields
  26. private readonly Stream _baseStream;
  27. private readonly BsonStream _bsonStream;
  28. private readonly BsonBinaryWriterSettings _settings; // same value as in base class just declared as derived class
  29. private readonly Stack<int> _maxDocumentSizeStack = new Stack<int>();
  30. private BsonBinaryWriterContext _context;
  31. // constructors
  32. /// <summary>
  33. /// Initializes a new instance of the BsonBinaryWriter class.
  34. /// </summary>
  35. /// <param name="stream">A stream. The BsonBinaryWriter does not own the stream and will not Dispose it.</param>
  36. public BsonBinaryWriter(Stream stream)
  37. : this(stream, BsonBinaryWriterSettings.Defaults)
  38. {
  39. }
  40. /// <summary>
  41. /// Initializes a new instance of the BsonBinaryWriter class.
  42. /// </summary>
  43. /// <param name="stream">A stream. The BsonBinaryWriter does not own the stream and will not Dispose it.</param>
  44. /// <param name="settings">The BsonBinaryWriter settings.</param>
  45. public BsonBinaryWriter(Stream stream, BsonBinaryWriterSettings settings)
  46. : base(settings)
  47. {
  48. if (stream == null)
  49. {
  50. throw new ArgumentNullException("stream");
  51. }
  52. if (!stream.CanSeek)
  53. {
  54. throw new ArgumentException("The stream must be capable of seeking.", "stream");
  55. }
  56. _baseStream = stream;
  57. _bsonStream = (stream as BsonStream) ?? new BsonStreamAdapter(stream);
  58. _settings = settings; // already frozen by base class
  59. _maxDocumentSizeStack.Push(_settings.MaxDocumentSize);
  60. _context = null;
  61. State = BsonWriterState.Initial;
  62. }
  63. // public properties
  64. /// <summary>
  65. /// Gets the base stream.
  66. /// </summary>
  67. /// <value>
  68. /// The base stream.
  69. /// </value>
  70. public Stream BaseStream
  71. {
  72. get { return _baseStream; }
  73. }
  74. /// <summary>
  75. /// Gets the BSON stream.
  76. /// </summary>
  77. /// <value>
  78. /// The BSON stream.
  79. /// </value>
  80. public BsonStream BsonStream
  81. {
  82. get { return _bsonStream; }
  83. }
  84. // public methods
  85. /// <summary>
  86. /// Closes the writer. Also closes the base stream.
  87. /// </summary>
  88. public override void Close()
  89. {
  90. // Close can be called on Disposed objects
  91. if (State != BsonWriterState.Closed)
  92. {
  93. if (State == BsonWriterState.Done)
  94. {
  95. Flush();
  96. }
  97. _context = null;
  98. State = BsonWriterState.Closed;
  99. }
  100. }
  101. /// <summary>
  102. /// Flushes any pending data to the output destination.
  103. /// </summary>
  104. public override void Flush()
  105. {
  106. if (Disposed) { throw new ObjectDisposedException("BsonBinaryWriter"); }
  107. if (State == BsonWriterState.Closed)
  108. {
  109. throw new InvalidOperationException("Flush called on closed BsonWriter.");
  110. }
  111. if (State != BsonWriterState.Done)
  112. {
  113. throw new InvalidOperationException("Flush called before BsonBinaryWriter was finished writing to buffer.");
  114. }
  115. _bsonStream.Flush();
  116. }
  117. /// <summary>
  118. /// Pops the max document size stack, restoring the previous max document size.
  119. /// </summary>
  120. public void PopMaxDocumentSize()
  121. {
  122. _maxDocumentSizeStack.Pop();
  123. }
  124. /// <summary>
  125. /// Pushes a new max document size onto the max document size stack.
  126. /// </summary>
  127. /// <param name="maxDocumentSize">The maximum size of the document.</param>
  128. public void PushMaxDocumentSize(int maxDocumentSize)
  129. {
  130. _maxDocumentSizeStack.Push(Math.Min(maxDocumentSize, _maxDocumentSizeStack.Peek()));
  131. }
  132. #pragma warning disable 618 // about obsolete BsonBinarySubType.OldBinary
  133. /// <summary>
  134. /// Writes BSON binary data to the writer.
  135. /// </summary>
  136. /// <param name="binaryData">The binary data.</param>
  137. public override void WriteBinaryData(BsonBinaryData binaryData)
  138. {
  139. if (Disposed) { throw new ObjectDisposedException("BsonBinaryWriter"); }
  140. if (State != BsonWriterState.Value)
  141. {
  142. ThrowInvalidState("WriteBinaryData", BsonWriterState.Value);
  143. }
  144. var bytes = binaryData.Bytes;
  145. var subType = binaryData.SubType;
  146. var guidRepresentation = binaryData.GuidRepresentation;
  147. switch (subType)
  148. {
  149. case BsonBinarySubType.OldBinary:
  150. if (_settings.FixOldBinarySubTypeOnOutput)
  151. {
  152. subType = BsonBinarySubType.Binary; // replace obsolete OldBinary with new Binary sub type
  153. }
  154. break;
  155. case BsonBinarySubType.UuidLegacy:
  156. case BsonBinarySubType.UuidStandard:
  157. if (_settings.GuidRepresentation != GuidRepresentation.Unspecified)
  158. {
  159. var expectedSubType = (_settings.GuidRepresentation == GuidRepresentation.Standard) ? BsonBinarySubType.UuidStandard : BsonBinarySubType.UuidLegacy;
  160. if (subType != expectedSubType)
  161. {
  162. var message = string.Format(
  163. "The GuidRepresentation for the writer is {0}, which requires the subType argument to be {1}, not {2}.",
  164. _settings.GuidRepresentation, expectedSubType, subType);
  165. throw new BsonSerializationException(message);
  166. }
  167. if (guidRepresentation != _settings.GuidRepresentation)
  168. {
  169. var message = string.Format(
  170. "The GuidRepresentation for the writer is {0}, which requires the the guidRepresentation argument to also be {0}, not {1}.",
  171. _settings.GuidRepresentation, guidRepresentation);
  172. throw new BsonSerializationException(message);
  173. }
  174. }
  175. break;
  176. }
  177. _bsonStream.WriteBsonType(BsonType.Binary);
  178. WriteNameHelper();
  179. if (subType == BsonBinarySubType.OldBinary)
  180. {
  181. // sub type OldBinary has two sizes (for historical reasons)
  182. _bsonStream.WriteInt32(bytes.Length + 4);
  183. _bsonStream.WriteBinarySubType(subType);
  184. _bsonStream.WriteInt32(bytes.Length);
  185. }
  186. else
  187. {
  188. _bsonStream.WriteInt32(bytes.Length);
  189. _bsonStream.WriteBinarySubType(subType);
  190. }
  191. _bsonStream.WriteBytes(bytes, 0, bytes.Length);
  192. State = GetNextState();
  193. }
  194. #pragma warning restore 618
  195. /// <summary>
  196. /// Writes a BSON Boolean to the writer.
  197. /// </summary>
  198. /// <param name="value">The Boolean value.</param>
  199. public override void WriteBoolean(bool value)
  200. {
  201. if (Disposed) { throw new ObjectDisposedException("BsonBinaryWriter"); }
  202. if (State != BsonWriterState.Value)
  203. {
  204. ThrowInvalidState("WriteBoolean", BsonWriterState.Value);
  205. }
  206. _bsonStream.WriteBsonType(BsonType.Boolean);
  207. WriteNameHelper();
  208. _bsonStream.WriteBoolean(value);
  209. State = GetNextState();
  210. }
  211. /// <summary>
  212. /// Writes BSON binary data to the writer.
  213. /// </summary>
  214. /// <param name="bytes">The bytes.</param>
  215. public override void WriteBytes(byte[] bytes)
  216. {
  217. if (Disposed) { throw new ObjectDisposedException("BsonBinaryWriter"); }
  218. if (State != BsonWriterState.Value)
  219. {
  220. ThrowInvalidState("WriteBytes", BsonWriterState.Value);
  221. }
  222. _bsonStream.WriteBsonType(BsonType.Binary);
  223. WriteNameHelper();
  224. _bsonStream.WriteInt32(bytes.Length);
  225. _bsonStream.WriteBinarySubType(BsonBinarySubType.Binary);
  226. _bsonStream.WriteBytes(bytes, 0, bytes.Length);
  227. State = GetNextState();
  228. }
  229. /// <summary>
  230. /// Writes a BSON DateTime to the writer.
  231. /// </summary>
  232. /// <param name="value">The number of milliseconds since the Unix epoch.</param>
  233. public override void WriteDateTime(long value)
  234. {
  235. if (Disposed) { throw new ObjectDisposedException("BsonBinaryWriter"); }
  236. if (State != BsonWriterState.Value)
  237. {
  238. ThrowInvalidState("WriteDateTime", BsonWriterState.Value);
  239. }
  240. _bsonStream.WriteBsonType(BsonType.DateTime);
  241. WriteNameHelper();
  242. _bsonStream.WriteInt64(value);
  243. State = GetNextState();
  244. }
  245. /// <inheritdoc />
  246. public override void WriteDecimal128(Decimal128 value)
  247. {
  248. if (Disposed) { throw new ObjectDisposedException("BsonBinaryWriter"); }
  249. if (State != BsonWriterState.Value)
  250. {
  251. ThrowInvalidState(nameof(WriteDecimal128), BsonWriterState.Value);
  252. }
  253. _bsonStream.WriteBsonType(BsonType.Decimal128);
  254. WriteNameHelper();
  255. _bsonStream.WriteDecimal128(value);
  256. State = GetNextState();
  257. }
  258. /// <summary>
  259. /// Writes a BSON Double to the writer.
  260. /// </summary>
  261. /// <param name="value">The Double value.</param>
  262. public override void WriteDouble(double value)
  263. {
  264. if (Disposed) { throw new ObjectDisposedException("BsonBinaryWriter"); }
  265. if (State != BsonWriterState.Value)
  266. {
  267. ThrowInvalidState("WriteDouble", BsonWriterState.Value);
  268. }
  269. _bsonStream.WriteBsonType(BsonType.Double);
  270. WriteNameHelper();
  271. _bsonStream.WriteDouble(value);
  272. State = GetNextState();
  273. }
  274. /// <summary>
  275. /// Writes the end of a BSON array to the writer.
  276. /// </summary>
  277. public override void WriteEndArray()
  278. {
  279. if (Disposed) { throw new ObjectDisposedException("BsonBinaryWriter"); }
  280. if (State != BsonWriterState.Value)
  281. {
  282. ThrowInvalidState("WriteEndArray", BsonWriterState.Value);
  283. }
  284. if (_context.ContextType != ContextType.Array)
  285. {
  286. ThrowInvalidContextType("WriteEndArray", _context.ContextType, ContextType.Array);
  287. }
  288. base.WriteEndArray();
  289. _bsonStream.WriteByte(0);
  290. BackpatchSize(); // size of document
  291. _context = _context.ParentContext;
  292. State = GetNextState();
  293. }
  294. /// <summary>
  295. /// Writes the end of a BSON document to the writer.
  296. /// </summary>
  297. public override void WriteEndDocument()
  298. {
  299. if (Disposed) { throw new ObjectDisposedException("BsonBinaryWriter"); }
  300. if (State != BsonWriterState.Name)
  301. {
  302. ThrowInvalidState("WriteEndDocument", BsonWriterState.Name);
  303. }
  304. if (_context.ContextType != ContextType.Document && _context.ContextType != ContextType.ScopeDocument)
  305. {
  306. ThrowInvalidContextType("WriteEndDocument", _context.ContextType, ContextType.Document, ContextType.ScopeDocument);
  307. }
  308. base.WriteEndDocument();
  309. _bsonStream.WriteByte(0);
  310. BackpatchSize(); // size of document
  311. _context = _context.ParentContext;
  312. if (_context == null)
  313. {
  314. State = BsonWriterState.Done;
  315. }
  316. else
  317. {
  318. if (_context.ContextType == ContextType.JavaScriptWithScope)
  319. {
  320. BackpatchSize(); // size of the JavaScript with scope value
  321. _context = _context.ParentContext;
  322. }
  323. State = GetNextState();
  324. }
  325. }
  326. /// <summary>
  327. /// Writes a BSON Int32 to the writer.
  328. /// </summary>
  329. /// <param name="value">The Int32 value.</param>
  330. public override void WriteInt32(int value)
  331. {
  332. if (Disposed) { throw new ObjectDisposedException("BsonBinaryWriter"); }
  333. if (State != BsonWriterState.Value)
  334. {
  335. ThrowInvalidState("WriteInt32", BsonWriterState.Value);
  336. }
  337. _bsonStream.WriteBsonType(BsonType.Int32);
  338. WriteNameHelper();
  339. _bsonStream.WriteInt32(value);
  340. State = GetNextState();
  341. }
  342. /// <summary>
  343. /// Writes a BSON Int64 to the writer.
  344. /// </summary>
  345. /// <param name="value">The Int64 value.</param>
  346. public override void WriteInt64(long value)
  347. {
  348. if (Disposed) { throw new ObjectDisposedException("BsonBinaryWriter"); }
  349. if (State != BsonWriterState.Value)
  350. {
  351. ThrowInvalidState("WriteInt64", BsonWriterState.Value);
  352. }
  353. _bsonStream.WriteBsonType(BsonType.Int64);
  354. WriteNameHelper();
  355. _bsonStream.WriteInt64(value);
  356. State = GetNextState();
  357. }
  358. /// <summary>
  359. /// Writes a BSON JavaScript to the writer.
  360. /// </summary>
  361. /// <param name="code">The JavaScript code.</param>
  362. public override void WriteJavaScript(string code)
  363. {
  364. if (Disposed) { throw new ObjectDisposedException("BsonBinaryWriter"); }
  365. if (State != BsonWriterState.Value)
  366. {
  367. ThrowInvalidState("WriteJavaScript", BsonWriterState.Value);
  368. }
  369. _bsonStream.WriteBsonType(BsonType.JavaScript);
  370. WriteNameHelper();
  371. _bsonStream.WriteString(code, _settings.Encoding);
  372. State = GetNextState();
  373. }
  374. /// <summary>
  375. /// Writes a BSON JavaScript to the writer (call WriteStartDocument to start writing the scope).
  376. /// </summary>
  377. /// <param name="code">The JavaScript code.</param>
  378. public override void WriteJavaScriptWithScope(string code)
  379. {
  380. if (Disposed) { throw new ObjectDisposedException("BsonBinaryWriter"); }
  381. if (State != BsonWriterState.Value)
  382. {
  383. ThrowInvalidState("WriteJavaScriptWithScope", BsonWriterState.Value);
  384. }
  385. _bsonStream.WriteBsonType(BsonType.JavaScriptWithScope);
  386. WriteNameHelper();
  387. _context = new BsonBinaryWriterContext(_context, ContextType.JavaScriptWithScope, _bsonStream.Position);
  388. _bsonStream.WriteInt32(0); // reserve space for size of JavaScript with scope value
  389. _bsonStream.WriteString(code, _settings.Encoding);
  390. State = BsonWriterState.ScopeDocument;
  391. }
  392. /// <summary>
  393. /// Writes a BSON MaxKey to the writer.
  394. /// </summary>
  395. public override void WriteMaxKey()
  396. {
  397. if (Disposed) { throw new ObjectDisposedException("BsonBinaryWriter"); }
  398. if (State != BsonWriterState.Value)
  399. {
  400. ThrowInvalidState("WriteMaxKey", BsonWriterState.Value);
  401. }
  402. _bsonStream.WriteBsonType(BsonType.MaxKey);
  403. WriteNameHelper();
  404. State = GetNextState();
  405. }
  406. /// <summary>
  407. /// Writes a BSON MinKey to the writer.
  408. /// </summary>
  409. public override void WriteMinKey()
  410. {
  411. if (Disposed) { throw new ObjectDisposedException("BsonBinaryWriter"); }
  412. if (State != BsonWriterState.Value)
  413. {
  414. ThrowInvalidState("WriteMinKey", BsonWriterState.Value);
  415. }
  416. _bsonStream.WriteBsonType(BsonType.MinKey);
  417. WriteNameHelper();
  418. State = GetNextState();
  419. }
  420. /// <summary>
  421. /// Writes a BSON null to the writer.
  422. /// </summary>
  423. public override void WriteNull()
  424. {
  425. if (Disposed) { throw new ObjectDisposedException("BsonBinaryWriter"); }
  426. if (State != BsonWriterState.Value)
  427. {
  428. ThrowInvalidState("WriteNull", BsonWriterState.Value);
  429. }
  430. _bsonStream.WriteBsonType(BsonType.Null);
  431. WriteNameHelper();
  432. State = GetNextState();
  433. }
  434. /// <summary>
  435. /// Writes a BSON ObjectId to the writer.
  436. /// </summary>
  437. /// <param name="objectId">The ObjectId.</param>
  438. public override void WriteObjectId(ObjectId objectId)
  439. {
  440. if (Disposed) { throw new ObjectDisposedException("BsonBinaryWriter"); }
  441. if (State != BsonWriterState.Value)
  442. {
  443. ThrowInvalidState("WriteObjectId", BsonWriterState.Value);
  444. }
  445. _bsonStream.WriteBsonType(BsonType.ObjectId);
  446. WriteNameHelper();
  447. _bsonStream.WriteObjectId(objectId);
  448. State = GetNextState();
  449. }
  450. /// <summary>
  451. /// Writes a raw BSON array.
  452. /// </summary>
  453. /// <param name="slice">The byte buffer containing the raw BSON array.</param>
  454. public override void WriteRawBsonArray(IByteBuffer slice)
  455. {
  456. if (Disposed) { throw new ObjectDisposedException("BsonBinaryWriter"); }
  457. if (State != BsonWriterState.Value)
  458. {
  459. ThrowInvalidState("WriteRawBsonArray", BsonWriterState.Value);
  460. }
  461. _bsonStream.WriteBsonType(BsonType.Array);
  462. WriteNameHelper();
  463. _bsonStream.WriteSlice(slice); // assumes slice is a valid raw BSON array
  464. State = GetNextState();
  465. }
  466. /// <summary>
  467. /// Writes a raw BSON document.
  468. /// </summary>
  469. /// <param name="slice">The byte buffer containing the raw BSON document.</param>
  470. public override void WriteRawBsonDocument(IByteBuffer slice)
  471. {
  472. if (Disposed) { throw new ObjectDisposedException("BsonBinaryWriter"); }
  473. if (State != BsonWriterState.Initial && State != BsonWriterState.Value && State != BsonWriterState.ScopeDocument && State != BsonWriterState.Done)
  474. {
  475. ThrowInvalidState("WriteRawBsonDocument", BsonWriterState.Initial, BsonWriterState.Value, BsonWriterState.ScopeDocument, BsonWriterState.Done);
  476. }
  477. if (State == BsonWriterState.Value)
  478. {
  479. _bsonStream.WriteBsonType(BsonType.Document);
  480. WriteNameHelper();
  481. }
  482. _bsonStream.WriteSlice(slice); // assumes byteBuffer is a valid raw BSON document
  483. if (_context == null)
  484. {
  485. State = BsonWriterState.Done;
  486. }
  487. else
  488. {
  489. if (_context.ContextType == ContextType.JavaScriptWithScope)
  490. {
  491. BackpatchSize(); // size of the JavaScript with scope value
  492. _context = _context.ParentContext;
  493. }
  494. State = GetNextState();
  495. }
  496. }
  497. /// <summary>
  498. /// Writes a BSON regular expression to the writer.
  499. /// </summary>
  500. /// <param name="regex">A BsonRegularExpression.</param>
  501. public override void WriteRegularExpression(BsonRegularExpression regex)
  502. {
  503. if (Disposed) { throw new ObjectDisposedException("BsonBinaryWriter"); }
  504. if (State != BsonWriterState.Value)
  505. {
  506. ThrowInvalidState("WriteRegularExpression", BsonWriterState.Value);
  507. }
  508. _bsonStream.WriteBsonType(BsonType.RegularExpression);
  509. WriteNameHelper();
  510. _bsonStream.WriteCString(regex.Pattern);
  511. _bsonStream.WriteCString(regex.Options);
  512. State = GetNextState();
  513. }
  514. /// <summary>
  515. /// Writes the start of a BSON array to the writer.
  516. /// </summary>
  517. public override void WriteStartArray()
  518. {
  519. if (Disposed) { throw new ObjectDisposedException("BsonBinaryWriter"); }
  520. if (State != BsonWriterState.Value)
  521. {
  522. ThrowInvalidState("WriteStartArray", BsonWriterState.Value);
  523. }
  524. base.WriteStartArray();
  525. _bsonStream.WriteBsonType(BsonType.Array);
  526. WriteNameHelper();
  527. _context = new BsonBinaryWriterContext(_context, ContextType.Array, _bsonStream.Position);
  528. _bsonStream.WriteInt32(0); // reserve space for size
  529. State = BsonWriterState.Value;
  530. }
  531. /// <summary>
  532. /// Writes the start of a BSON document to the writer.
  533. /// </summary>
  534. public override void WriteStartDocument()
  535. {
  536. if (Disposed) { throw new ObjectDisposedException("BsonBinaryWriter"); }
  537. if (State != BsonWriterState.Initial && State != BsonWriterState.Value && State != BsonWriterState.ScopeDocument && State != BsonWriterState.Done)
  538. {
  539. ThrowInvalidState("WriteStartDocument", BsonWriterState.Initial, BsonWriterState.Value, BsonWriterState.ScopeDocument, BsonWriterState.Done);
  540. }
  541. base.WriteStartDocument();
  542. if (State == BsonWriterState.Value)
  543. {
  544. _bsonStream.WriteBsonType(BsonType.Document);
  545. WriteNameHelper();
  546. }
  547. var contextType = (State == BsonWriterState.ScopeDocument) ? ContextType.ScopeDocument : ContextType.Document;
  548. _context = new BsonBinaryWriterContext(_context, contextType, _bsonStream.Position);
  549. _bsonStream.WriteInt32(0); // reserve space for size
  550. State = BsonWriterState.Name;
  551. }
  552. /// <summary>
  553. /// Writes a BSON String to the writer.
  554. /// </summary>
  555. /// <param name="value">The String value.</param>
  556. public override void WriteString(string value)
  557. {
  558. if (Disposed) { throw new ObjectDisposedException("BsonBinaryWriter"); }
  559. if (State != BsonWriterState.Value)
  560. {
  561. ThrowInvalidState("WriteString", BsonWriterState.Value);
  562. }
  563. _bsonStream.WriteBsonType(BsonType.String);
  564. WriteNameHelper();
  565. _bsonStream.WriteString(value, _settings.Encoding);
  566. State = GetNextState();
  567. }
  568. /// <summary>
  569. /// Writes a BSON Symbol to the writer.
  570. /// </summary>
  571. /// <param name="value">The symbol.</param>
  572. public override void WriteSymbol(string value)
  573. {
  574. if (Disposed) { throw new ObjectDisposedException("BsonBinaryWriter"); }
  575. if (State != BsonWriterState.Value)
  576. {
  577. ThrowInvalidState("WriteSymbol", BsonWriterState.Value);
  578. }
  579. _bsonStream.WriteBsonType(BsonType.Symbol);
  580. WriteNameHelper();
  581. _bsonStream.WriteString(value, _settings.Encoding);
  582. State = GetNextState();
  583. }
  584. /// <summary>
  585. /// Writes a BSON timestamp to the writer.
  586. /// </summary>
  587. /// <param name="value">The combined timestamp/increment value.</param>
  588. public override void WriteTimestamp(long value)
  589. {
  590. if (Disposed) { throw new ObjectDisposedException("BsonBinaryWriter"); }
  591. if (State != BsonWriterState.Value)
  592. {
  593. ThrowInvalidState("WriteTimestamp", BsonWriterState.Value);
  594. }
  595. _bsonStream.WriteBsonType(BsonType.Timestamp);
  596. WriteNameHelper();
  597. _bsonStream.WriteInt64(value);
  598. State = GetNextState();
  599. }
  600. /// <summary>
  601. /// Writes a BSON undefined to the writer.
  602. /// </summary>
  603. public override void WriteUndefined()
  604. {
  605. if (Disposed) { throw new ObjectDisposedException("BsonBinaryWriter"); }
  606. if (State != BsonWriterState.Value)
  607. {
  608. ThrowInvalidState("WriteUndefined", BsonWriterState.Value);
  609. }
  610. _bsonStream.WriteBsonType(BsonType.Undefined);
  611. WriteNameHelper();
  612. State = GetNextState();
  613. }
  614. // protected methods
  615. /// <summary>
  616. /// Disposes of any resources used by the writer.
  617. /// </summary>
  618. /// <param name="disposing">True if called from Dispose.</param>
  619. protected override void Dispose(bool disposing)
  620. {
  621. if (disposing)
  622. {
  623. try
  624. {
  625. Close();
  626. }
  627. catch { } // ignore exceptions
  628. }
  629. base.Dispose(disposing);
  630. }
  631. // private methods
  632. private void BackpatchSize()
  633. {
  634. var size = _bsonStream.Position - _context.StartPosition;
  635. if (size > _maxDocumentSizeStack.Peek())
  636. {
  637. var message = string.Format("Size {0} is larger than MaxDocumentSize {1}.", size, _maxDocumentSizeStack.Peek());
  638. throw new FormatException(message);
  639. }
  640. var currentPosition = _bsonStream.Position;
  641. _bsonStream.Position = _context.StartPosition;
  642. _bsonStream.WriteInt32((int)size);
  643. _bsonStream.Position = currentPosition;
  644. }
  645. private BsonWriterState GetNextState()
  646. {
  647. if (_context.ContextType == ContextType.Array)
  648. {
  649. return BsonWriterState.Value;
  650. }
  651. else
  652. {
  653. return BsonWriterState.Name;
  654. }
  655. }
  656. private void WriteNameHelper()
  657. {
  658. if (_context.ContextType == ContextType.Array)
  659. {
  660. var index = _context.Index++;
  661. var nameBytes = ArrayElementNameAccelerator.Default.GetElementNameBytes(index);
  662. _bsonStream.WriteCStringBytes(nameBytes);
  663. }
  664. else
  665. {
  666. _bsonStream.WriteCString(Name);
  667. }
  668. }
  669. }
  670. }