BsonUtils.cs 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  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.Reflection;
  17. using System.Text;
  18. using System.Text.RegularExpressions;
  19. namespace MongoDB.Bson
  20. {
  21. /// <summary>
  22. /// A static class containing BSON utility methods.
  23. /// </summary>
  24. public static class BsonUtils
  25. {
  26. // public static methods
  27. /// <summary>
  28. /// Gets a friendly class name suitable for use in error messages.
  29. /// </summary>
  30. /// <param name="type">The type.</param>
  31. /// <returns>A friendly class name.</returns>
  32. public static string GetFriendlyTypeName(Type type)
  33. {
  34. var typeInfo = type.GetTypeInfo();
  35. if (!typeInfo.IsGenericType)
  36. {
  37. return type.Name;
  38. }
  39. var sb = new StringBuilder();
  40. sb.AppendFormat("{0}<", Regex.Replace(type.Name, @"\`\d+$", ""));
  41. foreach (var typeParameter in type.GetTypeInfo().GetGenericArguments())
  42. {
  43. sb.AppendFormat("{0}, ", GetFriendlyTypeName(typeParameter));
  44. }
  45. sb.Remove(sb.Length - 2, 2);
  46. sb.Append(">");
  47. return sb.ToString();
  48. }
  49. /// <summary>
  50. /// Parses a hex string into its equivalent byte array.
  51. /// </summary>
  52. /// <param name="s">The hex string to parse.</param>
  53. /// <returns>The byte equivalent of the hex string.</returns>
  54. public static byte[] ParseHexString(string s)
  55. {
  56. if (s == null)
  57. {
  58. throw new ArgumentNullException("s");
  59. }
  60. byte[] bytes;
  61. if ((s.Length & 1) != 0)
  62. {
  63. s = "0" + s; // make length of s even
  64. }
  65. bytes = new byte[s.Length / 2];
  66. for (int i = 0; i < bytes.Length; i++)
  67. {
  68. string hex = s.Substring(2 * i, 2);
  69. try
  70. {
  71. byte b = Convert.ToByte(hex, 16);
  72. bytes[i] = b;
  73. }
  74. catch (FormatException e)
  75. {
  76. throw new FormatException(
  77. string.Format("Invalid hex string {0}. Problem with substring {1} starting at position {2}",
  78. s,
  79. hex,
  80. 2 * i),
  81. e);
  82. }
  83. }
  84. return bytes;
  85. }
  86. /// <summary>
  87. /// Converts from number of milliseconds since Unix epoch to DateTime.
  88. /// </summary>
  89. /// <param name="millisecondsSinceEpoch">The number of milliseconds since Unix epoch.</param>
  90. /// <returns>A DateTime.</returns>
  91. public static DateTime ToDateTimeFromMillisecondsSinceEpoch(long millisecondsSinceEpoch)
  92. {
  93. if (millisecondsSinceEpoch < BsonConstants.DateTimeMinValueMillisecondsSinceEpoch ||
  94. millisecondsSinceEpoch > BsonConstants.DateTimeMaxValueMillisecondsSinceEpoch)
  95. {
  96. var message = string.Format(
  97. "The value {0} for the BsonDateTime MillisecondsSinceEpoch is outside the"+
  98. "range that can be converted to a .NET DateTime.",
  99. millisecondsSinceEpoch);
  100. throw new ArgumentOutOfRangeException("millisecondsSinceEpoch", message);
  101. }
  102. // MaxValue has to be handled specially to avoid rounding errors
  103. if (millisecondsSinceEpoch == BsonConstants.DateTimeMaxValueMillisecondsSinceEpoch)
  104. {
  105. return DateTime.SpecifyKind(DateTime.MaxValue, DateTimeKind.Utc);
  106. }
  107. else
  108. {
  109. return BsonConstants.UnixEpoch.AddTicks(millisecondsSinceEpoch * 10000);
  110. }
  111. }
  112. /// <summary>
  113. /// Converts a byte array to a hex string.
  114. /// </summary>
  115. /// <param name="bytes">The byte array.</param>
  116. /// <returns>A hex string.</returns>
  117. public static string ToHexString(byte[] bytes)
  118. {
  119. if (bytes == null)
  120. {
  121. throw new ArgumentNullException("bytes");
  122. }
  123. var sb = new StringBuilder(bytes.Length * 2);
  124. foreach (var b in bytes)
  125. {
  126. sb.AppendFormat("{0:x2}", b);
  127. }
  128. return sb.ToString();
  129. }
  130. /// <summary>
  131. /// Converts a DateTime to local time (with special handling for MinValue and MaxValue).
  132. /// </summary>
  133. /// <param name="dateTime">A DateTime.</param>
  134. /// <returns>The DateTime in local time.</returns>
  135. public static DateTime ToLocalTime(DateTime dateTime)
  136. {
  137. if (dateTime == DateTime.MinValue)
  138. {
  139. return DateTime.SpecifyKind(DateTime.MinValue, DateTimeKind.Local);
  140. }
  141. else if (dateTime == DateTime.MaxValue)
  142. {
  143. return DateTime.SpecifyKind(DateTime.MaxValue, DateTimeKind.Local);
  144. }
  145. else
  146. {
  147. return dateTime.ToLocalTime();
  148. }
  149. }
  150. /// <summary>
  151. /// Converts a DateTime to number of milliseconds since Unix epoch.
  152. /// </summary>
  153. /// <param name="dateTime">A DateTime.</param>
  154. /// <returns>Number of seconds since Unix epoch.</returns>
  155. public static long ToMillisecondsSinceEpoch(DateTime dateTime)
  156. {
  157. var utcDateTime = ToUniversalTime(dateTime);
  158. return (utcDateTime - BsonConstants.UnixEpoch).Ticks / 10000;
  159. }
  160. /// <summary>
  161. /// Converts a DateTime to UTC (with special handling for MinValue and MaxValue).
  162. /// </summary>
  163. /// <param name="dateTime">A DateTime.</param>
  164. /// <returns>The DateTime in UTC.</returns>
  165. public static DateTime ToUniversalTime(DateTime dateTime)
  166. {
  167. if (dateTime == DateTime.MinValue)
  168. {
  169. return DateTime.SpecifyKind(DateTime.MinValue, DateTimeKind.Utc);
  170. }
  171. else if (dateTime == DateTime.MaxValue)
  172. {
  173. return DateTime.SpecifyKind(DateTime.MaxValue, DateTimeKind.Utc);
  174. }
  175. else
  176. {
  177. return dateTime.ToUniversalTime();
  178. }
  179. }
  180. /// <summary>
  181. /// Tries to parse a hex string to a byte array.
  182. /// </summary>
  183. /// <param name="s">The hex string.</param>
  184. /// <param name="bytes">A byte array.</param>
  185. /// <returns>True if the hex string was successfully parsed.</returns>
  186. public static bool TryParseHexString(string s, out byte[] bytes)
  187. {
  188. try
  189. {
  190. bytes = ParseHexString(s);
  191. }
  192. catch
  193. {
  194. bytes = null;
  195. return false;
  196. }
  197. return true;
  198. }
  199. }
  200. }