BsonBinaryReader.cs 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825
  1. /* Copyright 2010-present 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.Globalization;
  17. using System.IO;
  18. namespace MongoDB.Bson.IO
  19. {
  20. /// <summary>
  21. /// Represents a BSON reader for a binary BSON byte array.
  22. /// </summary>
  23. public class BsonBinaryReader : BsonReader
  24. {
  25. // private fields
  26. private readonly Stream _baseStream;
  27. private readonly BsonStream _bsonStream;
  28. private readonly BsonBinaryReaderSettings _settings; // same value as in base class just declared as derived class
  29. private BsonBinaryReaderContext _context;
  30. // constructors
  31. /// <summary>
  32. /// Initializes a new instance of the BsonBinaryReader class.
  33. /// </summary>
  34. /// <param name="stream">A stream (BsonBinary does not own the stream and will not Dispose it).</param>
  35. public BsonBinaryReader(Stream stream)
  36. : this(stream, BsonBinaryReaderSettings.Defaults)
  37. {
  38. }
  39. /// <summary>
  40. /// Initializes a new instance of the BsonBinaryReader class.
  41. /// </summary>
  42. /// <param name="stream">A stream (BsonBinary does not own the stream and will not Dispose it).</param>
  43. /// <param name="settings">A BsonBinaryReaderSettings.</param>
  44. public BsonBinaryReader(Stream stream, BsonBinaryReaderSettings settings)
  45. : base(settings)
  46. {
  47. if (stream == null)
  48. {
  49. throw new ArgumentNullException("stream");
  50. }
  51. if (!stream.CanSeek)
  52. {
  53. throw new ArgumentException("The stream must be capable of seeking.", "stream");
  54. }
  55. _baseStream = stream;
  56. _bsonStream = (stream as BsonStream) ?? new BsonStreamAdapter(stream);
  57. _settings = settings; // already frozen by base class
  58. _context = new BsonBinaryReaderContext(null, ContextType.TopLevel, 0, 0);
  59. }
  60. // public properties
  61. /// <summary>
  62. /// Gets the base stream.
  63. /// </summary>
  64. /// <value>
  65. /// The base stream.
  66. /// </value>
  67. public Stream BaseStream
  68. {
  69. get { return _baseStream; }
  70. }
  71. /// <summary>
  72. /// Gets the BSON stream.
  73. /// </summary>
  74. /// <value>
  75. /// The BSON stream.
  76. /// </value>
  77. public BsonStream BsonStream
  78. {
  79. get { return _bsonStream; }
  80. }
  81. // public methods
  82. /// <summary>
  83. /// Closes the reader.
  84. /// </summary>
  85. public override void Close()
  86. {
  87. // Close can be called on Disposed objects
  88. State = BsonReaderState.Closed;
  89. }
  90. /// <summary>
  91. /// Gets a bookmark to the reader's current position and state.
  92. /// </summary>
  93. /// <returns>A bookmark.</returns>
  94. public override BsonReaderBookmark GetBookmark()
  95. {
  96. return new BsonBinaryReaderBookmark(State, CurrentBsonType, CurrentName, _context, _bsonStream.Position);
  97. }
  98. /// <summary>
  99. /// Determines whether this reader is at end of file.
  100. /// </summary>
  101. /// <returns>
  102. /// Whether this reader is at end of file.
  103. /// </returns>
  104. public override bool IsAtEndOfFile()
  105. {
  106. return _bsonStream.Position >= _bsonStream.Length;
  107. }
  108. /// <summary>
  109. /// Reads BSON binary data from the reader.
  110. /// </summary>
  111. /// <returns>A BsonBinaryData.</returns>
  112. #pragma warning disable 618 // about obsolete BsonBinarySubType.OldBinary
  113. public override BsonBinaryData ReadBinaryData()
  114. {
  115. if (Disposed) { ThrowObjectDisposedException(); }
  116. VerifyBsonType("ReadBinaryData", BsonType.Binary);
  117. int size = ReadSize();
  118. var subType = _bsonStream.ReadBinarySubType();
  119. if (subType == BsonBinarySubType.OldBinary)
  120. {
  121. // sub type OldBinary has two sizes (for historical reasons)
  122. int size2 = ReadSize();
  123. if (size2 != size - 4)
  124. {
  125. throw new FormatException("Binary sub type OldBinary has inconsistent sizes");
  126. }
  127. size = size2;
  128. if (_settings.FixOldBinarySubTypeOnInput)
  129. {
  130. subType = BsonBinarySubType.Binary; // replace obsolete OldBinary with new Binary sub type
  131. }
  132. }
  133. var bytes = _bsonStream.ReadBytes(size);
  134. GuidRepresentation guidRepresentation;
  135. switch (subType)
  136. {
  137. case BsonBinarySubType.UuidLegacy: guidRepresentation = _settings.GuidRepresentation; break;
  138. case BsonBinarySubType.UuidStandard: guidRepresentation = GuidRepresentation.Standard; break;
  139. default: guidRepresentation = GuidRepresentation.Unspecified; break;
  140. }
  141. State = GetNextState();
  142. return new BsonBinaryData(bytes, subType, guidRepresentation);
  143. }
  144. #pragma warning restore 618
  145. /// <summary>
  146. /// Reads a BSON boolean from the reader.
  147. /// </summary>
  148. /// <returns>A Boolean.</returns>
  149. public override bool ReadBoolean()
  150. {
  151. if (Disposed) { ThrowObjectDisposedException(); }
  152. VerifyBsonType("ReadBoolean", BsonType.Boolean);
  153. State = GetNextState();
  154. return _bsonStream.ReadBoolean();
  155. }
  156. /// <summary>
  157. /// Reads a BsonType from the reader.
  158. /// </summary>
  159. /// <returns>A BsonType.</returns>
  160. public override BsonType ReadBsonType()
  161. {
  162. if (Disposed) { ThrowObjectDisposedException(); }
  163. if (State == BsonReaderState.Initial || State == BsonReaderState.ScopeDocument)
  164. {
  165. // there is an implied type of Document for the top level and for scope documents
  166. CurrentBsonType = BsonType.Document;
  167. State = BsonReaderState.Value;
  168. return CurrentBsonType;
  169. }
  170. if (State != BsonReaderState.Type)
  171. {
  172. ThrowInvalidState("ReadBsonType", BsonReaderState.Type);
  173. }
  174. if (_context.ContextType == ContextType.Array)
  175. {
  176. _context.CurrentArrayIndex++;
  177. }
  178. try
  179. {
  180. CurrentBsonType = _bsonStream.ReadBsonType();
  181. }
  182. catch (FormatException ex)
  183. {
  184. if (ex.Message.StartsWith("Detected unknown BSON type"))
  185. {
  186. // insert the element name into the error message
  187. var periodIndex = ex.Message.IndexOf('.');
  188. var dottedElementName = GenerateDottedElementName();
  189. var message = ex.Message.Substring(0, periodIndex) + $" for fieldname \"{dottedElementName}\"" + ex.Message.Substring(periodIndex);
  190. throw new FormatException(message);
  191. }
  192. throw;
  193. }
  194. if (CurrentBsonType == BsonType.EndOfDocument)
  195. {
  196. switch (_context.ContextType)
  197. {
  198. case ContextType.Array:
  199. State = BsonReaderState.EndOfArray;
  200. return BsonType.EndOfDocument;
  201. case ContextType.Document:
  202. case ContextType.ScopeDocument:
  203. State = BsonReaderState.EndOfDocument;
  204. return BsonType.EndOfDocument;
  205. default:
  206. var message = string.Format("BsonType EndOfDocument is not valid when ContextType is {0}.", _context.ContextType);
  207. throw new FormatException(message);
  208. }
  209. }
  210. else
  211. {
  212. switch (_context.ContextType)
  213. {
  214. case ContextType.Array:
  215. _bsonStream.SkipCString(); // ignore array element names
  216. State = BsonReaderState.Value;
  217. break;
  218. case ContextType.Document:
  219. case ContextType.ScopeDocument:
  220. State = BsonReaderState.Name;
  221. break;
  222. default:
  223. throw new BsonInternalException("Unexpected ContextType.");
  224. }
  225. return CurrentBsonType;
  226. }
  227. }
  228. /// <summary>
  229. /// Reads BSON binary data from the reader.
  230. /// </summary>
  231. /// <returns>A byte array.</returns>
  232. #pragma warning disable 618 // about obsolete BsonBinarySubType.OldBinary
  233. public override byte[] ReadBytes()
  234. {
  235. if (Disposed) { ThrowObjectDisposedException(); }
  236. VerifyBsonType("ReadBytes", BsonType.Binary);
  237. int size = ReadSize();
  238. var subType = _bsonStream.ReadBinarySubType();
  239. if (subType != BsonBinarySubType.Binary && subType != BsonBinarySubType.OldBinary)
  240. {
  241. var message = string.Format("ReadBytes requires the binary sub type to be Binary, not {0}.", subType);
  242. throw new FormatException(message);
  243. }
  244. State = GetNextState();
  245. return _bsonStream.ReadBytes(size);
  246. }
  247. #pragma warning restore 618
  248. /// <summary>
  249. /// Reads a BSON DateTime from the reader.
  250. /// </summary>
  251. /// <returns>The number of milliseconds since the Unix epoch.</returns>
  252. public override long ReadDateTime()
  253. {
  254. if (Disposed) { ThrowObjectDisposedException(); }
  255. VerifyBsonType("ReadDateTime", BsonType.DateTime);
  256. State = GetNextState();
  257. var value = _bsonStream.ReadInt64();
  258. if (value == BsonConstants.DateTimeMaxValueMillisecondsSinceEpoch + 1)
  259. {
  260. if (_settings.FixOldDateTimeMaxValueOnInput)
  261. {
  262. value = BsonConstants.DateTimeMaxValueMillisecondsSinceEpoch;
  263. }
  264. }
  265. return value;
  266. }
  267. /// <inheritdoc />
  268. public override Decimal128 ReadDecimal128()
  269. {
  270. if (Disposed) { ThrowObjectDisposedException(); }
  271. VerifyBsonType(nameof(ReadDecimal128), BsonType.Decimal128);
  272. State = GetNextState();
  273. return _bsonStream.ReadDecimal128();
  274. }
  275. /// <summary>
  276. /// Reads a BSON Double from the reader.
  277. /// </summary>
  278. /// <returns>A Double.</returns>
  279. public override double ReadDouble()
  280. {
  281. if (Disposed) { ThrowObjectDisposedException(); }
  282. VerifyBsonType("ReadDouble", BsonType.Double);
  283. State = GetNextState();
  284. return _bsonStream.ReadDouble();
  285. }
  286. /// <summary>
  287. /// Reads the end of a BSON array from the reader.
  288. /// </summary>
  289. public override void ReadEndArray()
  290. {
  291. if (Disposed) { ThrowObjectDisposedException(); }
  292. if (_context.ContextType != ContextType.Array)
  293. {
  294. ThrowInvalidContextType("ReadEndArray", _context.ContextType, ContextType.Array);
  295. }
  296. if (State == BsonReaderState.Type)
  297. {
  298. ReadBsonType(); // will set state to EndOfArray if at end of array
  299. }
  300. if (State != BsonReaderState.EndOfArray)
  301. {
  302. ThrowInvalidState("ReadEndArray", BsonReaderState.EndOfArray);
  303. }
  304. _context = _context.PopContext(_bsonStream.Position);
  305. switch (_context.ContextType)
  306. {
  307. case ContextType.Array: State = BsonReaderState.Type; break;
  308. case ContextType.Document: State = BsonReaderState.Type; break;
  309. case ContextType.TopLevel: State = BsonReaderState.Initial; break;
  310. default: throw new BsonInternalException("Unexpected ContextType.");
  311. }
  312. }
  313. /// <summary>
  314. /// Reads the end of a BSON document from the reader.
  315. /// </summary>
  316. public override void ReadEndDocument()
  317. {
  318. if (Disposed) { ThrowObjectDisposedException(); }
  319. if (_context.ContextType != ContextType.Document && _context.ContextType != ContextType.ScopeDocument)
  320. {
  321. ThrowInvalidContextType("ReadEndDocument", _context.ContextType, ContextType.Document, ContextType.ScopeDocument);
  322. }
  323. if (State == BsonReaderState.Type)
  324. {
  325. ReadBsonType(); // will set state to EndOfDocument if at end of document
  326. }
  327. if (State != BsonReaderState.EndOfDocument)
  328. {
  329. ThrowInvalidState("ReadEndDocument", BsonReaderState.EndOfDocument);
  330. }
  331. _context = _context.PopContext(_bsonStream.Position);
  332. if (_context.ContextType == ContextType.JavaScriptWithScope)
  333. {
  334. _context = _context.PopContext(_bsonStream.Position); // JavaScriptWithScope
  335. }
  336. switch (_context.ContextType)
  337. {
  338. case ContextType.Array: State = BsonReaderState.Type; break;
  339. case ContextType.Document: State = BsonReaderState.Type; break;
  340. case ContextType.TopLevel: State = BsonReaderState.Initial; break;
  341. default: throw new BsonInternalException("Unexpected ContextType.");
  342. }
  343. }
  344. /// <summary>
  345. /// Reads a BSON Int32 from the reader.
  346. /// </summary>
  347. /// <returns>An Int32.</returns>
  348. public override int ReadInt32()
  349. {
  350. if (Disposed) { ThrowObjectDisposedException(); }
  351. VerifyBsonType("ReadInt32", BsonType.Int32);
  352. State = GetNextState();
  353. return _bsonStream.ReadInt32();
  354. }
  355. /// <summary>
  356. /// Reads a BSON Int64 from the reader.
  357. /// </summary>
  358. /// <returns>An Int64.</returns>
  359. public override long ReadInt64()
  360. {
  361. if (Disposed) { ThrowObjectDisposedException(); }
  362. VerifyBsonType("ReadInt64", BsonType.Int64);
  363. State = GetNextState();
  364. return _bsonStream.ReadInt64();
  365. }
  366. /// <summary>
  367. /// Reads a BSON JavaScript from the reader.
  368. /// </summary>
  369. /// <returns>A string.</returns>
  370. public override string ReadJavaScript()
  371. {
  372. if (Disposed) { ThrowObjectDisposedException(); }
  373. VerifyBsonType("ReadJavaScript", BsonType.JavaScript);
  374. State = GetNextState();
  375. return _bsonStream.ReadString(_settings.Encoding);
  376. }
  377. /// <summary>
  378. /// Reads a BSON JavaScript with scope from the reader (call ReadStartDocument next to read the scope).
  379. /// </summary>
  380. /// <returns>A string.</returns>
  381. public override string ReadJavaScriptWithScope()
  382. {
  383. if (Disposed) { ThrowObjectDisposedException(); }
  384. VerifyBsonType("ReadJavaScriptWithScope", BsonType.JavaScriptWithScope);
  385. var startPosition = _bsonStream.Position; // position of size field
  386. var size = ReadSize();
  387. _context = new BsonBinaryReaderContext(_context, ContextType.JavaScriptWithScope, startPosition, size);
  388. var code = _bsonStream.ReadString(_settings.Encoding);
  389. State = BsonReaderState.ScopeDocument;
  390. return code;
  391. }
  392. /// <summary>
  393. /// Reads a BSON MaxKey from the reader.
  394. /// </summary>
  395. public override void ReadMaxKey()
  396. {
  397. if (Disposed) { ThrowObjectDisposedException(); }
  398. VerifyBsonType("ReadMaxKey", BsonType.MaxKey);
  399. State = GetNextState();
  400. }
  401. /// <summary>
  402. /// Reads a BSON MinKey from the reader.
  403. /// </summary>
  404. public override void ReadMinKey()
  405. {
  406. if (Disposed) { ThrowObjectDisposedException(); }
  407. VerifyBsonType("ReadMinKey", BsonType.MinKey);
  408. State = GetNextState();
  409. }
  410. /// <summary>
  411. /// Reads the name of an element from the reader.
  412. /// </summary>
  413. /// <param name="nameDecoder">The name decoder.</param>
  414. /// <returns>The name of the element.</returns>
  415. public override string ReadName(INameDecoder nameDecoder)
  416. {
  417. if (nameDecoder == null)
  418. {
  419. throw new ArgumentNullException("nameDecoder");
  420. }
  421. if (Disposed) { ThrowObjectDisposedException(); }
  422. if (State == BsonReaderState.Type)
  423. {
  424. ReadBsonType();
  425. }
  426. if (State != BsonReaderState.Name)
  427. {
  428. ThrowInvalidState("ReadName", BsonReaderState.Name);
  429. }
  430. CurrentName = nameDecoder.Decode(_bsonStream, _settings.Encoding);
  431. State = BsonReaderState.Value;
  432. if (_context.ContextType == ContextType.Document)
  433. {
  434. _context.CurrentElementName = CurrentName;
  435. }
  436. return CurrentName;
  437. }
  438. /// <summary>
  439. /// Reads a BSON null from the reader.
  440. /// </summary>
  441. public override void ReadNull()
  442. {
  443. if (Disposed) { ThrowObjectDisposedException(); }
  444. VerifyBsonType("ReadNull", BsonType.Null);
  445. State = GetNextState();
  446. }
  447. /// <summary>
  448. /// Reads a BSON ObjectId from the reader.
  449. /// </summary>
  450. /// <returns>An ObjectId.</returns>
  451. public override ObjectId ReadObjectId()
  452. {
  453. if (Disposed) { ThrowObjectDisposedException(); }
  454. VerifyBsonType("ReadObjectId", BsonType.ObjectId);
  455. State = GetNextState();
  456. return _bsonStream.ReadObjectId();
  457. }
  458. /// <summary>
  459. /// Reads a raw BSON array.
  460. /// </summary>
  461. /// <returns>
  462. /// The raw BSON array.
  463. /// </returns>
  464. public override IByteBuffer ReadRawBsonArray()
  465. {
  466. if (Disposed) { ThrowObjectDisposedException(); }
  467. VerifyBsonType("ReadRawBsonArray", BsonType.Array);
  468. var slice = _bsonStream.ReadSlice();
  469. switch (_context.ContextType)
  470. {
  471. case ContextType.Array: State = BsonReaderState.Type; break;
  472. case ContextType.Document: State = BsonReaderState.Type; break;
  473. case ContextType.TopLevel: State = BsonReaderState.Initial; break;
  474. default: throw new BsonInternalException("Unexpected ContextType.");
  475. }
  476. return slice;
  477. }
  478. /// <summary>
  479. /// Reads a raw BSON document.
  480. /// </summary>
  481. /// <returns>
  482. /// The raw BSON document.
  483. /// </returns>
  484. public override IByteBuffer ReadRawBsonDocument()
  485. {
  486. if (Disposed) { ThrowObjectDisposedException(); }
  487. VerifyBsonType("ReadRawBsonDocument", BsonType.Document);
  488. var slice = _bsonStream.ReadSlice();
  489. if (_context.ContextType == ContextType.JavaScriptWithScope)
  490. {
  491. _context = _context.PopContext(_bsonStream.Position); // JavaScriptWithScope
  492. }
  493. switch (_context.ContextType)
  494. {
  495. case ContextType.Array: State = BsonReaderState.Type; break;
  496. case ContextType.Document: State = BsonReaderState.Type; break;
  497. case ContextType.TopLevel: State = BsonReaderState.Initial; break;
  498. default: throw new BsonInternalException("Unexpected ContextType.");
  499. }
  500. return slice;
  501. }
  502. /// <summary>
  503. /// Reads a BSON regular expression from the reader.
  504. /// </summary>
  505. /// <returns>A BsonRegularExpression.</returns>
  506. public override BsonRegularExpression ReadRegularExpression()
  507. {
  508. if (Disposed) { ThrowObjectDisposedException(); }
  509. VerifyBsonType("ReadRegularExpression", BsonType.RegularExpression);
  510. State = GetNextState();
  511. var pattern = _bsonStream.ReadCString(_settings.Encoding);
  512. var options = _bsonStream.ReadCString(_settings.Encoding);
  513. return new BsonRegularExpression(pattern, options);
  514. }
  515. /// <summary>
  516. /// Reads the start of a BSON array.
  517. /// </summary>
  518. public override void ReadStartArray()
  519. {
  520. if (Disposed) { ThrowObjectDisposedException(); }
  521. VerifyBsonType("ReadStartArray", BsonType.Array);
  522. var startPosition = _bsonStream.Position; // position of size field
  523. var size = ReadSize();
  524. _context = new BsonBinaryReaderContext(_context, ContextType.Array, startPosition, size);
  525. State = BsonReaderState.Type;
  526. }
  527. /// <summary>
  528. /// Reads the start of a BSON document.
  529. /// </summary>
  530. public override void ReadStartDocument()
  531. {
  532. if (Disposed) { ThrowObjectDisposedException(); }
  533. VerifyBsonType("ReadStartDocument", BsonType.Document);
  534. var contextType = (State == BsonReaderState.ScopeDocument) ? ContextType.ScopeDocument : ContextType.Document;
  535. var startPosition = _bsonStream.Position; // position of size field
  536. var size = ReadSize();
  537. _context = new BsonBinaryReaderContext(_context, contextType, startPosition, size);
  538. State = BsonReaderState.Type;
  539. }
  540. /// <summary>
  541. /// Reads a BSON string from the reader.
  542. /// </summary>
  543. /// <returns>A String.</returns>
  544. public override string ReadString()
  545. {
  546. if (Disposed) { ThrowObjectDisposedException(); }
  547. VerifyBsonType("ReadString", BsonType.String);
  548. State = GetNextState();
  549. return _bsonStream.ReadString(_settings.Encoding);
  550. }
  551. /// <summary>
  552. /// Reads a BSON symbol from the reader.
  553. /// </summary>
  554. /// <returns>A string.</returns>
  555. public override string ReadSymbol()
  556. {
  557. if (Disposed) { ThrowObjectDisposedException(); }
  558. VerifyBsonType("ReadSymbol", BsonType.Symbol);
  559. State = GetNextState();
  560. return _bsonStream.ReadString(_settings.Encoding);
  561. }
  562. /// <summary>
  563. /// Reads a BSON timestamp from the reader.
  564. /// </summary>
  565. /// <returns>The combined timestamp/increment.</returns>
  566. public override long ReadTimestamp()
  567. {
  568. if (Disposed) { ThrowObjectDisposedException(); }
  569. VerifyBsonType("ReadTimestamp", BsonType.Timestamp);
  570. State = GetNextState();
  571. return _bsonStream.ReadInt64();
  572. }
  573. /// <summary>
  574. /// Reads a BSON undefined from the reader.
  575. /// </summary>
  576. public override void ReadUndefined()
  577. {
  578. if (Disposed) { ThrowObjectDisposedException(); }
  579. VerifyBsonType("ReadUndefined", BsonType.Undefined);
  580. State = GetNextState();
  581. }
  582. /// <summary>
  583. /// Returns the reader to previously bookmarked position and state.
  584. /// </summary>
  585. /// <param name="bookmark">The bookmark.</param>
  586. public override void ReturnToBookmark(BsonReaderBookmark bookmark)
  587. {
  588. var binaryReaderBookmark = (BsonBinaryReaderBookmark)bookmark;
  589. State = binaryReaderBookmark.State;
  590. CurrentBsonType = binaryReaderBookmark.CurrentBsonType;
  591. CurrentName = binaryReaderBookmark.CurrentName;
  592. _context = binaryReaderBookmark.CloneContext();
  593. _bsonStream.Position = binaryReaderBookmark.Position;
  594. }
  595. /// <summary>
  596. /// Skips the name (reader must be positioned on a name).
  597. /// </summary>
  598. public override void SkipName()
  599. {
  600. if (Disposed) { ThrowObjectDisposedException(); }
  601. if (State != BsonReaderState.Name)
  602. {
  603. ThrowInvalidState("SkipName", BsonReaderState.Name);
  604. }
  605. _bsonStream.SkipCString();
  606. CurrentName = null;
  607. State = BsonReaderState.Value;
  608. if (_context.ContextType == ContextType.Document)
  609. {
  610. _context.CurrentElementName = CurrentName;
  611. }
  612. }
  613. /// <summary>
  614. /// Skips the value (reader must be positioned on a value).
  615. /// </summary>
  616. public override void SkipValue()
  617. {
  618. if (Disposed) { ThrowObjectDisposedException(); }
  619. if (State != BsonReaderState.Value)
  620. {
  621. ThrowInvalidState("SkipValue", BsonReaderState.Value);
  622. }
  623. int skip;
  624. switch (CurrentBsonType)
  625. {
  626. case BsonType.Array: skip = ReadSize() - 4; break;
  627. case BsonType.Binary: skip = ReadSize() + 1; break;
  628. case BsonType.Boolean: skip = 1; break;
  629. case BsonType.DateTime: skip = 8; break;
  630. case BsonType.Document: skip = ReadSize() - 4; break;
  631. case BsonType.Decimal128: skip = 16; break;
  632. case BsonType.Double: skip = 8; break;
  633. case BsonType.Int32: skip = 4; break;
  634. case BsonType.Int64: skip = 8; break;
  635. case BsonType.JavaScript: skip = ReadSize(); break;
  636. case BsonType.JavaScriptWithScope: skip = ReadSize() - 4; break;
  637. case BsonType.MaxKey: skip = 0; break;
  638. case BsonType.MinKey: skip = 0; break;
  639. case BsonType.Null: skip = 0; break;
  640. case BsonType.ObjectId: skip = 12; break;
  641. case BsonType.RegularExpression: _bsonStream.SkipCString(); _bsonStream.SkipCString(); skip = 0; break;
  642. case BsonType.String: skip = ReadSize(); break;
  643. case BsonType.Symbol: skip = ReadSize(); break;
  644. case BsonType.Timestamp: skip = 8; break;
  645. case BsonType.Undefined: skip = 0; break;
  646. default: throw new BsonInternalException("Unexpected BsonType.");
  647. }
  648. _bsonStream.Seek(skip, SeekOrigin.Current);
  649. State = BsonReaderState.Type;
  650. }
  651. // protected methods
  652. /// <summary>
  653. /// Disposes of any resources used by the reader.
  654. /// </summary>
  655. /// <param name="disposing">True if called from Dispose.</param>
  656. protected override void Dispose(bool disposing)
  657. {
  658. // don't Dispose the _stream because we don't own it
  659. if (disposing)
  660. {
  661. try
  662. {
  663. Close();
  664. }
  665. catch { } // ignore exceptions
  666. }
  667. base.Dispose(disposing);
  668. }
  669. // private methods
  670. private string GenerateDottedElementName()
  671. {
  672. string elementName;
  673. if (_context.ContextType == ContextType.Document)
  674. {
  675. try
  676. {
  677. elementName = _bsonStream.ReadCString(Utf8Encodings.Lenient);
  678. }
  679. catch
  680. {
  681. elementName = "?"; // ignore exception
  682. }
  683. }
  684. else if (_context.ContextType == ContextType.Array)
  685. {
  686. elementName = _context.CurrentArrayIndex.ToString(NumberFormatInfo.InvariantInfo);
  687. }
  688. else
  689. {
  690. elementName = "?";
  691. }
  692. return GenerateDottedElementName(_context.ParentContext, elementName);
  693. }
  694. private string GenerateDottedElementName(BsonBinaryReaderContext context, string elementName)
  695. {
  696. if (context.ContextType == ContextType.Document)
  697. {
  698. return GenerateDottedElementName(context.ParentContext, (context.CurrentElementName ?? "?") + "." + elementName);
  699. }
  700. else if (context.ContextType == ContextType.Array)
  701. {
  702. var indexElementName = context.CurrentArrayIndex.ToString(NumberFormatInfo.InvariantInfo);
  703. return GenerateDottedElementName(context.ParentContext, indexElementName + "." + elementName);
  704. }
  705. else if (context.ParentContext != null)
  706. {
  707. return GenerateDottedElementName(context.ParentContext, "?." + elementName);
  708. }
  709. else
  710. {
  711. return elementName;
  712. }
  713. }
  714. private BsonReaderState GetNextState()
  715. {
  716. switch (_context.ContextType)
  717. {
  718. case ContextType.Array:
  719. case ContextType.Document:
  720. case ContextType.ScopeDocument:
  721. return BsonReaderState.Type;
  722. case ContextType.TopLevel:
  723. return BsonReaderState.Initial;
  724. default:
  725. throw new BsonInternalException("Unexpected ContextType.");
  726. }
  727. }
  728. private int ReadSize()
  729. {
  730. int size = _bsonStream.ReadInt32();
  731. if (size < 0)
  732. {
  733. var message = string.Format("Size {0} is not valid because it is negative.", size);
  734. throw new FormatException(message);
  735. }
  736. if (size > _settings.MaxDocumentSize)
  737. {
  738. var message = string.Format("Size {0} is not valid because it is larger than MaxDocumentSize {1}.", size, _settings.MaxDocumentSize);
  739. throw new FormatException(message);
  740. }
  741. return size;
  742. }
  743. }
  744. }