ConvertUtils
using Newtonsoft.Json.Serialization;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Reflection;
using System.Text.RegularExpressions;
namespace Newtonsoft.Json.Utilities
{
internal static class ConvertUtils
{
internal enum ConvertResult
{
Success,
CannotConvertNull,
NotInstantiableType,
NoValidConversion
}
private static readonly Dictionary<Type, PrimitiveTypeCode> TypeCodeMap = new Dictionary<Type, PrimitiveTypeCode> {
{
typeof(char),
PrimitiveTypeCode.Char
},
{
typeof(char?),
PrimitiveTypeCode.CharNullable
},
{
typeof(bool),
PrimitiveTypeCode.Boolean
},
{
typeof(bool?),
PrimitiveTypeCode.BooleanNullable
},
{
typeof(sbyte),
PrimitiveTypeCode.SByte
},
{
typeof(sbyte?),
PrimitiveTypeCode.SByteNullable
},
{
typeof(short),
PrimitiveTypeCode.Int16
},
{
typeof(short?),
PrimitiveTypeCode.Int16Nullable
},
{
typeof(ushort),
PrimitiveTypeCode.UInt16
},
{
typeof(ushort?),
PrimitiveTypeCode.UInt16Nullable
},
{
typeof(int),
PrimitiveTypeCode.Int32
},
{
typeof(int?),
PrimitiveTypeCode.Int32Nullable
},
{
typeof(byte),
PrimitiveTypeCode.Byte
},
{
typeof(byte?),
PrimitiveTypeCode.ByteNullable
},
{
typeof(uint),
PrimitiveTypeCode.UInt32
},
{
typeof(uint?),
PrimitiveTypeCode.UInt32Nullable
},
{
typeof(long),
PrimitiveTypeCode.Int64
},
{
typeof(long?),
PrimitiveTypeCode.Int64Nullable
},
{
typeof(ulong),
PrimitiveTypeCode.UInt64
},
{
typeof(ulong?),
PrimitiveTypeCode.UInt64Nullable
},
{
typeof(float),
PrimitiveTypeCode.Single
},
{
typeof(float?),
PrimitiveTypeCode.SingleNullable
},
{
typeof(double),
PrimitiveTypeCode.Double
},
{
typeof(double?),
PrimitiveTypeCode.DoubleNullable
},
{
typeof(DateTime),
PrimitiveTypeCode.DateTime
},
{
typeof(DateTime?),
PrimitiveTypeCode.DateTimeNullable
},
{
typeof(DateTimeOffset),
PrimitiveTypeCode.DateTimeOffset
},
{
typeof(DateTimeOffset?),
PrimitiveTypeCode.DateTimeOffsetNullable
},
{
typeof(decimal),
PrimitiveTypeCode.Decimal
},
{
typeof(decimal?),
PrimitiveTypeCode.DecimalNullable
},
{
typeof(Guid),
PrimitiveTypeCode.Guid
},
{
typeof(Guid?),
PrimitiveTypeCode.GuidNullable
},
{
typeof(TimeSpan),
PrimitiveTypeCode.TimeSpan
},
{
typeof(TimeSpan?),
PrimitiveTypeCode.TimeSpanNullable
},
{
typeof(Uri),
PrimitiveTypeCode.Uri
},
{
typeof(string),
PrimitiveTypeCode.String
},
{
typeof(byte[]),
PrimitiveTypeCode.Bytes
},
{
typeof(DBNull),
PrimitiveTypeCode.DBNull
}
};
private static readonly TypeInformation[] PrimitiveTypeCodes = new TypeInformation[19] {
new TypeInformation {
Type = typeof(object),
TypeCode = PrimitiveTypeCode.Empty
},
new TypeInformation {
Type = typeof(object),
TypeCode = PrimitiveTypeCode.Object
},
new TypeInformation {
Type = typeof(object),
TypeCode = PrimitiveTypeCode.DBNull
},
new TypeInformation {
Type = typeof(bool),
TypeCode = PrimitiveTypeCode.Boolean
},
new TypeInformation {
Type = typeof(char),
TypeCode = PrimitiveTypeCode.Char
},
new TypeInformation {
Type = typeof(sbyte),
TypeCode = PrimitiveTypeCode.SByte
},
new TypeInformation {
Type = typeof(byte),
TypeCode = PrimitiveTypeCode.Byte
},
new TypeInformation {
Type = typeof(short),
TypeCode = PrimitiveTypeCode.Int16
},
new TypeInformation {
Type = typeof(ushort),
TypeCode = PrimitiveTypeCode.UInt16
},
new TypeInformation {
Type = typeof(int),
TypeCode = PrimitiveTypeCode.Int32
},
new TypeInformation {
Type = typeof(uint),
TypeCode = PrimitiveTypeCode.UInt32
},
new TypeInformation {
Type = typeof(long),
TypeCode = PrimitiveTypeCode.Int64
},
new TypeInformation {
Type = typeof(ulong),
TypeCode = PrimitiveTypeCode.UInt64
},
new TypeInformation {
Type = typeof(float),
TypeCode = PrimitiveTypeCode.Single
},
new TypeInformation {
Type = typeof(double),
TypeCode = PrimitiveTypeCode.Double
},
new TypeInformation {
Type = typeof(decimal),
TypeCode = PrimitiveTypeCode.Decimal
},
new TypeInformation {
Type = typeof(DateTime),
TypeCode = PrimitiveTypeCode.DateTime
},
new TypeInformation {
Type = typeof(object),
TypeCode = PrimitiveTypeCode.Empty
},
new TypeInformation {
Type = typeof(string),
TypeCode = PrimitiveTypeCode.String
}
};
private static readonly ThreadSafeStore<StructMultiKey<Type, Type>, Func<object, object>> CastConverters = new ThreadSafeStore<StructMultiKey<Type, Type>, Func<object, object>>(CreateCastConverter);
public static PrimitiveTypeCode GetTypeCode(Type t)
{
bool isEnum;
return GetTypeCode(t, out isEnum);
}
public static PrimitiveTypeCode GetTypeCode(Type t, out bool isEnum)
{
if (TypeCodeMap.TryGetValue(t, out PrimitiveTypeCode value)) {
isEnum = false;
return value;
}
if (t.IsEnum()) {
isEnum = true;
return GetTypeCode(Enum.GetUnderlyingType(t));
}
if (ReflectionUtils.IsNullableType(t)) {
Type underlyingType = Nullable.GetUnderlyingType(t);
if (underlyingType.IsEnum()) {
Type t2 = typeof(Nullable<>).MakeGenericType(Enum.GetUnderlyingType(underlyingType));
isEnum = true;
return GetTypeCode(t2);
}
}
isEnum = false;
return PrimitiveTypeCode.Object;
}
public static TypeInformation GetTypeInformation(IConvertible convertable)
{
return PrimitiveTypeCodes[(int)convertable.GetTypeCode()];
}
public static bool IsConvertible(Type t)
{
return typeof(IConvertible).IsAssignableFrom(t);
}
public static TimeSpan ParseTimeSpan(string input)
{
return TimeSpan.Parse(input);
}
private static Func<object, object> CreateCastConverter(StructMultiKey<Type, Type> t)
{
Type value = t.Value1;
Type value2 = t.Value2;
MethodInfo methodInfo = value2.GetMethod("op_Implicit", new Type[1] {
value
}) ?? value2.GetMethod("op_Explicit", new Type[1] {
value
});
if ((object)methodInfo == null)
return null;
MethodCall<object, object> call = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall<object>(methodInfo);
return (object o) => call(null, o);
}
public static object Convert(object initialValue, CultureInfo culture, Type targetType)
{
object value;
switch (TryConvertInternal(initialValue, culture, targetType, out value)) {
case ConvertResult.Success:
return value;
case ConvertResult.CannotConvertNull:
throw new Exception("Can not convert null {0} into non-nullable {1}.".FormatWith(CultureInfo.InvariantCulture, initialValue.GetType(), targetType));
case ConvertResult.NotInstantiableType:
throw new ArgumentException("Target type {0} is not a value type or a non-abstract class.".FormatWith(CultureInfo.InvariantCulture, targetType), "targetType");
case ConvertResult.NoValidConversion:
throw new InvalidOperationException("Can not convert from {0} to {1}.".FormatWith(CultureInfo.InvariantCulture, initialValue.GetType(), targetType));
default:
throw new InvalidOperationException("Unexpected conversion result.");
}
}
private static bool TryConvert(object initialValue, CultureInfo culture, Type targetType, out object value)
{
try {
if (TryConvertInternal(initialValue, culture, targetType, out value) != 0) {
value = null;
return false;
}
return true;
} catch {
value = null;
return false;
}
}
private static ConvertResult TryConvertInternal(object initialValue, CultureInfo culture, Type targetType, out object value)
{
if (initialValue == null)
throw new ArgumentNullException("initialValue");
if (ReflectionUtils.IsNullableType(targetType))
targetType = Nullable.GetUnderlyingType(targetType);
Type type = initialValue.GetType();
if ((object)targetType == type) {
value = initialValue;
return ConvertResult.Success;
}
if (IsConvertible(initialValue.GetType()) && IsConvertible(targetType)) {
if (targetType.IsEnum()) {
if (initialValue is string) {
value = Enum.Parse(targetType, initialValue.ToString(), true);
return ConvertResult.Success;
}
if (IsInteger(initialValue)) {
value = Enum.ToObject(targetType, initialValue);
return ConvertResult.Success;
}
}
value = System.Convert.ChangeType(initialValue, targetType, culture);
return ConvertResult.Success;
}
object obj;
if ((obj = initialValue) is DateTime) {
DateTime dateTime = (DateTime)obj;
if ((object)targetType == typeof(DateTimeOffset)) {
value = new DateTimeOffset(dateTime);
return ConvertResult.Success;
}
}
byte[] b;
if ((b = (initialValue as byte[])) != null && (object)targetType == typeof(Guid)) {
value = new Guid(b);
return ConvertResult.Success;
}
if ((obj = initialValue) is Guid) {
Guid guid = (Guid)obj;
if ((object)targetType == typeof(byte[])) {
value = guid.ToByteArray();
return ConvertResult.Success;
}
}
string text;
if ((text = (initialValue as string)) != null) {
if ((object)targetType == typeof(Guid)) {
value = new Guid(text);
return ConvertResult.Success;
}
if ((object)targetType == typeof(Uri)) {
value = new Uri(text, UriKind.RelativeOrAbsolute);
return ConvertResult.Success;
}
if ((object)targetType == typeof(TimeSpan)) {
value = ParseTimeSpan(text);
return ConvertResult.Success;
}
if ((object)targetType == typeof(byte[])) {
value = System.Convert.FromBase64String(text);
return ConvertResult.Success;
}
if ((object)targetType == typeof(Version)) {
if (VersionTryParse(text, out Version result)) {
value = result;
return ConvertResult.Success;
}
value = null;
return ConvertResult.NoValidConversion;
}
if (typeof(Type).IsAssignableFrom(targetType)) {
value = Type.GetType(text, true);
return ConvertResult.Success;
}
}
TypeConverter converter = TypeDescriptor.GetConverter(type);
if (converter != null && converter.CanConvertTo(targetType)) {
value = converter.ConvertTo(null, culture, initialValue, targetType);
return ConvertResult.Success;
}
TypeConverter converter2 = TypeDescriptor.GetConverter(targetType);
if (converter2 != null && converter2.CanConvertFrom(type)) {
value = converter2.ConvertFrom(null, culture, initialValue);
return ConvertResult.Success;
}
if (initialValue == DBNull.Value) {
if (ReflectionUtils.IsNullable(targetType)) {
value = EnsureTypeAssignable(null, type, targetType);
return ConvertResult.Success;
}
value = null;
return ConvertResult.CannotConvertNull;
}
if (targetType.IsInterface() || targetType.IsGenericTypeDefinition() || targetType.IsAbstract()) {
value = null;
return ConvertResult.NotInstantiableType;
}
value = null;
return ConvertResult.NoValidConversion;
}
public static object ConvertOrCast(object initialValue, CultureInfo culture, Type targetType)
{
if ((object)targetType == typeof(object))
return initialValue;
if (initialValue == null && ReflectionUtils.IsNullable(targetType))
return null;
if (TryConvert(initialValue, culture, targetType, out object value))
return value;
return EnsureTypeAssignable(initialValue, ReflectionUtils.GetObjectType(initialValue), targetType);
}
private static object EnsureTypeAssignable(object value, Type initialType, Type targetType)
{
Type type = value?.GetType();
if (value != null) {
if (targetType.IsAssignableFrom(type))
return value;
Func<object, object> func = CastConverters.Get(new StructMultiKey<Type, Type>(type, targetType));
if (func != null)
return func(value);
} else if (ReflectionUtils.IsNullable(targetType)) {
return null;
}
throw new ArgumentException("Could not cast or convert from {0} to {1}.".FormatWith(CultureInfo.InvariantCulture, initialType?.ToString() ?? "{null}", targetType));
}
public static bool VersionTryParse(string input, out Version result)
{
try {
result = new Version(input);
return true;
} catch {
result = null;
return false;
}
}
public static bool IsInteger(object value)
{
switch (GetTypeCode(value.GetType())) {
case PrimitiveTypeCode.SByte:
case PrimitiveTypeCode.Int16:
case PrimitiveTypeCode.UInt16:
case PrimitiveTypeCode.Int32:
case PrimitiveTypeCode.Byte:
case PrimitiveTypeCode.UInt32:
case PrimitiveTypeCode.Int64:
case PrimitiveTypeCode.UInt64:
return true;
default:
return false;
}
}
public static ParseResult Int32TryParse(char[] chars, int start, int length, out int value)
{
value = 0;
if (length == 0)
return ParseResult.Invalid;
bool flag = chars[start] == '-';
if (flag) {
if (length == 1)
return ParseResult.Invalid;
start++;
length--;
}
int num = start + length;
if (length > 10 || (length == 10 && chars[start] - 48 > 2)) {
for (int i = start; i < num; i++) {
int num2 = chars[i] - 48;
if (num2 < 0 || num2 > 9)
return ParseResult.Invalid;
}
return ParseResult.Overflow;
}
for (int j = start; j < num; j++) {
int num3 = chars[j] - 48;
if (num3 < 0 || num3 > 9)
return ParseResult.Invalid;
int num4 = 10 * value - num3;
if (num4 > value) {
for (j++; j < num; j++) {
num3 = chars[j] - 48;
if (num3 < 0 || num3 > 9)
return ParseResult.Invalid;
}
return ParseResult.Overflow;
}
value = num4;
}
if (!flag) {
if (value == -2147483648)
return ParseResult.Overflow;
value = -value;
}
return ParseResult.Success;
}
public static ParseResult Int64TryParse(char[] chars, int start, int length, out long value)
{
value = 0;
if (length == 0)
return ParseResult.Invalid;
bool flag = chars[start] == '-';
if (flag) {
if (length == 1)
return ParseResult.Invalid;
start++;
length--;
}
int num = start + length;
if (length > 19) {
for (int i = start; i < num; i++) {
int num2 = chars[i] - 48;
if (num2 < 0 || num2 > 9)
return ParseResult.Invalid;
}
return ParseResult.Overflow;
}
for (int j = start; j < num; j++) {
int num3 = chars[j] - 48;
if (num3 < 0 || num3 > 9)
return ParseResult.Invalid;
long num4 = 10 * value - num3;
if (num4 > value) {
for (j++; j < num; j++) {
num3 = chars[j] - 48;
if (num3 < 0 || num3 > 9)
return ParseResult.Invalid;
}
return ParseResult.Overflow;
}
value = num4;
}
if (!flag) {
if (value == -9223372036854775808)
return ParseResult.Overflow;
value = -value;
}
return ParseResult.Success;
}
public static ParseResult DecimalTryParse(char[] chars, int start, int length, out decimal value)
{
value = default(decimal);
if (length == 0)
return ParseResult.Invalid;
bool flag = chars[start] == '-';
if (flag) {
if (length == 1)
return ParseResult.Invalid;
start++;
length--;
}
int i = start;
int num = start + length;
int num2 = num;
int num3 = num;
int num4 = 0;
ulong num5 = 0;
ulong num6 = 0;
int num7 = 0;
int num8 = 0;
char? nullable = null;
bool? nullable2 = null;
for (; i < num; i++) {
char c = chars[i];
if (c == '.')
goto IL_0074;
if (c == 'E' || c == 'e')
goto IL_0091;
if (c < '0' || c > '9')
return ParseResult.Invalid;
if (i == start && c == '0') {
i++;
if (i != num) {
switch (chars[i]) {
case '.':
break;
case 'E':
case 'e':
goto IL_0091;
default:
return ParseResult.Invalid;
}
goto IL_0074;
}
}
if (num7 < 29) {
if (num7 == 28) {
bool? nullable3 = nullable2;
int valueOrDefault;
if (!nullable3.HasValue) {
nullable2 = (num5 > 7922816251426433759 || (num5 == 7922816251426433759 && (num6 > 354395033 || (num6 == 354395033 && c > '5'))));
bool? nullable4 = nullable2;
valueOrDefault = (nullable4.GetValueOrDefault() ? 1 : 0);
} else
valueOrDefault = (nullable3.GetValueOrDefault() ? 1 : 0);
if (valueOrDefault != 0)
goto IL_01ff;
}
if (num7 < 19)
num5 = (ulong)((long)(num5 * 10) + (long)(c - 48));
else
num6 = (ulong)((long)(num6 * 10) + (long)(c - 48));
num7++;
continue;
}
goto IL_01ff;
IL_0091:
if (i == start)
return ParseResult.Invalid;
if (i == num2)
return ParseResult.Invalid;
i++;
if (i == num)
return ParseResult.Invalid;
if (num2 < num)
num3 = i - 1;
c = chars[i];
bool flag2 = false;
switch (c) {
case '-':
flag2 = true;
i++;
break;
case '+':
i++;
break;
}
for (; i < num; i++) {
c = chars[i];
if (c < '0' || c > '9')
return ParseResult.Invalid;
int num9 = 10 * num4 + (c - 48);
if (num4 < num9)
num4 = num9;
}
if (flag2)
num4 = -num4;
continue;
IL_01ff:
if (!nullable.HasValue)
nullable = c;
num8++;
continue;
IL_0074:
if (i == start)
return ParseResult.Invalid;
if (i + 1 == num)
return ParseResult.Invalid;
if (num2 != num)
return ParseResult.Invalid;
num2 = i + 1;
}
num4 += num8;
num4 -= num3 - num2;
if (num7 <= 19)
value = num5;
else
value = (decimal)num5 / new decimal(1, 0, 0, false, (byte)(num7 - 19)) + (decimal)num6;
if (num4 > 0) {
num7 += num4;
if (num7 > 29)
return ParseResult.Overflow;
if (num7 != 29)
value /= new decimal(1, 0, 0, false, (byte)num4);
else {
if (num4 > 1) {
value /= new decimal(1, 0, 0, false, (byte)(num4 - 1));
if (value > 7922816251426433759354395033)
return ParseResult.Overflow;
} else if (value == 7922816251426433759354395033) {
int? nullable5 = nullable;
int num10 = 53;
if ((nullable5.GetValueOrDefault() > num10) & nullable5.HasValue)
return ParseResult.Overflow;
}
value *= 10;
}
} else {
int? nullable5 = nullable;
int num10 = 53;
if (((nullable5.GetValueOrDefault() >= num10) & nullable5.HasValue) && num4 >= -28)
++value;
if (num4 < 0) {
if (num7 + num4 + 28 <= 0) {
value = (flag ? decimal.Zero : decimal.Zero);
return ParseResult.Success;
}
if (num4 < -28) {
value /= 10000000000000000000000000000;
value *= new decimal(1, 0, 0, false, (byte)(-num4 - 28));
} else
value *= new decimal(1, 0, 0, false, (byte)(-num4));
}
}
if (flag)
value = -value;
return ParseResult.Success;
}
public static bool TryConvertGuid(string s, out Guid g)
{
if (s == null)
throw new ArgumentNullException("s");
if (new Regex("^[A-Fa-f0-9]{8}-([A-Fa-f0-9]{4}-){3}[A-Fa-f0-9]{12}$").Match(s).Success) {
g = new Guid(s);
return true;
}
g = Guid.Empty;
return false;
}
public static bool TryHexTextToInt(char[] text, int start, int end, out int value)
{
value = 0;
for (int i = start; i < end; i++) {
char c = text[i];
int num;
if (c <= '9' && c >= '0')
num = c - 48;
else if (c <= 'F' && c >= 'A') {
num = c - 55;
} else {
if (c > 'f' || c < 'a') {
value = 0;
return false;
}
num = c - 87;
}
value += num << (end - 1 - i) * 4;
}
return true;
}
}
}