BsonReader.cs 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959
  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.Serializers;
  19. namespace MongoDB.Bson.IO
  20. {
  21. /// <summary>
  22. /// Represents a BSON reader for some external format (see subclasses).
  23. /// </summary>
  24. public abstract class BsonReader : IDisposable
  25. {
  26. // private fields
  27. private bool _disposed = false;
  28. private BsonReaderSettings _settings;
  29. private BsonReaderState _state;
  30. private BsonType _currentBsonType;
  31. private string _currentName;
  32. // constructors
  33. /// <summary>
  34. /// Initializes a new instance of the BsonReader class.
  35. /// </summary>
  36. /// <param name="settings">The reader settings.</param>
  37. protected BsonReader(BsonReaderSettings settings)
  38. {
  39. if (settings == null)
  40. {
  41. throw new ArgumentNullException("settings");
  42. }
  43. _settings = settings.FrozenCopy();
  44. _state = BsonReaderState.Initial;
  45. }
  46. // public properties
  47. /// <summary>
  48. /// Gets the current BsonType.
  49. /// </summary>
  50. public BsonType CurrentBsonType
  51. {
  52. get { return _currentBsonType; }
  53. protected set { _currentBsonType = value; }
  54. }
  55. /// <summary>
  56. /// Gets the settings of the reader.
  57. /// </summary>
  58. public BsonReaderSettings Settings
  59. {
  60. get { return _settings; }
  61. }
  62. /// <summary>
  63. /// Gets the current state of the reader.
  64. /// </summary>
  65. public BsonReaderState State
  66. {
  67. get { return _state; }
  68. protected set { _state = value; }
  69. }
  70. // protected properties
  71. /// <summary>
  72. /// Gets the current name.
  73. /// </summary>
  74. protected string CurrentName
  75. {
  76. get { return _currentName; }
  77. set { _currentName = value; }
  78. }
  79. /// <summary>
  80. /// Gets whether the BsonReader has been disposed.
  81. /// </summary>
  82. protected bool Disposed
  83. {
  84. get { return _disposed; }
  85. }
  86. // public static methods
  87. /// <summary>
  88. /// Creates a BsonReader for a BsonBuffer.
  89. /// </summary>
  90. /// <param name="buffer">The BsonBuffer.</param>
  91. /// <returns>A BsonReader.</returns>
  92. public static BsonReader Create(BsonBuffer buffer)
  93. {
  94. return Create(buffer, BsonBinaryReaderSettings.Defaults);
  95. }
  96. /// <summary>
  97. /// Creates a BsonReader for a BsonBuffer.
  98. /// </summary>
  99. /// <param name="buffer">The BsonBuffer.</param>
  100. /// <param name="settings">Optional reader settings.</param>
  101. /// <returns>A BsonReader.</returns>
  102. public static BsonReader Create(BsonBuffer buffer, BsonBinaryReaderSettings settings)
  103. {
  104. return new BsonBinaryReader(buffer, false, settings);
  105. }
  106. /// <summary>
  107. /// Creates a BsonReader for a BsonDocument.
  108. /// </summary>
  109. /// <param name="document">The BsonDocument.</param>
  110. /// <returns>A BsonReader.</returns>
  111. public static BsonReader Create(BsonDocument document)
  112. {
  113. return Create(document, BsonDocumentReaderSettings.Defaults);
  114. }
  115. /// <summary>
  116. /// Creates a BsonReader for a BsonDocument.
  117. /// </summary>
  118. /// <param name="document">The BsonDocument.</param>
  119. /// <param name="settings">The settings.</param>
  120. /// <returns>A BsonReader.</returns>
  121. public static BsonReader Create(BsonDocument document, BsonDocumentReaderSettings settings)
  122. {
  123. return new BsonDocumentReader(document, settings);
  124. }
  125. /// <summary>
  126. /// Creates a BsonReader for a JsonBuffer.
  127. /// </summary>
  128. /// <param name="buffer">The buffer.</param>
  129. /// <returns>A BsonReader.</returns>
  130. public static BsonReader Create(JsonBuffer buffer)
  131. {
  132. return Create(buffer, JsonReaderSettings.Defaults);
  133. }
  134. /// <summary>
  135. /// Creates a BsonReader for a JsonBuffer.
  136. /// </summary>
  137. /// <param name="buffer">The buffer.</param>
  138. /// <param name="settings">The settings.</param>
  139. /// <returns>A BsonReader.</returns>
  140. public static BsonReader Create(JsonBuffer buffer, JsonReaderSettings settings)
  141. {
  142. return new JsonReader(buffer, settings);
  143. }
  144. /// <summary>
  145. /// Creates a BsonReader for a BSON Stream.
  146. /// </summary>
  147. /// <param name="stream">The BSON Stream.</param>
  148. /// <returns>A BsonReader.</returns>
  149. public static BsonReader Create(Stream stream)
  150. {
  151. return Create(stream, BsonBinaryReaderSettings.Defaults);
  152. }
  153. /// <summary>
  154. /// Creates a BsonReader for a BSON Stream.
  155. /// </summary>
  156. /// <param name="stream">The BSON Stream.</param>
  157. /// <param name="settings">Optional reader settings.</param>
  158. /// <returns>A BsonReader.</returns>
  159. public static BsonReader Create(Stream stream, BsonBinaryReaderSettings settings)
  160. {
  161. var byteBuffer = ByteBufferFactory.LoadFrom(stream);
  162. byteBuffer.MakeReadOnly();
  163. return new BsonBinaryReader(new BsonBuffer(byteBuffer, true), true, settings);
  164. }
  165. /// <summary>
  166. /// Creates a BsonReader for a JSON string.
  167. /// </summary>
  168. /// <param name="json">The JSON string.</param>
  169. /// <returns>A BsonReader.</returns>
  170. public static BsonReader Create(string json)
  171. {
  172. var buffer = new JsonBuffer(json);
  173. return Create(buffer);
  174. }
  175. /// <summary>
  176. /// Creates a BsonReader for a JSON TextReader.
  177. /// </summary>
  178. /// <param name="textReader">The JSON TextReader.</param>
  179. /// <returns>A BsonReader.</returns>
  180. public static BsonReader Create(TextReader textReader)
  181. {
  182. var json = textReader.ReadToEnd();
  183. return Create(json);
  184. }
  185. // public methods
  186. /// <summary>
  187. /// Closes the reader.
  188. /// </summary>
  189. public abstract void Close();
  190. /// <summary>
  191. /// Disposes of any resources used by the reader.
  192. /// </summary>
  193. public void Dispose()
  194. {
  195. if (!_disposed)
  196. {
  197. Dispose(true);
  198. _disposed = true;
  199. }
  200. }
  201. /// <summary>
  202. /// Positions the reader to an element by name.
  203. /// </summary>
  204. /// <param name="name">The name of the element.</param>
  205. /// <returns>True if the element was found.</returns>
  206. public bool FindElement(string name)
  207. {
  208. if (_disposed) { ThrowObjectDisposedException(); }
  209. if (_state != BsonReaderState.Type)
  210. {
  211. ThrowInvalidState("FindElement", BsonReaderState.Type);
  212. }
  213. while ((ReadBsonType()) != BsonType.EndOfDocument)
  214. {
  215. var elementName = ReadName();
  216. if (elementName == name)
  217. {
  218. return true;
  219. }
  220. SkipValue();
  221. }
  222. return false;
  223. }
  224. /// <summary>
  225. /// Positions the reader to a string element by name.
  226. /// </summary>
  227. /// <param name="name">The name of the element.</param>
  228. /// <returns>True if the element was found.</returns>
  229. public string FindStringElement(string name)
  230. {
  231. if (_disposed) { ThrowObjectDisposedException(); }
  232. if (_state != BsonReaderState.Type)
  233. {
  234. ThrowInvalidState("FindStringElement", BsonReaderState.Type);
  235. }
  236. BsonType bsonType;
  237. while ((bsonType = ReadBsonType()) != BsonType.EndOfDocument)
  238. {
  239. var elementName = ReadName();
  240. if (bsonType == BsonType.String && elementName == name)
  241. {
  242. return ReadString();
  243. }
  244. else
  245. {
  246. SkipValue();
  247. }
  248. }
  249. return null;
  250. }
  251. /// <summary>
  252. /// Gets a bookmark to the reader's current position and state.
  253. /// </summary>
  254. /// <returns>A bookmark.</returns>
  255. public abstract BsonReaderBookmark GetBookmark();
  256. /// <summary>
  257. /// Gets the current BsonType (calls ReadBsonType if necessary).
  258. /// </summary>
  259. /// <returns>The current BsonType.</returns>
  260. public BsonType GetCurrentBsonType()
  261. {
  262. if (_state == BsonReaderState.Initial || _state == BsonReaderState.Done || _state == BsonReaderState.ScopeDocument || _state == BsonReaderState.Type)
  263. {
  264. ReadBsonType();
  265. }
  266. if (_state != BsonReaderState.Value)
  267. {
  268. ThrowInvalidState("GetCurrentBsonType", BsonReaderState.Value);
  269. }
  270. return _currentBsonType;
  271. }
  272. /// <summary>
  273. /// Reads BSON binary data from the reader.
  274. /// </summary>
  275. /// <returns>A BsonBinaryData.</returns>
  276. public abstract BsonBinaryData ReadBinaryData();
  277. /// <summary>
  278. /// Reads BSON binary data from the reader.
  279. /// </summary>
  280. /// <param name="bytes">The binary data.</param>
  281. /// <param name="subType">The binary data subtype.</param>
  282. [Obsolete("Use ReadBinaryData() instead.")]
  283. public void ReadBinaryData(out byte[] bytes, out BsonBinarySubType subType)
  284. {
  285. GuidRepresentation guidRepresentation;
  286. ReadBinaryData(out bytes, out subType, out guidRepresentation);
  287. }
  288. /// <summary>
  289. /// Reads BSON binary data from the reader.
  290. /// </summary>
  291. /// <param name="bytes">The binary data.</param>
  292. /// <param name="subType">The binary data subtype.</param>
  293. /// <param name="guidRepresentation">The representation for Guids.</param>
  294. [Obsolete("Use ReadBinaryData() instead.")]
  295. public void ReadBinaryData(
  296. out byte[] bytes,
  297. out BsonBinarySubType subType,
  298. out GuidRepresentation guidRepresentation)
  299. {
  300. var binaryData = ReadBinaryData();
  301. bytes = binaryData.Bytes;
  302. subType = binaryData.SubType;
  303. guidRepresentation = binaryData.GuidRepresentation;
  304. }
  305. /// <summary>
  306. /// Reads a BSON binary data element from the reader.
  307. /// </summary>
  308. /// <param name="name">The name of the element.</param>
  309. /// <returns>A BsonBinaryData.</returns>
  310. public BsonBinaryData ReadBinaryData(string name)
  311. {
  312. VerifyName(name);
  313. return ReadBinaryData();
  314. }
  315. /// <summary>
  316. /// Reads a BSON binary data element from the reader.
  317. /// </summary>
  318. /// <param name="name">The name of the element.</param>
  319. /// <param name="bytes">The binary data.</param>
  320. /// <param name="subType">The binary data subtype.</param>
  321. [Obsolete("Use ReadBinaryData(string name) instead.")]
  322. public void ReadBinaryData(string name, out byte[] bytes, out BsonBinarySubType subType)
  323. {
  324. GuidRepresentation guidRepresentation;
  325. ReadBinaryData(name, out bytes, out subType, out guidRepresentation);
  326. }
  327. /// <summary>
  328. /// Reads a BSON binary data element from the reader.
  329. /// </summary>
  330. /// <param name="name">The name of the element.</param>
  331. /// <param name="bytes">The binary data.</param>
  332. /// <param name="subType">The binary data subtype.</param>
  333. /// <param name="guidRepresentation">The representation for Guids.</param>
  334. [Obsolete("Use ReadBinaryData(string name) instead.")]
  335. public void ReadBinaryData(
  336. string name,
  337. out byte[] bytes,
  338. out BsonBinarySubType subType,
  339. out GuidRepresentation guidRepresentation)
  340. {
  341. VerifyName(name);
  342. ReadBinaryData(out bytes, out subType, out guidRepresentation);
  343. }
  344. /// <summary>
  345. /// Reads a BSON boolean from the reader.
  346. /// </summary>
  347. /// <returns>A Boolean.</returns>
  348. public abstract bool ReadBoolean();
  349. /// <summary>
  350. /// Reads a BSON boolean element from the reader.
  351. /// </summary>
  352. /// <param name="name">The name of the element.</param>
  353. /// <returns>A Boolean.</returns>
  354. public bool ReadBoolean(string name)
  355. {
  356. VerifyName(name);
  357. return ReadBoolean();
  358. }
  359. /// <summary>
  360. /// Reads a BsonType from the reader.
  361. /// </summary>
  362. /// <returns>A BsonType.</returns>
  363. public BsonType ReadBsonType()
  364. {
  365. bool found;
  366. object value;
  367. return ReadBsonType(null, out found, out value);
  368. }
  369. /// <summary>
  370. /// Reads a BsonType from the reader.
  371. /// </summary>
  372. /// <typeparam name="TValue">The type of the BsonTrie values.</typeparam>
  373. /// <param name="bsonTrie">An optional trie to search for a value that matches the next element name.</param>
  374. /// <param name="found">Set to true if a matching value was found in the trie.</param>
  375. /// <param name="value">Set to the matching value found in the trie or null if no matching value was found.</param>
  376. /// <returns>A BsonType.</returns>
  377. public abstract BsonType ReadBsonType<TValue>(BsonTrie<TValue> bsonTrie, out bool found, out TValue value);
  378. /// <summary>
  379. /// Reads BSON binary data from the reader.
  380. /// </summary>
  381. /// <returns>A byte array.</returns>
  382. public abstract byte[] ReadBytes();
  383. /// <summary>
  384. /// Reads a BSON binary data element from the reader.
  385. /// </summary>
  386. /// <param name="name">The name of the element.</param>
  387. /// <returns>A byte array.</returns>
  388. public byte[] ReadBytes(string name)
  389. {
  390. VerifyName(name);
  391. return ReadBytes();
  392. }
  393. /// <summary>
  394. /// Reads a BSON DateTime from the reader.
  395. /// </summary>
  396. /// <returns>The number of milliseconds since the Unix epoch.</returns>
  397. public abstract long ReadDateTime();
  398. /// <summary>
  399. /// Reads a BSON DateTime element from the reader.
  400. /// </summary>
  401. /// <param name="name">The name of the element.</param>
  402. /// <returns>The number of milliseconds since the Unix epoch.</returns>
  403. public long ReadDateTime(string name)
  404. {
  405. VerifyName(name);
  406. return ReadDateTime();
  407. }
  408. /// <summary>
  409. /// Reads a BSON Double from the reader.
  410. /// </summary>
  411. /// <returns>A Double.</returns>
  412. public abstract double ReadDouble();
  413. /// <summary>
  414. /// Reads a BSON Double element from the reader.
  415. /// </summary>
  416. /// <param name="name">The name of the element.</param>
  417. /// <returns>A Double.</returns>
  418. public double ReadDouble(string name)
  419. {
  420. VerifyName(name);
  421. return ReadDouble();
  422. }
  423. /// <summary>
  424. /// Reads the end of a BSON array from the reader.
  425. /// </summary>
  426. public abstract void ReadEndArray();
  427. /// <summary>
  428. /// Reads the end of a BSON document from the reader.
  429. /// </summary>
  430. public abstract void ReadEndDocument();
  431. /// <summary>
  432. /// Reads a BSON Int32 from the reader.
  433. /// </summary>
  434. /// <returns>An Int32.</returns>
  435. public abstract int ReadInt32();
  436. /// <summary>
  437. /// Reads a BSON Int32 element from the reader.
  438. /// </summary>
  439. /// <param name="name">The name of the element.</param>
  440. /// <returns>An Int32.</returns>
  441. public int ReadInt32(string name)
  442. {
  443. VerifyName(name);
  444. return ReadInt32();
  445. }
  446. /// <summary>
  447. /// Reads a BSON Int64 from the reader.
  448. /// </summary>
  449. /// <returns>An Int64.</returns>
  450. public abstract long ReadInt64();
  451. /// <summary>
  452. /// Reads a BSON Int64 element from the reader.
  453. /// </summary>
  454. /// <param name="name">The name of the element.</param>
  455. /// <returns>An Int64.</returns>
  456. public long ReadInt64(string name)
  457. {
  458. VerifyName(name);
  459. return ReadInt64();
  460. }
  461. /// <summary>
  462. /// Reads a BSON JavaScript from the reader.
  463. /// </summary>
  464. /// <returns>A string.</returns>
  465. public abstract string ReadJavaScript();
  466. /// <summary>
  467. /// Reads a BSON JavaScript element from the reader.
  468. /// </summary>
  469. /// <param name="name">The name of the element.</param>
  470. /// <returns>A string.</returns>
  471. public string ReadJavaScript(string name)
  472. {
  473. VerifyName(name);
  474. return ReadJavaScript();
  475. }
  476. /// <summary>
  477. /// Reads a BSON JavaScript with scope from the reader (call ReadStartDocument next to read the scope).
  478. /// </summary>
  479. /// <returns>A string.</returns>
  480. public abstract string ReadJavaScriptWithScope();
  481. /// <summary>
  482. /// Reads a BSON JavaScript with scope element from the reader (call ReadStartDocument next to read the scope).
  483. /// </summary>
  484. /// <param name="name">The name of the element.</param>
  485. /// <returns>A string.</returns>
  486. public string ReadJavaScriptWithScope(string name)
  487. {
  488. VerifyName(name);
  489. return ReadJavaScriptWithScope();
  490. }
  491. /// <summary>
  492. /// Reads a BSON MaxKey from the reader.
  493. /// </summary>
  494. public abstract void ReadMaxKey();
  495. /// <summary>
  496. /// Reads a BSON MaxKey element from the reader.
  497. /// </summary>
  498. /// <param name="name">The name of the element.</param>
  499. public void ReadMaxKey(string name)
  500. {
  501. VerifyName(name);
  502. ReadMaxKey();
  503. }
  504. /// <summary>
  505. /// Reads a BSON MinKey from the reader.
  506. /// </summary>
  507. public abstract void ReadMinKey();
  508. /// <summary>
  509. /// Reads a BSON MinKey element from the reader.
  510. /// </summary>
  511. /// <param name="name">The name of the element.</param>
  512. public void ReadMinKey(string name)
  513. {
  514. VerifyName(name);
  515. ReadMinKey();
  516. }
  517. /// <summary>
  518. /// Reads the name of an element from the reader.
  519. /// </summary>
  520. /// <returns>The name of the element.</returns>
  521. public string ReadName()
  522. {
  523. if (_disposed) { ThrowObjectDisposedException(); }
  524. if (_state == BsonReaderState.Type)
  525. {
  526. ReadBsonType();
  527. }
  528. if (_state != BsonReaderState.Name)
  529. {
  530. ThrowInvalidState("ReadName", BsonReaderState.Name);
  531. }
  532. _state = BsonReaderState.Value;
  533. return _currentName;
  534. }
  535. /// <summary>
  536. /// Reads the name of an element from the reader.
  537. /// </summary>
  538. /// <param name="name">The name of the element.</param>
  539. public void ReadName(string name)
  540. {
  541. VerifyName(name);
  542. }
  543. /// <summary>
  544. /// Reads a BSON null from the reader.
  545. /// </summary>
  546. public abstract void ReadNull();
  547. /// <summary>
  548. /// Reads a BSON null element from the reader.
  549. /// </summary>
  550. /// <param name="name">The name of the element.</param>
  551. public void ReadNull(string name)
  552. {
  553. VerifyName(name);
  554. ReadNull();
  555. }
  556. /// <summary>
  557. /// Reads a BSON ObjectId from the reader.
  558. /// </summary>
  559. /// <returns>An ObjectId.</returns>
  560. public abstract ObjectId ReadObjectId();
  561. /// <summary>
  562. /// Reads a BSON ObjectId from the reader.
  563. /// </summary>
  564. /// <param name="timestamp">The timestamp.</param>
  565. /// <param name="machine">The machine hash.</param>
  566. /// <param name="pid">The PID.</param>
  567. /// <param name="increment">The increment.</param>
  568. [Obsolete("Use ReadObjectId() instead.")]
  569. public void ReadObjectId(out int timestamp, out int machine, out short pid, out int increment)
  570. {
  571. var objectId = ReadObjectId();
  572. timestamp = objectId.Timestamp;
  573. machine = objectId.Machine;
  574. pid = objectId.Pid;
  575. increment = objectId.Increment;
  576. }
  577. /// <summary>
  578. /// Reads a BSON ObjectId element from the reader.
  579. /// </summary>
  580. /// <param name="name">The name of the element.</param>
  581. /// <returns>An ObjectId.</returns>
  582. public ObjectId ReadObjectId(string name)
  583. {
  584. VerifyName(name);
  585. return ReadObjectId();
  586. }
  587. /// <summary>
  588. /// Reads a BSON ObjectId element from the reader.
  589. /// </summary>
  590. /// <param name="name">The name of the element.</param>
  591. /// <param name="timestamp">The timestamp.</param>
  592. /// <param name="machine">The machine hash.</param>
  593. /// <param name="pid">The PID.</param>
  594. /// <param name="increment">The increment.</param>
  595. [Obsolete("Use ReadObjectId(string name) instead.")]
  596. public void ReadObjectId(string name, out int timestamp, out int machine, out short pid, out int increment)
  597. {
  598. VerifyName(name);
  599. ReadObjectId(out timestamp, out machine, out pid, out increment);
  600. }
  601. /// <summary>
  602. /// Reads a raw BSON array.
  603. /// </summary>
  604. /// <returns>The raw BSON array.</returns>
  605. public virtual IByteBuffer ReadRawBsonArray()
  606. {
  607. // overridden in BsonBinaryReader
  608. var array = BsonArraySerializer.Instance.Deserialize(this, typeof(BsonArray), null);
  609. using (var bsonWriter = new BsonBinaryWriter(new BsonBuffer(), true, BsonBinaryWriterSettings.Defaults))
  610. {
  611. bsonWriter.WriteStartDocument();
  612. var startPosition = bsonWriter.Buffer.Position + 3; // just past BsonType, "x" and null byte
  613. bsonWriter.WriteName("x");
  614. BsonArraySerializer.Instance.Serialize(bsonWriter, typeof(BsonArray), array, null);
  615. var endPosition = bsonWriter.Buffer.Position;
  616. bsonWriter.WriteEndDocument();
  617. var length = (int)(endPosition - startPosition);
  618. bsonWriter.Buffer.Position = startPosition;
  619. var bytes = bsonWriter.Buffer.ReadBytes(length);
  620. return new ByteArrayBuffer(bytes, 0, length, true);
  621. }
  622. }
  623. /// <summary>
  624. /// Reads a raw BSON array.
  625. /// </summary>
  626. /// <param name="name">The name.</param>
  627. /// <returns>
  628. /// The raw BSON array.
  629. /// </returns>
  630. public IByteBuffer ReadRawBsonArray(string name)
  631. {
  632. VerifyName(name);
  633. return ReadRawBsonArray();
  634. }
  635. /// <summary>
  636. /// Reads a raw BSON document.
  637. /// </summary>
  638. /// <returns>The raw BSON document.</returns>
  639. public virtual IByteBuffer ReadRawBsonDocument()
  640. {
  641. // overridden in BsonBinaryReader
  642. var document = BsonDocumentSerializer.Instance.Deserialize(this, typeof(BsonDocument), null);
  643. var bytes = document.ToBson();
  644. return new ByteArrayBuffer(bytes, 0, bytes.Length, true);
  645. }
  646. /// <summary>
  647. /// Reads a raw BSON document.
  648. /// </summary>
  649. /// <param name="name">The name.</param>
  650. /// <returns>The raw BSON document.</returns>
  651. public IByteBuffer ReadRawBsonDocument(string name)
  652. {
  653. VerifyName(name);
  654. return ReadRawBsonDocument();
  655. }
  656. /// <summary>
  657. /// Reads a BSON regular expression from the reader.
  658. /// </summary>
  659. /// <returns>A BsonRegularExpression.</returns>
  660. public abstract BsonRegularExpression ReadRegularExpression();
  661. /// <summary>
  662. /// Reads a BSON regular expression from the reader.
  663. /// </summary>
  664. /// <param name="pattern">A regular expression pattern.</param>
  665. /// <param name="options">A regular expression options.</param>
  666. [Obsolete("Use ReadRegularExpression() instead.")]
  667. public void ReadRegularExpression(out string pattern, out string options)
  668. {
  669. var regex = ReadRegularExpression();
  670. pattern = regex.Pattern;
  671. options = regex.Options;
  672. }
  673. /// <summary>
  674. /// Reads a BSON regular expression element from the reader.
  675. /// </summary>
  676. /// <param name="name">The name of the element.</param>
  677. /// <returns>A BsonRegularExpression.</returns>
  678. public BsonRegularExpression ReadRegularExpression(string name)
  679. {
  680. VerifyName(name);
  681. return ReadRegularExpression();
  682. }
  683. /// <summary>
  684. /// Reads a BSON regular expression element from the reader.
  685. /// </summary>
  686. /// <param name="name">The name of the element.</param>
  687. /// <param name="pattern">A regular expression pattern.</param>
  688. /// <param name="options">A regular expression options.</param>
  689. [Obsolete("Use ReadRegularExpression(string name) instead.")]
  690. public void ReadRegularExpression(string name, out string pattern, out string options)
  691. {
  692. VerifyName(name);
  693. ReadRegularExpression(out pattern, out options);
  694. }
  695. /// <summary>
  696. /// Reads the start of a BSON array.
  697. /// </summary>
  698. public abstract void ReadStartArray();
  699. /// <summary>
  700. /// Reads the start of a BSON document.
  701. /// </summary>
  702. public abstract void ReadStartDocument();
  703. /// <summary>
  704. /// Reads a BSON string from the reader.
  705. /// </summary>
  706. /// <returns>A String.</returns>
  707. public abstract string ReadString();
  708. /// <summary>
  709. /// Reads a BSON string element from the reader.
  710. /// </summary>
  711. /// <returns>A String.</returns>
  712. /// <param name="name">The name of the element.</param>
  713. public string ReadString(string name)
  714. {
  715. VerifyName(name);
  716. return ReadString();
  717. }
  718. /// <summary>
  719. /// Reads a BSON symbol from the reader.
  720. /// </summary>
  721. /// <returns>A string.</returns>
  722. public abstract string ReadSymbol();
  723. /// <summary>
  724. /// Reads a BSON symbol element from the reader.
  725. /// </summary>
  726. /// <param name="name">The name of the element.</param>
  727. /// <returns>A string.</returns>
  728. public string ReadSymbol(string name)
  729. {
  730. VerifyName(name);
  731. return ReadSymbol();
  732. }
  733. /// <summary>
  734. /// Reads a BSON timestamp from the reader.
  735. /// </summary>
  736. /// <returns>The combined timestamp/increment.</returns>
  737. public abstract long ReadTimestamp();
  738. /// <summary>
  739. /// Reads a BSON timestamp element from the reader.
  740. /// </summary>
  741. /// <returns>The combined timestamp/increment.</returns>
  742. /// <param name="name">The name of the element.</param>
  743. public long ReadTimestamp(string name)
  744. {
  745. VerifyName(name);
  746. return ReadTimestamp();
  747. }
  748. /// <summary>
  749. /// Reads a BSON undefined from the reader.
  750. /// </summary>
  751. public abstract void ReadUndefined();
  752. /// <summary>
  753. /// Reads a BSON undefined element from the reader.
  754. /// </summary>
  755. /// <param name="name">The name of the element.</param>
  756. public void ReadUndefined(string name)
  757. {
  758. VerifyName(name);
  759. ReadUndefined();
  760. }
  761. /// <summary>
  762. /// Returns the reader to previously bookmarked position and state.
  763. /// </summary>
  764. /// <param name="bookmark">The bookmark.</param>
  765. public abstract void ReturnToBookmark(BsonReaderBookmark bookmark);
  766. /// <summary>
  767. /// Skips the name (reader must be positioned on a name).
  768. /// </summary>
  769. public abstract void SkipName();
  770. /// <summary>
  771. /// Skips the value (reader must be positioned on a value).
  772. /// </summary>
  773. public abstract void SkipValue();
  774. // protected methods
  775. /// <summary>
  776. /// Disposes of any resources used by the reader.
  777. /// </summary>
  778. /// <param name="disposing">True if called from Dispose.</param>
  779. protected virtual void Dispose(bool disposing)
  780. {
  781. }
  782. /// <summary>
  783. /// Throws an InvalidOperationException when the method called is not valid for the current ContextType.
  784. /// </summary>
  785. /// <param name="methodName">The name of the method.</param>
  786. /// <param name="actualContextType">The actual ContextType.</param>
  787. /// <param name="validContextTypes">The valid ContextTypes.</param>
  788. protected void ThrowInvalidContextType(
  789. string methodName,
  790. ContextType actualContextType,
  791. params ContextType[] validContextTypes)
  792. {
  793. var validContextTypesString = string.Join(" or ", validContextTypes.Select(c => c.ToString()).ToArray());
  794. var message = string.Format(
  795. "{0} can only be called when ContextType is {1}, not when ContextType is {2}.",
  796. methodName, validContextTypesString, actualContextType);
  797. throw new InvalidOperationException(message);
  798. }
  799. /// <summary>
  800. /// Throws an InvalidOperationException when the method called is not valid for the current state.
  801. /// </summary>
  802. /// <param name="methodName">The name of the method.</param>
  803. /// <param name="validStates">The valid states.</param>
  804. protected void ThrowInvalidState(string methodName, params BsonReaderState[] validStates)
  805. {
  806. var validStatesString = string.Join(" or ", validStates.Select(s => s.ToString()).ToArray());
  807. var message = string.Format(
  808. "{0} can only be called when State is {1}, not when State is {2}.",
  809. methodName, validStatesString, _state);
  810. throw new InvalidOperationException(message);
  811. }
  812. /// <summary>
  813. /// Throws an ObjectDisposedException.
  814. /// </summary>
  815. protected void ThrowObjectDisposedException()
  816. {
  817. throw new ObjectDisposedException(this.GetType().Name);
  818. }
  819. /// <summary>
  820. /// Verifies the current state and BsonType of the reader.
  821. /// </summary>
  822. /// <param name="methodName">The name of the method calling this one.</param>
  823. /// <param name="requiredBsonType">The required BSON type.</param>
  824. protected void VerifyBsonType(string methodName, BsonType requiredBsonType)
  825. {
  826. if (_state == BsonReaderState.Initial || _state == BsonReaderState.ScopeDocument || _state == BsonReaderState.Type)
  827. {
  828. ReadBsonType();
  829. }
  830. if (_state == BsonReaderState.Name)
  831. {
  832. // ignore name
  833. SkipName();
  834. }
  835. if (_state != BsonReaderState.Value)
  836. {
  837. ThrowInvalidState(methodName, BsonReaderState.Value);
  838. }
  839. if (_currentBsonType != requiredBsonType)
  840. {
  841. var message = string.Format(
  842. "{0} can only be called when CurrentBsonType is {1}, not when CurrentBsonType is {2}.",
  843. methodName, requiredBsonType, _currentBsonType);
  844. throw new InvalidOperationException(message);
  845. }
  846. }
  847. /// <summary>
  848. /// Verifies the name of the current element.
  849. /// </summary>
  850. /// <param name="expectedName">The expected name.</param>
  851. protected void VerifyName(string expectedName)
  852. {
  853. var actualName = ReadName();
  854. if (actualName != expectedName)
  855. {
  856. var message = string.Format(
  857. "Expected element name to be '{0}', not '{1}'.",
  858. expectedName, actualName);
  859. throw new Exception(message);
  860. }
  861. }
  862. }
  863. }