BsonStreamExtensions.cs 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  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.IO;
  17. namespace MongoDB.Bson.IO
  18. {
  19. /// <summary>
  20. /// Represents extension methods on BsonStream.
  21. /// </summary>
  22. public static class BsonStreamExtensions
  23. {
  24. // static fields
  25. private static readonly bool[] __validBsonTypes = new bool[256];
  26. // static constructor
  27. static BsonStreamExtensions()
  28. {
  29. foreach (BsonType bsonType in Enum.GetValues(typeof(BsonType)))
  30. {
  31. __validBsonTypes[(byte)bsonType] = true;
  32. }
  33. }
  34. // static methods
  35. /// <summary>
  36. /// Backpatches the size.
  37. /// </summary>
  38. /// <param name="stream">The stream.</param>
  39. /// <param name="startPosition">The start position.</param>
  40. public static void BackpatchSize(this BsonStream stream, long startPosition)
  41. {
  42. if (stream == null)
  43. {
  44. throw new ArgumentNullException("stream");
  45. }
  46. if (startPosition < 0 || startPosition > stream.Length)
  47. {
  48. throw new ArgumentOutOfRangeException("startPosition");
  49. }
  50. var size = stream.Position - startPosition;
  51. if (size > int.MaxValue)
  52. {
  53. var message = string.Format("Size {0} is larger than {1} (Int32.MaxValue).", size, int.MaxValue);
  54. throw new FormatException(message);
  55. }
  56. var endPosition = stream.Position;
  57. stream.Position = startPosition;
  58. stream.WriteInt32((int)size);
  59. stream.Position = endPosition;
  60. }
  61. /// <summary>
  62. /// Reads the binary sub type.
  63. /// </summary>
  64. /// <param name="stream">The stream.</param>
  65. /// <returns>The binary sub type.</returns>
  66. public static BsonBinarySubType ReadBinarySubType(this BsonStream stream)
  67. {
  68. if (stream == null)
  69. {
  70. throw new ArgumentNullException("stream");
  71. }
  72. var b = stream.ReadByte();
  73. if (b == -1)
  74. {
  75. throw new EndOfStreamException();
  76. }
  77. return (BsonBinarySubType)b;
  78. }
  79. /// <summary>
  80. /// Reads a boolean from the stream.
  81. /// </summary>
  82. /// <param name="stream">The stream.</param>
  83. /// <returns>A boolean.</returns>
  84. public static bool ReadBoolean(this BsonStream stream)
  85. {
  86. if (stream == null)
  87. {
  88. throw new ArgumentNullException("stream");
  89. }
  90. var b = stream.ReadByte();
  91. switch (b)
  92. {
  93. case -1:
  94. throw new EndOfStreamException();
  95. case 0:
  96. return false;
  97. case 1:
  98. return true;
  99. default:
  100. throw new FormatException($"Invalid BsonBoolean value: {b}.");
  101. }
  102. }
  103. /// <summary>
  104. /// Reads the BSON type.
  105. /// </summary>
  106. /// <param name="stream">The stream.</param>
  107. /// <returns>The BSON type.</returns>
  108. public static BsonType ReadBsonType(this BsonStream stream)
  109. {
  110. if (stream == null)
  111. {
  112. throw new ArgumentNullException("stream");
  113. }
  114. var b = stream.ReadByte();
  115. if (b == -1)
  116. {
  117. throw new EndOfStreamException();
  118. }
  119. if (!__validBsonTypes[b])
  120. {
  121. var message = string.Format("Detected unknown BSON type \"\\x{0:x2}\". Are you using the latest driver version?", b);
  122. throw new FormatException(message);
  123. }
  124. return (BsonType)b;
  125. }
  126. /// <summary>
  127. /// Reads bytes from the stream.
  128. /// </summary>
  129. /// <param name="stream">The stream.</param>
  130. /// <param name="buffer">The buffer.</param>
  131. /// <param name="offset">The offset.</param>
  132. /// <param name="count">The count.</param>
  133. public static void ReadBytes(this BsonStream stream, byte[] buffer, int offset, int count)
  134. {
  135. if (stream == null)
  136. {
  137. throw new ArgumentNullException("stream");
  138. }
  139. if (buffer == null)
  140. {
  141. throw new ArgumentNullException("buffer");
  142. }
  143. if (offset < 0 || offset > buffer.Length)
  144. {
  145. throw new ArgumentOutOfRangeException("offset");
  146. }
  147. if (count < 0 || offset + count > buffer.Length)
  148. {
  149. throw new ArgumentOutOfRangeException("count");
  150. }
  151. if (count == 1)
  152. {
  153. var b = stream.ReadByte();
  154. if (b == -1)
  155. {
  156. throw new EndOfStreamException();
  157. }
  158. buffer[offset] = (byte)b;
  159. }
  160. else
  161. {
  162. while (count > 0)
  163. {
  164. var bytesRead = stream.Read(buffer, offset, count);
  165. if (bytesRead == 0)
  166. {
  167. throw new EndOfStreamException();
  168. }
  169. offset += bytesRead;
  170. count -= bytesRead;
  171. }
  172. }
  173. }
  174. /// <summary>
  175. /// Reads bytes from the stream.
  176. /// </summary>
  177. /// <param name="stream">The stream.</param>
  178. /// <param name="count">The count.</param>
  179. /// <returns>The bytes.</returns>
  180. public static byte[] ReadBytes(this BsonStream stream, int count)
  181. {
  182. if (stream == null)
  183. {
  184. throw new ArgumentNullException("stream");
  185. }
  186. if (count < 0)
  187. {
  188. throw new ArgumentOutOfRangeException("count");
  189. }
  190. var bytes = new byte[count];
  191. stream.ReadBytes(bytes, 0, count);
  192. return bytes;
  193. }
  194. /// <summary>
  195. /// Writes a binary sub type to the stream.
  196. /// </summary>
  197. /// <param name="stream">The stream.</param>
  198. /// <param name="value">The value.</param>
  199. public static void WriteBinarySubType(this BsonStream stream, BsonBinarySubType value)
  200. {
  201. if (stream == null)
  202. {
  203. throw new ArgumentNullException("stream");
  204. }
  205. stream.WriteByte((byte)value);
  206. }
  207. /// <summary>
  208. /// Writes a boolean to the stream.
  209. /// </summary>
  210. /// <param name="stream">The stream.</param>
  211. /// <param name="value">The value.</param>
  212. public static void WriteBoolean(this BsonStream stream, bool value)
  213. {
  214. if (stream == null)
  215. {
  216. throw new ArgumentNullException("stream");
  217. }
  218. stream.WriteByte(value ? (byte)1 : (byte)0);
  219. }
  220. /// <summary>
  221. /// Writes a BsonType to the stream.
  222. /// </summary>
  223. /// <param name="stream">The stream.</param>
  224. /// <param name="value">The value.</param>
  225. public static void WriteBsonType(this BsonStream stream, BsonType value)
  226. {
  227. if (stream == null)
  228. {
  229. throw new ArgumentNullException("stream");
  230. }
  231. stream.WriteByte((byte)value);
  232. }
  233. /// <summary>
  234. /// Writes bytes to the stream.
  235. /// </summary>
  236. /// <param name="stream">The stream.</param>
  237. /// <param name="buffer">The buffer.</param>
  238. /// <param name="offset">The offset.</param>
  239. /// <param name="count">The count.</param>
  240. public static void WriteBytes(this BsonStream stream, byte[] buffer, int offset, int count)
  241. {
  242. if (stream == null)
  243. {
  244. throw new ArgumentNullException("stream");
  245. }
  246. if (buffer == null)
  247. {
  248. throw new ArgumentNullException("buffer");
  249. }
  250. if (offset < 0 || offset > buffer.Length)
  251. {
  252. throw new ArgumentOutOfRangeException("offset");
  253. }
  254. if (count < 0 || offset + count > buffer.Length)
  255. {
  256. throw new ArgumentOutOfRangeException("count");
  257. }
  258. if (count == 1)
  259. {
  260. stream.WriteByte(buffer[offset]);
  261. }
  262. else
  263. {
  264. stream.Write(buffer, offset, count);
  265. }
  266. }
  267. /// <summary>
  268. /// Writes a slice to the stream.
  269. /// </summary>
  270. /// <param name="stream">The stream.</param>
  271. /// <param name="slice">The slice.</param>
  272. public static void WriteSlice(this BsonStream stream, IByteBuffer slice)
  273. {
  274. if (stream == null)
  275. {
  276. throw new ArgumentNullException("stream");
  277. }
  278. if (slice == null)
  279. {
  280. throw new ArgumentNullException("slice");
  281. }
  282. var position = 0;
  283. var count = slice.Length;
  284. while (count > 0)
  285. {
  286. var segment = slice.AccessBackingBytes(position);
  287. var partialCount = Math.Min(count, segment.Count);
  288. stream.WriteBytes(segment.Array, segment.Offset, partialCount);
  289. position += partialCount;
  290. count -= partialCount;
  291. }
  292. }
  293. }
  294. }