BsonStreamExtensions.cs 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  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. 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. if (b == -1)
  92. {
  93. throw new EndOfStreamException();
  94. }
  95. return b != 0;
  96. }
  97. /// <summary>
  98. /// Reads the BSON type.
  99. /// </summary>
  100. /// <param name="stream">The stream.</param>
  101. /// <returns>The BSON type.</returns>
  102. public static BsonType ReadBsonType(this BsonStream stream)
  103. {
  104. if (stream == null)
  105. {
  106. throw new ArgumentNullException("stream");
  107. }
  108. var b = stream.ReadByte();
  109. if (b == -1)
  110. {
  111. throw new EndOfStreamException();
  112. }
  113. if (!__validBsonTypes[b])
  114. {
  115. var message = string.Format("Detected unknown BSON type \"\\x{0:x2}\". Are you using the latest driver version?", b);
  116. throw new FormatException(message);
  117. }
  118. return (BsonType)b;
  119. }
  120. /// <summary>
  121. /// Reads bytes from the stream.
  122. /// </summary>
  123. /// <param name="stream">The stream.</param>
  124. /// <param name="buffer">The buffer.</param>
  125. /// <param name="offset">The offset.</param>
  126. /// <param name="count">The count.</param>
  127. public static void ReadBytes(this BsonStream stream, byte[] buffer, int offset, int count)
  128. {
  129. if (stream == null)
  130. {
  131. throw new ArgumentNullException("stream");
  132. }
  133. if (buffer == null)
  134. {
  135. throw new ArgumentNullException("buffer");
  136. }
  137. if (offset < 0 || offset > buffer.Length)
  138. {
  139. throw new ArgumentOutOfRangeException("offset");
  140. }
  141. if (count < 0 || offset + count > buffer.Length)
  142. {
  143. throw new ArgumentOutOfRangeException("count");
  144. }
  145. if (count == 1)
  146. {
  147. var b = stream.ReadByte();
  148. if (b == -1)
  149. {
  150. throw new EndOfStreamException();
  151. }
  152. buffer[offset] = (byte)b;
  153. }
  154. else
  155. {
  156. while (count > 0)
  157. {
  158. var bytesRead = stream.Read(buffer, offset, count);
  159. if (bytesRead == 0)
  160. {
  161. throw new EndOfStreamException();
  162. }
  163. offset += bytesRead;
  164. count -= bytesRead;
  165. }
  166. }
  167. }
  168. /// <summary>
  169. /// Reads bytes from the stream.
  170. /// </summary>
  171. /// <param name="stream">The stream.</param>
  172. /// <param name="count">The count.</param>
  173. /// <returns>The bytes.</returns>
  174. public static byte[] ReadBytes(this BsonStream stream, int count)
  175. {
  176. if (stream == null)
  177. {
  178. throw new ArgumentNullException("stream");
  179. }
  180. if (count < 0)
  181. {
  182. throw new ArgumentOutOfRangeException("count");
  183. }
  184. var bytes = new byte[count];
  185. stream.ReadBytes(bytes, 0, count);
  186. return bytes;
  187. }
  188. /// <summary>
  189. /// Writes a binary sub type to the stream.
  190. /// </summary>
  191. /// <param name="stream">The stream.</param>
  192. /// <param name="value">The value.</param>
  193. public static void WriteBinarySubType(this BsonStream stream, BsonBinarySubType value)
  194. {
  195. if (stream == null)
  196. {
  197. throw new ArgumentNullException("stream");
  198. }
  199. stream.WriteByte((byte)value);
  200. }
  201. /// <summary>
  202. /// Writes a boolean to the stream.
  203. /// </summary>
  204. /// <param name="stream">The stream.</param>
  205. /// <param name="value">The value.</param>
  206. public static void WriteBoolean(this BsonStream stream, bool value)
  207. {
  208. if (stream == null)
  209. {
  210. throw new ArgumentNullException("stream");
  211. }
  212. stream.WriteByte(value ? (byte)1 : (byte)0);
  213. }
  214. /// <summary>
  215. /// Writes a BsonType to the stream.
  216. /// </summary>
  217. /// <param name="stream">The stream.</param>
  218. /// <param name="value">The value.</param>
  219. public static void WriteBsonType(this BsonStream stream, BsonType value)
  220. {
  221. if (stream == null)
  222. {
  223. throw new ArgumentNullException("stream");
  224. }
  225. stream.WriteByte((byte)value);
  226. }
  227. /// <summary>
  228. /// Writes bytes to the stream.
  229. /// </summary>
  230. /// <param name="stream">The stream.</param>
  231. /// <param name="buffer">The buffer.</param>
  232. /// <param name="offset">The offset.</param>
  233. /// <param name="count">The count.</param>
  234. public static void WriteBytes(this BsonStream stream, byte[] buffer, int offset, int count)
  235. {
  236. if (stream == null)
  237. {
  238. throw new ArgumentNullException("stream");
  239. }
  240. if (buffer == null)
  241. {
  242. throw new ArgumentNullException("buffer");
  243. }
  244. if (offset < 0 || offset > buffer.Length)
  245. {
  246. throw new ArgumentOutOfRangeException("offset");
  247. }
  248. if (count < 0 || offset + count > buffer.Length)
  249. {
  250. throw new ArgumentOutOfRangeException("count");
  251. }
  252. if (count == 1)
  253. {
  254. stream.WriteByte(buffer[offset]);
  255. }
  256. else
  257. {
  258. stream.Write(buffer, offset, count);
  259. }
  260. }
  261. /// <summary>
  262. /// Writes a slice to the stream.
  263. /// </summary>
  264. /// <param name="stream">The stream.</param>
  265. /// <param name="slice">The slice.</param>
  266. public static void WriteSlice(this BsonStream stream, IByteBuffer slice)
  267. {
  268. if (stream == null)
  269. {
  270. throw new ArgumentNullException("stream");
  271. }
  272. if (slice == null)
  273. {
  274. throw new ArgumentNullException("slice");
  275. }
  276. var position = 0;
  277. var count = slice.Length;
  278. while (count > 0)
  279. {
  280. var segment = slice.AccessBackingBytes(position);
  281. var partialCount = Math.Min(count, segment.Count);
  282. stream.WriteBytes(segment.Array, segment.Offset, partialCount);
  283. position += partialCount;
  284. count -= partialCount;
  285. }
  286. }
  287. }
  288. }