BsonReader.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440
  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.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 reader for some external format (see subclasses).
  24. /// </summary>
  25. public abstract class BsonReader : IBsonReader
  26. {
  27. // private fields
  28. private bool _disposed = false;
  29. private BsonReaderSettings _settings;
  30. private BsonReaderState _state;
  31. private BsonType _currentBsonType;
  32. private string _currentName;
  33. // constructors
  34. /// <summary>
  35. /// Initializes a new instance of the BsonReader class.
  36. /// </summary>
  37. /// <param name="settings">The reader settings.</param>
  38. protected BsonReader(BsonReaderSettings settings)
  39. {
  40. if (settings == null)
  41. {
  42. throw new ArgumentNullException("settings");
  43. }
  44. _settings = settings.FrozenCopy();
  45. _state = BsonReaderState.Initial;
  46. }
  47. // public properties
  48. /// <summary>
  49. /// Gets the current BsonType.
  50. /// </summary>
  51. public BsonType CurrentBsonType
  52. {
  53. get { return _currentBsonType; }
  54. protected set { _currentBsonType = value; }
  55. }
  56. /// <summary>
  57. /// Gets the settings of the reader.
  58. /// </summary>
  59. public BsonReaderSettings Settings
  60. {
  61. get { return _settings; }
  62. }
  63. /// <summary>
  64. /// Gets the current state of the reader.
  65. /// </summary>
  66. public BsonReaderState State
  67. {
  68. get { return _state; }
  69. protected set { _state = value; }
  70. }
  71. // protected properties
  72. /// <summary>
  73. /// Gets the current name.
  74. /// </summary>
  75. protected string CurrentName
  76. {
  77. get { return _currentName; }
  78. set { _currentName = value; }
  79. }
  80. /// <summary>
  81. /// Gets whether the BsonReader has been disposed.
  82. /// </summary>
  83. protected bool Disposed
  84. {
  85. get { return _disposed; }
  86. }
  87. // public methods
  88. /// <summary>
  89. /// Closes the reader.
  90. /// </summary>
  91. public abstract void Close();
  92. /// <summary>
  93. /// Disposes of any resources used by the reader.
  94. /// </summary>
  95. public void Dispose()
  96. {
  97. if (!_disposed)
  98. {
  99. Dispose(true);
  100. _disposed = true;
  101. }
  102. }
  103. /// <summary>
  104. /// Gets a bookmark to the reader's current position and state.
  105. /// </summary>
  106. /// <returns>A bookmark.</returns>
  107. public abstract BsonReaderBookmark GetBookmark();
  108. /// <summary>
  109. /// Gets the current BsonType (calls ReadBsonType if necessary).
  110. /// </summary>
  111. /// <returns>The current BsonType.</returns>
  112. public BsonType GetCurrentBsonType()
  113. {
  114. if (_state == BsonReaderState.Initial || _state == BsonReaderState.ScopeDocument || _state == BsonReaderState.Type)
  115. {
  116. ReadBsonType();
  117. }
  118. if (_state != BsonReaderState.Value)
  119. {
  120. ThrowInvalidState("GetCurrentBsonType", BsonReaderState.Value);
  121. }
  122. return _currentBsonType;
  123. }
  124. /// <summary>
  125. /// Determines whether this reader is at end of file.
  126. /// </summary>
  127. /// <returns>
  128. /// Whether this reader is at end of file.
  129. /// </returns>
  130. public abstract bool IsAtEndOfFile();
  131. /// <summary>
  132. /// Reads BSON binary data from the reader.
  133. /// </summary>
  134. /// <returns>A BsonBinaryData.</returns>
  135. public abstract BsonBinaryData ReadBinaryData();
  136. /// <summary>
  137. /// Reads a BSON boolean from the reader.
  138. /// </summary>
  139. /// <returns>A Boolean.</returns>
  140. public abstract bool ReadBoolean();
  141. /// <summary>
  142. /// Reads a BsonType from the reader.
  143. /// </summary>
  144. /// <returns>A BsonType.</returns>
  145. public abstract BsonType ReadBsonType();
  146. /// <summary>
  147. /// Reads BSON binary data from the reader.
  148. /// </summary>
  149. /// <returns>A byte array.</returns>
  150. public abstract byte[] ReadBytes();
  151. /// <summary>
  152. /// Reads a BSON DateTime from the reader.
  153. /// </summary>
  154. /// <returns>The number of milliseconds since the Unix epoch.</returns>
  155. public abstract long ReadDateTime();
  156. /// <inheritdoc />
  157. public abstract Decimal128 ReadDecimal128();
  158. /// <summary>
  159. /// Reads a BSON Double from the reader.
  160. /// </summary>
  161. /// <returns>A Double.</returns>
  162. public abstract double ReadDouble();
  163. /// <summary>
  164. /// Reads the end of a BSON array from the reader.
  165. /// </summary>
  166. public abstract void ReadEndArray();
  167. /// <summary>
  168. /// Reads the end of a BSON document from the reader.
  169. /// </summary>
  170. public abstract void ReadEndDocument();
  171. /// <summary>
  172. /// Reads a BSON Int32 from the reader.
  173. /// </summary>
  174. /// <returns>An Int32.</returns>
  175. public abstract int ReadInt32();
  176. /// <summary>
  177. /// Reads a BSON Int64 from the reader.
  178. /// </summary>
  179. /// <returns>An Int64.</returns>
  180. public abstract long ReadInt64();
  181. /// <summary>
  182. /// Reads a BSON JavaScript from the reader.
  183. /// </summary>
  184. /// <returns>A string.</returns>
  185. public abstract string ReadJavaScript();
  186. /// <summary>
  187. /// Reads a BSON JavaScript with scope from the reader (call ReadStartDocument next to read the scope).
  188. /// </summary>
  189. /// <returns>A string.</returns>
  190. public abstract string ReadJavaScriptWithScope();
  191. /// <summary>
  192. /// Reads a BSON MaxKey from the reader.
  193. /// </summary>
  194. public abstract void ReadMaxKey();
  195. /// <summary>
  196. /// Reads a BSON MinKey from the reader.
  197. /// </summary>
  198. public abstract void ReadMinKey();
  199. /// <summary>
  200. /// Reads the name of an element from the reader.
  201. /// </summary>
  202. /// <returns>The name of the element.</returns>
  203. public virtual string ReadName()
  204. {
  205. return ReadName(Utf8NameDecoder.Instance);
  206. }
  207. /// <summary>
  208. /// Reads the name of an element from the reader (using the provided name decoder).
  209. /// </summary>
  210. /// <param name="nameDecoder">The name decoder.</param>
  211. /// <returns>
  212. /// The name of the element.
  213. /// </returns>
  214. public abstract string ReadName(INameDecoder nameDecoder);
  215. /// <summary>
  216. /// Reads a BSON null from the reader.
  217. /// </summary>
  218. public abstract void ReadNull();
  219. /// <summary>
  220. /// Reads a BSON ObjectId from the reader.
  221. /// </summary>
  222. /// <returns>An ObjectId.</returns>
  223. public abstract ObjectId ReadObjectId();
  224. /// <summary>
  225. /// Reads a raw BSON array.
  226. /// </summary>
  227. /// <returns>The raw BSON array.</returns>
  228. public virtual IByteBuffer ReadRawBsonArray()
  229. {
  230. // overridden in BsonBinaryReader to read the raw bytes from the stream
  231. // for all other streams, deserialize the array and reserialize it using a BsonBinaryWriter to get the raw bytes
  232. var deserializationContext = BsonDeserializationContext.CreateRoot(this);
  233. var array = BsonArraySerializer.Instance.Deserialize(deserializationContext);
  234. using (var memoryStream = new MemoryStream())
  235. using (var bsonWriter = new BsonBinaryWriter(memoryStream, BsonBinaryWriterSettings.Defaults))
  236. {
  237. var serializationContext = BsonSerializationContext.CreateRoot(bsonWriter);
  238. bsonWriter.WriteStartDocument();
  239. var startPosition = memoryStream.Position + 3; // just past BsonType, "x" and null byte
  240. bsonWriter.WriteName("x");
  241. BsonArraySerializer.Instance.Serialize(serializationContext, array);
  242. var endPosition = memoryStream.Position;
  243. bsonWriter.WriteEndDocument();
  244. byte[] memoryStreamBuffer;
  245. #if NETSTANDARD1_5 || NETSTANDARD1_6
  246. memoryStreamBuffer = memoryStream.ToArray();
  247. #else
  248. memoryStreamBuffer = memoryStream.GetBuffer();
  249. #endif
  250. var buffer = new ByteArrayBuffer(memoryStreamBuffer, (int)memoryStream.Length, isReadOnly: true);
  251. return new ByteBufferSlice(buffer, (int)startPosition, (int)(endPosition - startPosition));
  252. }
  253. }
  254. /// <summary>
  255. /// Reads a raw BSON document.
  256. /// </summary>
  257. /// <returns>The raw BSON document.</returns>
  258. public virtual IByteBuffer ReadRawBsonDocument()
  259. {
  260. // overridden in BsonBinaryReader to read the raw bytes from the stream
  261. // for all other streams, deserialize the document and use ToBson to get the raw bytes
  262. var deserializationContext = BsonDeserializationContext.CreateRoot(this);
  263. var document = BsonDocumentSerializer.Instance.Deserialize(deserializationContext);
  264. var bytes = document.ToBson();
  265. return new ByteArrayBuffer(bytes, isReadOnly: true);
  266. }
  267. /// <summary>
  268. /// Reads a BSON regular expression from the reader.
  269. /// </summary>
  270. /// <returns>A BsonRegularExpression.</returns>
  271. public abstract BsonRegularExpression ReadRegularExpression();
  272. /// <summary>
  273. /// Reads the start of a BSON array.
  274. /// </summary>
  275. public abstract void ReadStartArray();
  276. /// <summary>
  277. /// Reads the start of a BSON document.
  278. /// </summary>
  279. public abstract void ReadStartDocument();
  280. /// <summary>
  281. /// Reads a BSON string from the reader.
  282. /// </summary>
  283. /// <returns>A String.</returns>
  284. public abstract string ReadString();
  285. /// <summary>
  286. /// Reads a BSON symbol from the reader.
  287. /// </summary>
  288. /// <returns>A string.</returns>
  289. public abstract string ReadSymbol();
  290. /// <summary>
  291. /// Reads a BSON timestamp from the reader.
  292. /// </summary>
  293. /// <returns>The combined timestamp/increment.</returns>
  294. public abstract long ReadTimestamp();
  295. /// <summary>
  296. /// Reads a BSON undefined from the reader.
  297. /// </summary>
  298. public abstract void ReadUndefined();
  299. /// <summary>
  300. /// Returns the reader to previously bookmarked position and state.
  301. /// </summary>
  302. /// <param name="bookmark">The bookmark.</param>
  303. public abstract void ReturnToBookmark(BsonReaderBookmark bookmark);
  304. /// <summary>
  305. /// Skips the name (reader must be positioned on a name).
  306. /// </summary>
  307. public abstract void SkipName();
  308. /// <summary>
  309. /// Skips the value (reader must be positioned on a value).
  310. /// </summary>
  311. public abstract void SkipValue();
  312. // protected methods
  313. /// <summary>
  314. /// Disposes of any resources used by the reader.
  315. /// </summary>
  316. /// <param name="disposing">True if called from Dispose.</param>
  317. protected virtual void Dispose(bool disposing)
  318. {
  319. }
  320. /// <summary>
  321. /// Throws an InvalidOperationException when the method called is not valid for the current ContextType.
  322. /// </summary>
  323. /// <param name="methodName">The name of the method.</param>
  324. /// <param name="actualContextType">The actual ContextType.</param>
  325. /// <param name="validContextTypes">The valid ContextTypes.</param>
  326. protected void ThrowInvalidContextType(
  327. string methodName,
  328. ContextType actualContextType,
  329. params ContextType[] validContextTypes)
  330. {
  331. var validContextTypesString = string.Join(" or ", validContextTypes.Select(c => c.ToString()).ToArray());
  332. var message = string.Format(
  333. "{0} can only be called when ContextType is {1}, not when ContextType is {2}.",
  334. methodName, validContextTypesString, actualContextType);
  335. throw new InvalidOperationException(message);
  336. }
  337. /// <summary>
  338. /// Throws an InvalidOperationException when the method called is not valid for the current state.
  339. /// </summary>
  340. /// <param name="methodName">The name of the method.</param>
  341. /// <param name="validStates">The valid states.</param>
  342. protected void ThrowInvalidState(string methodName, params BsonReaderState[] validStates)
  343. {
  344. var validStatesString = string.Join(" or ", validStates.Select(s => s.ToString()).ToArray());
  345. var message = string.Format(
  346. "{0} can only be called when State is {1}, not when State is {2}.",
  347. methodName, validStatesString, _state);
  348. throw new InvalidOperationException(message);
  349. }
  350. /// <summary>
  351. /// Throws an ObjectDisposedException.
  352. /// </summary>
  353. protected void ThrowObjectDisposedException()
  354. {
  355. throw new ObjectDisposedException(this.GetType().Name);
  356. }
  357. /// <summary>
  358. /// Verifies the current state and BsonType of the reader.
  359. /// </summary>
  360. /// <param name="methodName">The name of the method calling this one.</param>
  361. /// <param name="requiredBsonType">The required BSON type.</param>
  362. protected void VerifyBsonType(string methodName, BsonType requiredBsonType)
  363. {
  364. if (_state == BsonReaderState.Initial || _state == BsonReaderState.ScopeDocument || _state == BsonReaderState.Type)
  365. {
  366. ReadBsonType();
  367. }
  368. if (_state == BsonReaderState.Name)
  369. {
  370. // ignore name
  371. SkipName();
  372. }
  373. if (_state != BsonReaderState.Value)
  374. {
  375. ThrowInvalidState(methodName, BsonReaderState.Value);
  376. }
  377. if (_currentBsonType != requiredBsonType)
  378. {
  379. var message = string.Format(
  380. "{0} can only be called when CurrentBsonType is {1}, not when CurrentBsonType is {2}.",
  381. methodName, requiredBsonType, _currentBsonType);
  382. throw new InvalidOperationException(message);
  383. }
  384. }
  385. }
  386. }