/* 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;
}
}
}