BsonBinaryData.cs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417
  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.Linq;
  17. namespace MongoDB.Bson
  18. {
  19. /// <summary>
  20. /// Represents BSON binary data.
  21. /// </summary>
  22. [Serializable]
  23. public class BsonBinaryData : BsonValue, IComparable<BsonBinaryData>, IEquatable<BsonBinaryData>
  24. {
  25. // private fields
  26. private byte[] _bytes;
  27. private BsonBinarySubType _subType;
  28. private GuidRepresentation _guidRepresentation; // only relevant if subType is UuidStandard or UuidLegacy
  29. // constructors
  30. /// <summary>
  31. /// Initializes a new instance of the BsonBinaryData class.
  32. /// </summary>
  33. /// <param name="bytes">The binary data.</param>
  34. public BsonBinaryData(byte[] bytes)
  35. : this(bytes, BsonBinarySubType.Binary)
  36. {
  37. }
  38. /// <summary>
  39. /// Initializes a new instance of the BsonBinaryData class.
  40. /// </summary>
  41. /// <param name="bytes">The binary data.</param>
  42. /// <param name="subType">The binary data subtype.</param>
  43. public BsonBinaryData(byte[] bytes, BsonBinarySubType subType)
  44. : this(bytes, subType, GuidRepresentation.Unspecified)
  45. {
  46. }
  47. /// <summary>
  48. /// Initializes a new instance of the BsonBinaryData class.
  49. /// </summary>
  50. /// <param name="bytes">The binary data.</param>
  51. /// <param name="subType">The binary data subtype.</param>
  52. /// <param name="guidRepresentation">The representation for Guids.</param>
  53. public BsonBinaryData(byte[] bytes, BsonBinarySubType subType, GuidRepresentation guidRepresentation)
  54. : base(BsonType.Binary)
  55. {
  56. if (bytes == null)
  57. {
  58. throw new ArgumentNullException("bytes");
  59. }
  60. if (subType == BsonBinarySubType.UuidStandard || subType == BsonBinarySubType.UuidLegacy)
  61. {
  62. if (bytes.Length != 16)
  63. {
  64. var message = string.Format(
  65. "Length must be 16, not {0}, when subType is {1}.",
  66. bytes.Length, subType);
  67. throw new ArgumentException(message);
  68. }
  69. var expectedSubType = (guidRepresentation == GuidRepresentation.Standard) ? BsonBinarySubType.UuidStandard : BsonBinarySubType.UuidLegacy;
  70. if (subType != expectedSubType)
  71. {
  72. var message = string.Format(
  73. "SubType must be {0}, not {1}, when GuidRepresentation is {2}.",
  74. expectedSubType, subType, GuidRepresentation);
  75. throw new ArgumentException(message);
  76. }
  77. }
  78. else
  79. {
  80. if (guidRepresentation != GuidRepresentation.Unspecified)
  81. {
  82. var message = string.Format(
  83. "GuidRepresentation must be Unspecified, not {0}, when SubType is not UuidStandard or UuidLegacy.",
  84. guidRepresentation);
  85. throw new ArgumentException(message);
  86. }
  87. }
  88. _bytes = bytes;
  89. _subType = subType;
  90. _guidRepresentation = guidRepresentation;
  91. }
  92. /// <summary>
  93. /// Initializes a new instance of the BsonBinaryData class.
  94. /// </summary>
  95. /// <param name="guid">A Guid.</param>
  96. public BsonBinaryData(Guid guid)
  97. : this(guid, BsonDefaults.GuidRepresentation)
  98. {
  99. }
  100. /// <summary>
  101. /// Initializes a new instance of the BsonBinaryData class.
  102. /// </summary>
  103. /// <param name="guid">A Guid.</param>
  104. /// <param name="guidRepresentation">The representation for Guids.</param>
  105. public BsonBinaryData(Guid guid, GuidRepresentation guidRepresentation)
  106. : this(GuidConverter.ToBytes(guid, guidRepresentation), (guidRepresentation == GuidRepresentation.Standard) ? BsonBinarySubType.UuidStandard : BsonBinarySubType.UuidLegacy, guidRepresentation)
  107. {
  108. }
  109. // public properties
  110. /// <summary>
  111. /// Gets the binary data.
  112. /// </summary>
  113. public byte[] Bytes
  114. {
  115. get { return _bytes; }
  116. }
  117. /// <summary>
  118. /// Gets the representation to use when representing the Guid as BSON binary data.
  119. /// </summary>
  120. public GuidRepresentation GuidRepresentation
  121. {
  122. get { return _guidRepresentation; }
  123. }
  124. /// <summary>
  125. /// Gets the BsonBinaryData as a Guid if the subtype is UuidStandard or UuidLegacy, otherwise null.
  126. /// </summary>
  127. #pragma warning disable 618 // about obsolete BsonBinarySubType.OldBinary
  128. [Obsolete("Use Value instead.")]
  129. public override object RawValue
  130. {
  131. get
  132. {
  133. if (_subType == BsonBinarySubType.Binary || _subType == BsonBinarySubType.OldBinary)
  134. {
  135. return _bytes;
  136. }
  137. else if (_subType == BsonBinarySubType.UuidStandard || _subType == BsonBinarySubType.UuidLegacy)
  138. {
  139. return ToGuid();
  140. }
  141. else
  142. {
  143. return null;
  144. }
  145. }
  146. }
  147. #pragma warning restore 618
  148. /// <summary>
  149. /// Gets the binary data subtype.
  150. /// </summary>
  151. public BsonBinarySubType SubType
  152. {
  153. get { return _subType; }
  154. }
  155. // public operators
  156. /// <summary>
  157. /// Converts a byte array to a BsonBinaryData.
  158. /// </summary>
  159. /// <param name="bytes">A byte array.</param>
  160. /// <returns>A BsonBinaryData.</returns>
  161. public static implicit operator BsonBinaryData(byte[] bytes)
  162. {
  163. return new BsonBinaryData(bytes);
  164. }
  165. /// <summary>
  166. /// Converts a Guid to a BsonBinaryData.
  167. /// </summary>
  168. /// <param name="value">A Guid.</param>
  169. /// <returns>A BsonBinaryData.</returns>
  170. public static implicit operator BsonBinaryData(Guid value)
  171. {
  172. return new BsonBinaryData(value);
  173. }
  174. /// <summary>
  175. /// Compares two BsonBinaryData values.
  176. /// </summary>
  177. /// <param name="lhs">The first BsonBinaryData.</param>
  178. /// <param name="rhs">The other BsonBinaryData.</param>
  179. /// <returns>True if the two BsonBinaryData values are not equal according to ==.</returns>
  180. public static bool operator !=(BsonBinaryData lhs, BsonBinaryData rhs)
  181. {
  182. return !(lhs == rhs);
  183. }
  184. /// <summary>
  185. /// Compares two BsonBinaryData values.
  186. /// </summary>
  187. /// <param name="lhs">The first BsonBinaryData.</param>
  188. /// <param name="rhs">The other BsonBinaryData.</param>
  189. /// <returns>True if the two BsonBinaryData values are equal according to ==.</returns>
  190. public static bool operator ==(BsonBinaryData lhs, BsonBinaryData rhs)
  191. {
  192. if (object.ReferenceEquals(lhs, null)) { return object.ReferenceEquals(rhs, null); }
  193. return lhs.Equals(rhs);
  194. }
  195. // public static methods
  196. /// <summary>
  197. /// Creates a new BsonBinaryData.
  198. /// </summary>
  199. /// <param name="bytes">The binary data.</param>
  200. /// <returns>A BsonBinaryData or null.</returns>
  201. [Obsolete("Use new BsonBinaryData(byte[] bytes) instead.")]
  202. public static BsonBinaryData Create(byte[] bytes)
  203. {
  204. return Create(bytes, BsonBinarySubType.Binary);
  205. }
  206. /// <summary>
  207. /// Creates a new BsonBinaryData.
  208. /// </summary>
  209. /// <param name="bytes">The binary data.</param>
  210. /// <param name="subType">The binary data subtype.</param>
  211. /// <returns>A BsonBinaryData or null.</returns>
  212. [Obsolete("Use new BsonBinaryData(byte[] bytes, BsonBinarySubtype subType) instead.")]
  213. public static BsonBinaryData Create(byte[] bytes, BsonBinarySubType subType)
  214. {
  215. if (bytes != null)
  216. {
  217. return new BsonBinaryData(bytes, subType);
  218. }
  219. else
  220. {
  221. return null;
  222. }
  223. }
  224. /// <summary>
  225. /// Creates a new BsonBinaryData.
  226. /// </summary>
  227. /// <param name="bytes">The binary data.</param>
  228. /// <param name="subType">The binary data subtype.</param>
  229. /// <param name="guidRepresentation">The representation for Guids.</param>
  230. /// <returns>A BsonBinaryData or null.</returns>
  231. [Obsolete("Use new BsonBinaryData(byte[] bytes, BsonBinarySubtype subType, GuidRepresentation guidRepresentation) instead.")]
  232. public static BsonBinaryData Create(
  233. byte[] bytes,
  234. BsonBinarySubType subType,
  235. GuidRepresentation guidRepresentation)
  236. {
  237. if (bytes != null)
  238. {
  239. return new BsonBinaryData(bytes, subType, guidRepresentation);
  240. }
  241. else
  242. {
  243. return null;
  244. }
  245. }
  246. /// <summary>
  247. /// Creates a new BsonBinaryData.
  248. /// </summary>
  249. /// <param name="guid">A Guid.</param>
  250. /// <returns>A BsonBinaryData.</returns>
  251. [Obsolete("Use new BsonBinaryData(Guid guid) instead.")]
  252. public static BsonBinaryData Create(Guid guid)
  253. {
  254. return new BsonBinaryData(guid);
  255. }
  256. /// <summary>
  257. /// Creates a new BsonBinaryData.
  258. /// </summary>
  259. /// <param name="guid">A Guid.</param>
  260. /// <param name="guidRepresentation">The representation for Guids.</param>
  261. /// <returns>A BsonBinaryData.</returns>
  262. [Obsolete("Use new BsonBinaryData(Guid guid, GuidRepresentation guidRepresentation) instead.")]
  263. public static BsonBinaryData Create(Guid guid, GuidRepresentation guidRepresentation)
  264. {
  265. return new BsonBinaryData(guid, guidRepresentation);
  266. }
  267. /// <summary>
  268. /// Creates a new BsonBinaryData.
  269. /// </summary>
  270. /// <param name="value">An object to be mapped to a BsonBinaryData.</param>
  271. /// <returns>A BsonBinaryData or null.</returns>
  272. public new static BsonBinaryData Create(object value)
  273. {
  274. if (value != null)
  275. {
  276. return (BsonBinaryData)BsonTypeMapper.MapToBsonValue(value, BsonType.Binary);
  277. }
  278. else
  279. {
  280. return null;
  281. }
  282. }
  283. // public methods
  284. /// <summary>
  285. /// Compares this BsonBinaryData to another BsonBinaryData.
  286. /// </summary>
  287. /// <param name="other">The other BsonBinaryData.</param>
  288. /// <returns>A 32-bit signed integer that indicates whether this BsonBinaryData is less than, equal to, or greather than the other.</returns>
  289. public int CompareTo(BsonBinaryData other)
  290. {
  291. if (other == null) { return 1; }
  292. int r = _subType.CompareTo(other._subType);
  293. if (r != 0) { return r; }
  294. for (int i = 0; i < _bytes.Length && i < other._bytes.Length; i++)
  295. {
  296. r = _bytes[i].CompareTo(other._bytes[i]);
  297. if (r != 0) { return r; }
  298. }
  299. return _bytes.Length.CompareTo(other._bytes.Length);
  300. }
  301. /// <summary>
  302. /// Compares the BsonBinaryData to another BsonValue.
  303. /// </summary>
  304. /// <param name="other">The other BsonValue.</param>
  305. /// <returns>A 32-bit signed integer that indicates whether this BsonBinaryData is less than, equal to, or greather than the other BsonValue.</returns>
  306. public override int CompareTo(BsonValue other)
  307. {
  308. if (other == null) { return 1; }
  309. var otherBinaryData = other as BsonBinaryData;
  310. if (otherBinaryData != null)
  311. {
  312. return CompareTo(otherBinaryData);
  313. }
  314. return CompareTypeTo(other);
  315. }
  316. /// <summary>
  317. /// Compares this BsonBinaryData to another BsonBinaryData.
  318. /// </summary>
  319. /// <param name="rhs">The other BsonBinaryData.</param>
  320. /// <returns>True if the two BsonBinaryData values are equal.</returns>
  321. public bool Equals(BsonBinaryData rhs)
  322. {
  323. if (object.ReferenceEquals(rhs, null) || GetType() != rhs.GetType()) { return false; }
  324. // note: guidRepresentation is not considered when testing for Equality
  325. return object.ReferenceEquals(this, rhs) || _subType == rhs._subType && _bytes.SequenceEqual(rhs._bytes);
  326. }
  327. /// <summary>
  328. /// Compares this BsonBinaryData to another object.
  329. /// </summary>
  330. /// <param name="obj">The other object.</param>
  331. /// <returns>True if the other object is a BsonBinaryData and equal to this one.</returns>
  332. public override bool Equals(object obj)
  333. {
  334. return Equals(obj as BsonBinaryData); // works even if obj is null or of a different type
  335. }
  336. /// <summary>
  337. /// Gets the hash code.
  338. /// </summary>
  339. /// <returns>The hash code.</returns>
  340. public override int GetHashCode()
  341. {
  342. // see Effective Java by Joshua Bloch
  343. // note: guidRepresentation is not considered when computing the hash code
  344. int hash = 17;
  345. hash = 37 * hash + BsonType.GetHashCode();
  346. foreach (byte b in _bytes)
  347. {
  348. hash = 37 * hash + b;
  349. }
  350. hash = 37 * hash + _subType.GetHashCode();
  351. return hash;
  352. }
  353. /// <summary>
  354. /// Converts this BsonBinaryData to a Guid.
  355. /// </summary>
  356. /// <returns>A Guid.</returns>
  357. public Guid ToGuid()
  358. {
  359. return ToGuid(_guidRepresentation);
  360. }
  361. /// <summary>
  362. /// Converts this BsonBinaryData to a Guid.
  363. /// </summary>
  364. /// <param name="guidRepresentation">The representation for Guids.</param>
  365. /// <returns>A Guid.</returns>
  366. public Guid ToGuid(GuidRepresentation guidRepresentation)
  367. {
  368. if (_subType != BsonBinarySubType.UuidStandard && _subType != BsonBinarySubType.UuidLegacy)
  369. {
  370. var message = string.Format("SubType must be UuidStandard or UuidLegacy, not {0}.", _subType);
  371. throw new InvalidOperationException(message);
  372. }
  373. if (guidRepresentation == GuidRepresentation.Unspecified)
  374. {
  375. throw new ArgumentException("GuidRepresentation cannot be Unspecified.");
  376. }
  377. return GuidConverter.FromBytes(_bytes, guidRepresentation);
  378. }
  379. /// <summary>
  380. /// Returns a string representation of the binary data.
  381. /// </summary>
  382. /// <returns>A string representation of the binary data.</returns>
  383. public override string ToString()
  384. {
  385. return string.Format("{0}:0x{1}", _subType, BsonUtils.ToHexString(_bytes));
  386. }
  387. }
  388. }