/* Copyright 2010-2014 MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; using System.Text; using System.Text.RegularExpressions; namespace MongoDB.Bson { /// /// A static class containing BSON utility methods. /// public static class BsonUtils { // public static methods /// /// Gets a friendly class name suitable for use in error messages. /// /// The type. /// A friendly class name. public static string GetFriendlyTypeName(Type type) { if (!type.IsGenericType) { return type.Name; } var sb = new StringBuilder(); sb.AppendFormat("{0}<", Regex.Replace(type.Name, @"\`\d+$", "")); foreach (var typeParameter in type.GetGenericArguments()) { sb.AppendFormat("{0}, ", GetFriendlyTypeName(typeParameter)); } sb.Remove(sb.Length - 2, 2); sb.Append(">"); return sb.ToString(); } /// /// Parses a hex string into its equivalent byte array. /// /// The hex string to parse. /// The byte equivalent of the hex string. public static byte[] ParseHexString(string s) { if (s == null) { throw new ArgumentNullException("s"); } byte[] bytes; if ((s.Length & 1) != 0) { s = "0" + s; // make length of s even } bytes = new byte[s.Length / 2]; for (int i = 0; i < bytes.Length; i++) { string hex = s.Substring(2 * i, 2); try { byte b = Convert.ToByte(hex, 16); bytes[i] = b; } catch (FormatException e) { throw new FormatException( string.Format("Invalid hex string {0}. Problem with substring {1} starting at position {2}", s, hex, 2 * i), e); } } return bytes; } /// /// Converts from number of milliseconds since Unix epoch to DateTime. /// /// The number of milliseconds since Unix epoch. /// A DateTime. public static DateTime ToDateTimeFromMillisecondsSinceEpoch(long millisecondsSinceEpoch) { if (millisecondsSinceEpoch < BsonConstants.DateTimeMinValueMillisecondsSinceEpoch || millisecondsSinceEpoch > BsonConstants.DateTimeMaxValueMillisecondsSinceEpoch) { var message = string.Format( "The value {0} for the BsonDateTime MillisecondsSinceEpoch is outside the"+ "range that can be converted to a .NET DateTime.", millisecondsSinceEpoch); throw new ArgumentOutOfRangeException("millisecondsSinceEpoch", message); } // MaxValue has to be handled specially to avoid rounding errors if (millisecondsSinceEpoch == BsonConstants.DateTimeMaxValueMillisecondsSinceEpoch) { return DateTime.SpecifyKind(DateTime.MaxValue, DateTimeKind.Utc); } else { return BsonConstants.UnixEpoch.AddTicks(millisecondsSinceEpoch * 10000); } } /// /// Converts a byte array to a hex string. /// /// The byte array. /// A hex string. public static string ToHexString(byte[] bytes) { if (bytes == null) { throw new ArgumentNullException("bytes"); } var sb = new StringBuilder(bytes.Length * 2); foreach (var b in bytes) { sb.AppendFormat("{0:x2}", b); } return sb.ToString(); } /// /// Converts a DateTime to local time (with special handling for MinValue and MaxValue). /// /// A DateTime. /// The DateTime in local time. public static DateTime ToLocalTime(DateTime dateTime) { if (dateTime == DateTime.MinValue) { return DateTime.SpecifyKind(DateTime.MinValue, DateTimeKind.Local); } else if (dateTime == DateTime.MaxValue) { return DateTime.SpecifyKind(DateTime.MaxValue, DateTimeKind.Local); } else { return dateTime.ToLocalTime(); } } /// /// Converts a DateTime to number of milliseconds since Unix epoch. /// /// A DateTime. /// Number of seconds since Unix epoch. public static long ToMillisecondsSinceEpoch(DateTime dateTime) { var utcDateTime = ToUniversalTime(dateTime); return (utcDateTime - BsonConstants.UnixEpoch).Ticks / 10000; } /// /// Converts a DateTime to UTC (with special handling for MinValue and MaxValue). /// /// A DateTime. /// The DateTime in UTC. public static DateTime ToUniversalTime(DateTime dateTime) { if (dateTime == DateTime.MinValue) { return DateTime.SpecifyKind(DateTime.MinValue, DateTimeKind.Utc); } else if (dateTime == DateTime.MaxValue) { return DateTime.SpecifyKind(DateTime.MaxValue, DateTimeKind.Utc); } else { return dateTime.ToUniversalTime(); } } /// /// Tries to parse a hex string to a byte array. /// /// The hex string. /// A byte array. /// True if the hex string was successfully parsed. public static bool TryParseHexString(string s, out byte[] bytes) { try { bytes = ParseHexString(s); } catch { bytes = null; return false; } return true; } } }