mirror of https://github.com/Sonarr/Sonarr
834 lines
28 KiB
C#
834 lines
28 KiB
C#
![]() |
//http://fastjson.codeplex.com/
|
|||
|
//http://fastjson.codeplex.com/license
|
|||
|
|
|||
|
using System;
|
|||
|
using System.Collections;
|
|||
|
using System.Collections.Generic;
|
|||
|
using System.Data;
|
|||
|
using System.Globalization;
|
|||
|
using System.IO;
|
|||
|
using System.Reflection;
|
|||
|
using System.Reflection.Emit;
|
|||
|
using System.Xml.Serialization;
|
|||
|
|
|||
|
namespace Exceptron.Client.fastJSON
|
|||
|
{
|
|||
|
|
|||
|
internal class JSON
|
|||
|
{
|
|||
|
public readonly static JSON Instance = new JSON();
|
|||
|
|
|||
|
private JSON()
|
|||
|
{
|
|||
|
UseSerializerExtension = false;
|
|||
|
SerializeNullValues = false;
|
|||
|
UseOptimizedDatasetSchema = false;
|
|||
|
UsingGlobalTypes = false;
|
|||
|
}
|
|||
|
public bool UseOptimizedDatasetSchema = true;
|
|||
|
public bool UseFastGuid = true;
|
|||
|
public bool UseSerializerExtension = true;
|
|||
|
public bool IndentOutput = false;
|
|||
|
public bool SerializeNullValues = true;
|
|||
|
public bool UseUTCDateTime = false;
|
|||
|
public bool ShowReadOnlyProperties = false;
|
|||
|
public bool UsingGlobalTypes = true;
|
|||
|
|
|||
|
public string ToJSON(object obj)
|
|||
|
{
|
|||
|
return ToJSON(obj, UseSerializerExtension, UseFastGuid, UseOptimizedDatasetSchema, SerializeNullValues);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
public string ToJSON(object obj,
|
|||
|
bool enableSerializerExtensions,
|
|||
|
bool enableFastGuid,
|
|||
|
bool enableOptimizedDatasetSchema,
|
|||
|
bool serializeNullValues)
|
|||
|
{
|
|||
|
return new JSONSerializer(enableOptimizedDatasetSchema, enableFastGuid, enableSerializerExtensions, serializeNullValues, IndentOutput).ConvertToJSON(obj);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
public T ToObject<T>(string json)
|
|||
|
{
|
|||
|
return (T)ToObject(json, typeof(T));
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
public object ToObject(string json, Type type)
|
|||
|
{
|
|||
|
var ht = new JsonParser(json).Decode() as Dictionary<string, object>;
|
|||
|
if (ht == null) return null;
|
|||
|
return ParseDictionary(ht, null, type);
|
|||
|
}
|
|||
|
|
|||
|
#if CUSTOMTYPE
|
|||
|
internal SafeDictionary<Type, Serialize> _customSerializer = new SafeDictionary<Type, Serialize>();
|
|||
|
internal SafeDictionary<Type, Deserialize> _customDeserializer = new SafeDictionary<Type, Deserialize>();
|
|||
|
|
|||
|
public void RegisterCustomType(Type type, Serialize serializer, Deserialize deserializer)
|
|||
|
{
|
|||
|
if (type != null && serializer != null && deserializer != null)
|
|||
|
{
|
|||
|
_customSerializer.Add(type, serializer);
|
|||
|
_customDeserializer.Add(type, deserializer);
|
|||
|
// reset property cache
|
|||
|
_propertycache = new SafeDictionary<string, SafeDictionary<string, myPropInfo>>();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
internal bool IsTypeRegistered(Type t)
|
|||
|
{
|
|||
|
Serialize s;
|
|||
|
return _customSerializer.TryGetValue(t, out s);
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
#region [ PROPERTY GET SET CACHE ]
|
|||
|
|
|||
|
readonly SafeDictionary<Type, string> _tyname = new SafeDictionary<Type, string>();
|
|||
|
internal string GetTypeAssemblyName(Type t)
|
|||
|
{
|
|||
|
string val = "";
|
|||
|
if (_tyname.TryGetValue(t, out val))
|
|||
|
return val;
|
|||
|
else
|
|||
|
{
|
|||
|
string s = t.AssemblyQualifiedName;
|
|||
|
_tyname.Add(t, s);
|
|||
|
return s;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
readonly SafeDictionary<string, Type> _typecache = new SafeDictionary<string, Type>();
|
|||
|
private Type GetTypeFromCache(string typename)
|
|||
|
{
|
|||
|
Type val = null;
|
|||
|
if (_typecache.TryGetValue(typename, out val))
|
|||
|
return val;
|
|||
|
else
|
|||
|
{
|
|||
|
Type t = Type.GetType(typename);
|
|||
|
_typecache.Add(typename, t);
|
|||
|
return t;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
readonly SafeDictionary<Type, CreateObject> _constrcache = new SafeDictionary<Type, CreateObject>();
|
|||
|
private delegate object CreateObject();
|
|||
|
private object FastCreateInstance(Type objtype)
|
|||
|
{
|
|||
|
try
|
|||
|
{
|
|||
|
CreateObject c = null;
|
|||
|
if (_constrcache.TryGetValue(objtype, out c))
|
|||
|
{
|
|||
|
return c();
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
DynamicMethod dynMethod = new DynamicMethod("_", objtype, null, true);
|
|||
|
ILGenerator ilGen = dynMethod.GetILGenerator();
|
|||
|
|
|||
|
ilGen.Emit(OpCodes.Newobj, objtype.GetConstructor(Type.EmptyTypes));
|
|||
|
ilGen.Emit(OpCodes.Ret);
|
|||
|
c = (CreateObject)dynMethod.CreateDelegate(typeof(CreateObject));
|
|||
|
_constrcache.Add(objtype, c);
|
|||
|
return c();
|
|||
|
}
|
|||
|
}
|
|||
|
catch (Exception exc)
|
|||
|
{
|
|||
|
throw new Exception(string.Format("Failed to fast create instance for type '{0}' from assemebly '{1}'",
|
|||
|
objtype.FullName, objtype.AssemblyQualifiedName), exc);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
private struct myPropInfo
|
|||
|
{
|
|||
|
public bool filled;
|
|||
|
public Type pt;
|
|||
|
public Type bt;
|
|||
|
public Type changeType;
|
|||
|
public bool isDictionary;
|
|||
|
public bool isValueType;
|
|||
|
public bool isGenericType;
|
|||
|
public bool isArray;
|
|||
|
public bool isByteArray;
|
|||
|
public bool isGuid;
|
|||
|
#if !SILVERLIGHT
|
|||
|
public bool isDataSet;
|
|||
|
public bool isDataTable;
|
|||
|
public bool isHashtable;
|
|||
|
#endif
|
|||
|
public GenericSetter setter;
|
|||
|
public bool isEnum;
|
|||
|
public bool isDateTime;
|
|||
|
public Type[] GenericTypes;
|
|||
|
public bool isInt;
|
|||
|
public bool isLong;
|
|||
|
public bool isString;
|
|||
|
public bool isBool;
|
|||
|
public bool isClass;
|
|||
|
public GenericGetter getter;
|
|||
|
public bool isStringDictionary;
|
|||
|
public string Name;
|
|||
|
#if CUSTOMTYPE
|
|||
|
public bool isCustomType;
|
|||
|
#endif
|
|||
|
public bool CanWrite;
|
|||
|
}
|
|||
|
|
|||
|
readonly SafeDictionary<string, SafeDictionary<string, myPropInfo>> _propertycache = new SafeDictionary<string, SafeDictionary<string, myPropInfo>>();
|
|||
|
private SafeDictionary<string, myPropInfo> Getproperties(Type type, string typename)
|
|||
|
{
|
|||
|
SafeDictionary<string, myPropInfo> sd = null;
|
|||
|
if (_propertycache.TryGetValue(typename, out sd))
|
|||
|
{
|
|||
|
return sd;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
sd = new SafeDictionary<string, myPropInfo>();
|
|||
|
var pr = type.GetProperties(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
|
|||
|
foreach (var p in pr)
|
|||
|
{
|
|||
|
myPropInfo d = CreateMyProp(p.PropertyType, p.Name);
|
|||
|
d.CanWrite = p.CanWrite;
|
|||
|
d.setter = CreateSetMethod(p);
|
|||
|
d.getter = CreateGetMethod(p);
|
|||
|
sd.Add(p.Name, d);
|
|||
|
}
|
|||
|
|
|||
|
_propertycache.Add(typename, sd);
|
|||
|
return sd;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
private myPropInfo CreateMyProp(Type t, string name)
|
|||
|
{
|
|||
|
myPropInfo d = new myPropInfo();
|
|||
|
d.filled = true;
|
|||
|
d.CanWrite = true;
|
|||
|
d.pt = t;
|
|||
|
d.Name = name;
|
|||
|
d.isDictionary = t.Name.Contains("Dictionary");
|
|||
|
if (d.isDictionary)
|
|||
|
d.GenericTypes = t.GetGenericArguments();
|
|||
|
d.isValueType = t.IsValueType;
|
|||
|
d.isGenericType = t.IsGenericType;
|
|||
|
d.isArray = t.IsArray;
|
|||
|
if (d.isArray)
|
|||
|
d.bt = t.GetElementType();
|
|||
|
if (d.isGenericType)
|
|||
|
d.bt = t.GetGenericArguments()[0];
|
|||
|
d.isByteArray = t == typeof(byte[]);
|
|||
|
d.isGuid = (t == typeof(Guid) || t == typeof(Guid?));
|
|||
|
#if !SILVERLIGHT
|
|||
|
d.isHashtable = t == typeof(Hashtable);
|
|||
|
d.isDataSet = t == typeof(DataSet);
|
|||
|
d.isDataTable = t == typeof(DataTable);
|
|||
|
#endif
|
|||
|
|
|||
|
d.changeType = GetChangeType(t);
|
|||
|
d.isEnum = t.IsEnum;
|
|||
|
d.isDateTime = t == typeof(DateTime) || t == typeof(DateTime?);
|
|||
|
d.isInt = t == typeof(int) || t == typeof(int?);
|
|||
|
d.isLong = t == typeof(long) || t == typeof(long?);
|
|||
|
d.isString = t == typeof(string);
|
|||
|
d.isBool = t == typeof(bool) || t == typeof(bool?);
|
|||
|
d.isClass = t.IsClass;
|
|||
|
|
|||
|
if (d.isDictionary && d.GenericTypes.Length > 0 && d.GenericTypes[0] == typeof(string))
|
|||
|
d.isStringDictionary = true;
|
|||
|
|
|||
|
#if CUSTOMTYPE
|
|||
|
if (IsTypeRegistered(t))
|
|||
|
d.isCustomType = true;
|
|||
|
#endif
|
|||
|
return d;
|
|||
|
}
|
|||
|
|
|||
|
private delegate void GenericSetter(object target, object value);
|
|||
|
|
|||
|
private static GenericSetter CreateSetMethod(PropertyInfo propertyInfo)
|
|||
|
{
|
|||
|
MethodInfo setMethod = propertyInfo.GetSetMethod(nonPublic: true);
|
|||
|
if (setMethod == null)
|
|||
|
return null;
|
|||
|
|
|||
|
var arguments = new Type[2];
|
|||
|
arguments[0] = arguments[1] = typeof(object);
|
|||
|
|
|||
|
DynamicMethod setter = new DynamicMethod("_", typeof(void), arguments, true);
|
|||
|
ILGenerator il = setter.GetILGenerator();
|
|||
|
il.Emit(OpCodes.Ldarg_0);
|
|||
|
il.Emit(OpCodes.Castclass, propertyInfo.DeclaringType);
|
|||
|
il.Emit(OpCodes.Ldarg_1);
|
|||
|
|
|||
|
if (propertyInfo.PropertyType.IsClass)
|
|||
|
il.Emit(OpCodes.Castclass, propertyInfo.PropertyType);
|
|||
|
else
|
|||
|
il.Emit(OpCodes.Unbox_Any, propertyInfo.PropertyType);
|
|||
|
|
|||
|
il.EmitCall(OpCodes.Callvirt, setMethod, null);
|
|||
|
il.Emit(OpCodes.Ret);
|
|||
|
|
|||
|
return (GenericSetter)setter.CreateDelegate(typeof(GenericSetter));
|
|||
|
}
|
|||
|
|
|||
|
internal delegate object GenericGetter(object obj);
|
|||
|
|
|||
|
|
|||
|
private GenericGetter CreateGetMethod(PropertyInfo propertyInfo)
|
|||
|
{
|
|||
|
MethodInfo getMethod = propertyInfo.GetGetMethod();
|
|||
|
if (getMethod == null)
|
|||
|
return null;
|
|||
|
|
|||
|
var arguments = new Type[1];
|
|||
|
arguments[0] = typeof(object);
|
|||
|
|
|||
|
DynamicMethod getter = new DynamicMethod("_", typeof(object), arguments, true);
|
|||
|
ILGenerator il = getter.GetILGenerator();
|
|||
|
il.Emit(OpCodes.Ldarg_0);
|
|||
|
il.Emit(OpCodes.Castclass, propertyInfo.DeclaringType);
|
|||
|
il.EmitCall(OpCodes.Callvirt, getMethod, null);
|
|||
|
|
|||
|
if (!propertyInfo.PropertyType.IsClass)
|
|||
|
il.Emit(OpCodes.Box, propertyInfo.PropertyType);
|
|||
|
|
|||
|
il.Emit(OpCodes.Ret);
|
|||
|
|
|||
|
return (GenericGetter)getter.CreateDelegate(typeof(GenericGetter));
|
|||
|
}
|
|||
|
|
|||
|
readonly SafeDictionary<Type, List<Getters>> _getterscache = new SafeDictionary<Type, List<Getters>>();
|
|||
|
internal List<Getters> GetGetters(Type type)
|
|||
|
{
|
|||
|
List<Getters> val = null;
|
|||
|
if (_getterscache.TryGetValue(type, out val))
|
|||
|
return val;
|
|||
|
|
|||
|
var props = type.GetProperties(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
|
|||
|
var getters = new List<Getters>();
|
|||
|
foreach (var p in props)
|
|||
|
{
|
|||
|
if (!p.CanWrite && ShowReadOnlyProperties == false) continue;
|
|||
|
|
|||
|
var att = p.GetCustomAttributes(typeof(XmlIgnoreAttribute), false);
|
|||
|
if (att != null && att.Length > 0)
|
|||
|
continue;
|
|||
|
|
|||
|
GenericGetter g = CreateGetMethod(p);
|
|||
|
if (g != null)
|
|||
|
{
|
|||
|
Getters gg = new Getters();
|
|||
|
gg.Name = p.Name;
|
|||
|
gg.Getter = g;
|
|||
|
gg.propertyType = p.PropertyType;
|
|||
|
getters.Add(gg);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
_getterscache.Add(type, getters);
|
|||
|
return getters;
|
|||
|
}
|
|||
|
|
|||
|
private object ChangeType(object value, Type conversionType)
|
|||
|
{
|
|||
|
if (conversionType == typeof(int))
|
|||
|
return (int)CreateLong((string)value);
|
|||
|
|
|||
|
else if (conversionType == typeof(long))
|
|||
|
return CreateLong((string)value);
|
|||
|
|
|||
|
else if (conversionType == typeof(string))
|
|||
|
return value;
|
|||
|
|
|||
|
else if (conversionType == typeof(Guid))
|
|||
|
return CreateGuid((string)value);
|
|||
|
|
|||
|
else if (conversionType.IsEnum)
|
|||
|
return CreateEnum(conversionType, (string)value);
|
|||
|
|
|||
|
return Convert.ChangeType(value, conversionType, CultureInfo.InvariantCulture);
|
|||
|
}
|
|||
|
#endregion
|
|||
|
|
|||
|
|
|||
|
private object ParseDictionary(Dictionary<string, object> d, Dictionary<string, object> globaltypes, Type type)
|
|||
|
{
|
|||
|
object tn = "";
|
|||
|
if (d.TryGetValue("$types", out tn))
|
|||
|
{
|
|||
|
UsingGlobalTypes = true;
|
|||
|
globaltypes = new Dictionary<string, object>();
|
|||
|
foreach (var kv in (Dictionary<string, object>)tn)
|
|||
|
{
|
|||
|
globaltypes.Add((string)kv.Value, kv.Key);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
bool found = d.TryGetValue("$type", out tn);
|
|||
|
#if !SILVERLIGHT
|
|||
|
if (found == false && type == typeof(Object))
|
|||
|
{
|
|||
|
return CreateDataset(d, globaltypes);
|
|||
|
}
|
|||
|
#endif
|
|||
|
if (found)
|
|||
|
{
|
|||
|
if (UsingGlobalTypes)
|
|||
|
{
|
|||
|
object tname = "";
|
|||
|
if (globaltypes.TryGetValue((string)tn, out tname))
|
|||
|
tn = tname;
|
|||
|
}
|
|||
|
type = GetTypeFromCache((string)tn);
|
|||
|
}
|
|||
|
|
|||
|
if (type == null)
|
|||
|
throw new Exception("Cannot determine type");
|
|||
|
|
|||
|
string typename = type.FullName;
|
|||
|
object o = FastCreateInstance(type);
|
|||
|
var props = Getproperties(type, typename);
|
|||
|
foreach (var name in d.Keys)
|
|||
|
{
|
|||
|
if (name == "$map")
|
|||
|
{
|
|||
|
ProcessMap(o, props, (Dictionary<string, object>)d[name]);
|
|||
|
continue;
|
|||
|
}
|
|||
|
myPropInfo pi;
|
|||
|
if (props.TryGetValue(name, out pi) == false)
|
|||
|
continue;
|
|||
|
if (pi.filled)
|
|||
|
{
|
|||
|
object v = d[name];
|
|||
|
|
|||
|
if (v != null)
|
|||
|
{
|
|||
|
object oset = null;
|
|||
|
|
|||
|
if (pi.isInt)
|
|||
|
oset = (int)CreateLong((string)v);
|
|||
|
#if CUSTOMTYPE
|
|||
|
else if (pi.isCustomType)
|
|||
|
oset = CreateCustom((string)v, pi.pt);
|
|||
|
#endif
|
|||
|
else if (pi.isLong)
|
|||
|
oset = CreateLong((string)v);
|
|||
|
|
|||
|
else if (pi.isString)
|
|||
|
oset = v;
|
|||
|
|
|||
|
else if (pi.isBool)
|
|||
|
oset = (bool)v;
|
|||
|
|
|||
|
else if (pi.isGenericType && pi.isValueType == false && pi.isDictionary == false)
|
|||
|
#if SILVERLIGHT
|
|||
|
oset = CreateGenericList((List<object>)v, pi.pt, pi.bt, globaltypes);
|
|||
|
#else
|
|||
|
oset = CreateGenericList((ArrayList)v, pi.pt, pi.bt, globaltypes);
|
|||
|
#endif
|
|||
|
else if (pi.isByteArray)
|
|||
|
oset = Convert.FromBase64String((string)v);
|
|||
|
|
|||
|
else if (pi.isArray && pi.isValueType == false)
|
|||
|
#if SILVERLIGHT
|
|||
|
oset = CreateArray((List<object>)v, pi.pt, pi.bt, globaltypes);
|
|||
|
#else
|
|||
|
oset = CreateArray((ArrayList)v, pi.pt, pi.bt, globaltypes);
|
|||
|
#endif
|
|||
|
else if (pi.isGuid)
|
|||
|
oset = CreateGuid((string)v);
|
|||
|
#if !SILVERLIGHT
|
|||
|
else if (pi.isDataSet)
|
|||
|
oset = CreateDataset((Dictionary<string, object>)v, globaltypes);
|
|||
|
|
|||
|
else if (pi.isDataTable)
|
|||
|
oset = CreateDataTable((Dictionary<string, object>)v, globaltypes);
|
|||
|
#endif
|
|||
|
|
|||
|
else if (pi.isStringDictionary)
|
|||
|
oset = CreateStringKeyDictionary((Dictionary<string, object>)v, pi.pt, pi.GenericTypes, globaltypes);
|
|||
|
|
|||
|
#if !SILVERLIGHT
|
|||
|
else if (pi.isDictionary || pi.isHashtable)
|
|||
|
oset = CreateDictionary((ArrayList)v, pi.pt, pi.GenericTypes, globaltypes);
|
|||
|
#else
|
|||
|
else if (pi.isDictionary)
|
|||
|
oset = CreateDictionary((List<object>)v, pi.pt, pi.GenericTypes, globaltypes);
|
|||
|
#endif
|
|||
|
|
|||
|
else if (pi.isEnum)
|
|||
|
oset = CreateEnum(pi.pt, (string)v);
|
|||
|
|
|||
|
else if (pi.isDateTime)
|
|||
|
oset = CreateDateTime((string)v);
|
|||
|
|
|||
|
else if (pi.isClass && v is Dictionary<string, object>)
|
|||
|
oset = ParseDictionary((Dictionary<string, object>)v, globaltypes, pi.pt);
|
|||
|
|
|||
|
else if (pi.isValueType)
|
|||
|
oset = ChangeType(v, pi.changeType);
|
|||
|
|
|||
|
#if SILVERLIGHT
|
|||
|
else if (v is List<object>)
|
|||
|
oset = CreateArray((List<object>)v, pi.pt, typeof(object), globaltypes);
|
|||
|
#else
|
|||
|
else if (v is ArrayList)
|
|||
|
oset = CreateArray((ArrayList)v, pi.pt, typeof(object), globaltypes);
|
|||
|
#endif
|
|||
|
else
|
|||
|
oset = v;
|
|||
|
|
|||
|
if (pi.CanWrite)
|
|||
|
pi.setter(o, oset);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
return o;
|
|||
|
}
|
|||
|
|
|||
|
#if CUSTOMTYPE
|
|||
|
private object CreateCustom(string v, Type type)
|
|||
|
{
|
|||
|
Deserialize d;
|
|||
|
_customDeserializer.TryGetValue(type, out d);
|
|||
|
return d(v);
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
private void ProcessMap(object obj, SafeDictionary<string, myPropInfo> props, Dictionary<string, object> dic)
|
|||
|
{
|
|||
|
foreach (var kv in dic)
|
|||
|
{
|
|||
|
myPropInfo p = props[kv.Key];
|
|||
|
object o = p.getter(obj);
|
|||
|
Type t = Type.GetType((string)kv.Value);
|
|||
|
if (t == typeof(Guid))
|
|||
|
p.setter(obj, CreateGuid((string)o));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
private long CreateLong(string s)
|
|||
|
{
|
|||
|
long num = 0;
|
|||
|
bool neg = false;
|
|||
|
foreach (var cc in s)
|
|||
|
{
|
|||
|
if (cc == '-')
|
|||
|
neg = true;
|
|||
|
else if (cc == '+')
|
|||
|
neg = false;
|
|||
|
else
|
|||
|
{
|
|||
|
num *= 10;
|
|||
|
num += (cc - '0');
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return neg ? -num : num;
|
|||
|
}
|
|||
|
|
|||
|
private object CreateEnum(Type pt, string v)
|
|||
|
{
|
|||
|
// TODO : optimize create enum
|
|||
|
#if !SILVERLIGHT
|
|||
|
return Enum.Parse(pt, v);
|
|||
|
#else
|
|||
|
return Enum.Parse(pt, v, true);
|
|||
|
#endif
|
|||
|
}
|
|||
|
|
|||
|
private Guid CreateGuid(string s)
|
|||
|
{
|
|||
|
if (s.Length > 30)
|
|||
|
return new Guid(s);
|
|||
|
else
|
|||
|
return new Guid(Convert.FromBase64String(s));
|
|||
|
}
|
|||
|
|
|||
|
private DateTime CreateDateTime(string value)
|
|||
|
{
|
|||
|
bool utc = false;
|
|||
|
// 0123456789012345678
|
|||
|
// datetime format = yyyy-MM-dd HH:mm:ss
|
|||
|
int year = (int)CreateLong(value.Substring(0, 4));
|
|||
|
int month = (int)CreateLong(value.Substring(5, 2));
|
|||
|
int day = (int)CreateLong(value.Substring(8, 2));
|
|||
|
int hour = (int)CreateLong(value.Substring(11, 2));
|
|||
|
int min = (int)CreateLong(value.Substring(14, 2));
|
|||
|
int sec = (int)CreateLong(value.Substring(17, 2));
|
|||
|
|
|||
|
if (value.EndsWith("Z"))
|
|||
|
utc = true;
|
|||
|
|
|||
|
if (UseUTCDateTime == false && utc == false)
|
|||
|
return new DateTime(year, month, day, hour, min, sec);
|
|||
|
else
|
|||
|
return new DateTime(year, month, day, hour, min, sec, DateTimeKind.Utc).ToLocalTime();
|
|||
|
}
|
|||
|
|
|||
|
#if SILVERLIGHT
|
|||
|
private object CreateArray(List<object> data, Type pt, Type bt, Dictionary<string, object> globalTypes)
|
|||
|
{
|
|||
|
Array col = Array.CreateInstance(bt, data.Count);
|
|||
|
// create an array of objects
|
|||
|
for (int i = 0; i < data.Count; i++)// each (object ob in data)
|
|||
|
{
|
|||
|
object ob = data[i];
|
|||
|
if (ob is IDictionary)
|
|||
|
col.SetValue(ParseDictionary((Dictionary<string, object>)ob, globalTypes, bt), i);
|
|||
|
else
|
|||
|
col.SetValue(ChangeType(ob, bt), i);
|
|||
|
}
|
|||
|
|
|||
|
return col;
|
|||
|
}
|
|||
|
#else
|
|||
|
private object CreateArray(ArrayList data, Type pt, Type bt, Dictionary<string, object> globalTypes)
|
|||
|
{
|
|||
|
ArrayList col = new ArrayList();
|
|||
|
// create an array of objects
|
|||
|
foreach (var ob in data)
|
|||
|
{
|
|||
|
if (ob is IDictionary)
|
|||
|
col.Add(ParseDictionary((Dictionary<string, object>)ob, globalTypes, bt));
|
|||
|
else
|
|||
|
col.Add(ChangeType(ob, bt));
|
|||
|
}
|
|||
|
return col.ToArray(bt);
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
|
|||
|
#if SILVERLIGHT
|
|||
|
private object CreateGenericList(List<object> data, Type pt, Type bt, Dictionary<string, object> globalTypes)
|
|||
|
#else
|
|||
|
private object CreateGenericList(ArrayList data, Type pt, Type bt, Dictionary<string, object> globalTypes)
|
|||
|
#endif
|
|||
|
{
|
|||
|
IList col = (IList)FastCreateInstance(pt);
|
|||
|
// create an array of objects
|
|||
|
foreach (var ob in data)
|
|||
|
{
|
|||
|
if (ob is IDictionary)
|
|||
|
col.Add(ParseDictionary((Dictionary<string, object>)ob, globalTypes, bt));
|
|||
|
#if SILVERLIGHT
|
|||
|
else if (ob is List<object>)
|
|||
|
col.Add(((List<object>)ob).ToArray());
|
|||
|
#else
|
|||
|
else if (ob is ArrayList)
|
|||
|
col.Add(((ArrayList)ob).ToArray());
|
|||
|
#endif
|
|||
|
else
|
|||
|
col.Add(ChangeType(ob, bt));
|
|||
|
}
|
|||
|
return col;
|
|||
|
}
|
|||
|
|
|||
|
private object CreateStringKeyDictionary(Dictionary<string, object> reader, Type pt, Type[] types, Dictionary<string, object> globalTypes)
|
|||
|
{
|
|||
|
var col = (IDictionary)FastCreateInstance(pt);
|
|||
|
Type t1 = null;
|
|||
|
Type t2 = null;
|
|||
|
if (types != null)
|
|||
|
{
|
|||
|
t1 = types[0];
|
|||
|
t2 = types[1];
|
|||
|
}
|
|||
|
|
|||
|
foreach (var values in reader)
|
|||
|
{
|
|||
|
var key = values.Key;//ChangeType(values.Key, t1);
|
|||
|
object val = null;
|
|||
|
if (values.Value is Dictionary<string, object>)
|
|||
|
val = ParseDictionary((Dictionary<string, object>)values.Value, globalTypes, t2);
|
|||
|
else
|
|||
|
val = ChangeType(values.Value, t2);
|
|||
|
col.Add(key, val);
|
|||
|
}
|
|||
|
|
|||
|
return col;
|
|||
|
}
|
|||
|
|
|||
|
#if SILVERLIGHT
|
|||
|
private object CreateDictionary(List<object> reader, Type pt, Type[] types, Dictionary<string, object> globalTypes)
|
|||
|
#else
|
|||
|
private object CreateDictionary(ArrayList reader, Type pt, Type[] types, Dictionary<string, object> globalTypes)
|
|||
|
#endif
|
|||
|
{
|
|||
|
IDictionary col = (IDictionary)FastCreateInstance(pt);
|
|||
|
Type t1 = null;
|
|||
|
Type t2 = null;
|
|||
|
if (types != null)
|
|||
|
{
|
|||
|
t1 = types[0];
|
|||
|
t2 = types[1];
|
|||
|
}
|
|||
|
|
|||
|
foreach (Dictionary<string, object> values in reader)
|
|||
|
{
|
|||
|
object key = values["k"];
|
|||
|
object val = values["v"];
|
|||
|
|
|||
|
if (key is Dictionary<string, object>)
|
|||
|
key = ParseDictionary((Dictionary<string, object>)key, globalTypes, t1);
|
|||
|
else
|
|||
|
key = ChangeType(key, t1);
|
|||
|
|
|||
|
if (val is Dictionary<string, object>)
|
|||
|
val = ParseDictionary((Dictionary<string, object>)val, globalTypes, t2);
|
|||
|
else
|
|||
|
val = ChangeType(val, t2);
|
|||
|
|
|||
|
col.Add(key, val);
|
|||
|
}
|
|||
|
|
|||
|
return col;
|
|||
|
}
|
|||
|
|
|||
|
private Type GetChangeType(Type conversionType)
|
|||
|
{
|
|||
|
if (conversionType.IsGenericType && conversionType.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))
|
|||
|
return conversionType.GetGenericArguments()[0];
|
|||
|
|
|||
|
return conversionType;
|
|||
|
}
|
|||
|
#if !SILVERLIGHT
|
|||
|
private DataSet CreateDataset(Dictionary<string, object> reader, Dictionary<string, object> globalTypes)
|
|||
|
{
|
|||
|
DataSet ds = new DataSet();
|
|||
|
ds.EnforceConstraints = false;
|
|||
|
ds.BeginInit();
|
|||
|
|
|||
|
// read dataset schema here
|
|||
|
ReadSchema(reader, ds, globalTypes);
|
|||
|
|
|||
|
foreach (var pair in reader)
|
|||
|
{
|
|||
|
if (pair.Key == "$type" || pair.Key == "$schema") continue;
|
|||
|
|
|||
|
ArrayList rows = (ArrayList)pair.Value;
|
|||
|
if (rows == null) continue;
|
|||
|
|
|||
|
DataTable dt = ds.Tables[pair.Key];
|
|||
|
ReadDataTable(rows, dt);
|
|||
|
}
|
|||
|
|
|||
|
ds.EndInit();
|
|||
|
|
|||
|
return ds;
|
|||
|
}
|
|||
|
|
|||
|
private void ReadSchema(Dictionary<string, object> reader, DataSet ds, Dictionary<string, object> globalTypes)
|
|||
|
{
|
|||
|
var schema = reader["$schema"];
|
|||
|
|
|||
|
if (schema is string)
|
|||
|
{
|
|||
|
TextReader tr = new StringReader((string)schema);
|
|||
|
ds.ReadXmlSchema(tr);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
DatasetSchema ms = (DatasetSchema)ParseDictionary((Dictionary<string, object>)schema, globalTypes, typeof(DatasetSchema));
|
|||
|
ds.DataSetName = ms.Name;
|
|||
|
for (int i = 0; i < ms.Info.Count; i += 3)
|
|||
|
{
|
|||
|
if (ds.Tables.Contains(ms.Info[i]) == false)
|
|||
|
ds.Tables.Add(ms.Info[i]);
|
|||
|
ds.Tables[ms.Info[i]].Columns.Add(ms.Info[i + 1], Type.GetType(ms.Info[i + 2]));
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
private void ReadDataTable(ArrayList rows, DataTable dt)
|
|||
|
{
|
|||
|
dt.BeginInit();
|
|||
|
dt.BeginLoadData();
|
|||
|
var guidcols = new List<int>();
|
|||
|
var datecol = new List<int>();
|
|||
|
|
|||
|
foreach (DataColumn c in dt.Columns)
|
|||
|
{
|
|||
|
if (c.DataType == typeof(Guid) || c.DataType == typeof(Guid?))
|
|||
|
guidcols.Add(c.Ordinal);
|
|||
|
if (UseUTCDateTime && (c.DataType == typeof(DateTime) || c.DataType == typeof(DateTime?)))
|
|||
|
datecol.Add(c.Ordinal);
|
|||
|
}
|
|||
|
|
|||
|
foreach (ArrayList row in rows)
|
|||
|
{
|
|||
|
var v = new object[row.Count];
|
|||
|
row.CopyTo(v, 0);
|
|||
|
foreach (var i in guidcols)
|
|||
|
{
|
|||
|
string s = (string)v[i];
|
|||
|
if (s != null && s.Length < 36)
|
|||
|
v[i] = new Guid(Convert.FromBase64String(s));
|
|||
|
}
|
|||
|
if (UseUTCDateTime)
|
|||
|
{
|
|||
|
foreach (var i in datecol)
|
|||
|
{
|
|||
|
string s = (string)v[i];
|
|||
|
if (s != null)
|
|||
|
v[i] = CreateDateTime(s);
|
|||
|
}
|
|||
|
}
|
|||
|
dt.Rows.Add(v);
|
|||
|
}
|
|||
|
|
|||
|
dt.EndLoadData();
|
|||
|
dt.EndInit();
|
|||
|
}
|
|||
|
|
|||
|
DataTable CreateDataTable(Dictionary<string, object> reader, Dictionary<string, object> globalTypes)
|
|||
|
{
|
|||
|
var dt = new DataTable();
|
|||
|
|
|||
|
// read dataset schema here
|
|||
|
var schema = reader["$schema"];
|
|||
|
|
|||
|
if (schema is string)
|
|||
|
{
|
|||
|
TextReader tr = new StringReader((string)schema);
|
|||
|
dt.ReadXmlSchema(tr);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
var ms = (DatasetSchema)ParseDictionary((Dictionary<string, object>)schema, globalTypes, typeof(DatasetSchema));
|
|||
|
dt.TableName = ms.Info[0];
|
|||
|
for (int i = 0; i < ms.Info.Count; i += 3)
|
|||
|
{
|
|||
|
dt.Columns.Add(ms.Info[i + 1], Type.GetType(ms.Info[i + 2]));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
foreach (var pair in reader)
|
|||
|
{
|
|||
|
if (pair.Key == "$type" || pair.Key == "$schema")
|
|||
|
continue;
|
|||
|
|
|||
|
var rows = (ArrayList)pair.Value;
|
|||
|
if (rows == null)
|
|||
|
continue;
|
|||
|
|
|||
|
if (!dt.TableName.Equals(pair.Key, StringComparison.InvariantCultureIgnoreCase))
|
|||
|
continue;
|
|||
|
|
|||
|
ReadDataTable(rows, dt);
|
|||
|
}
|
|||
|
|
|||
|
return dt;
|
|||
|
}
|
|||
|
#endif
|
|||
|
}
|
|||
|
}
|