using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Globalization;
using System.Reflection;
using System.Reflection.Emit;
using System.IO;
namespace fastJSON
{
public class JSON
{
public readonly static JSON Instance = new JSON();
private JSON()
{
}
public bool UseOptimizedDatasetSchema = true;
public bool UseFastGuid = true;
public string ToJSON(object obj)
{
return new JSONSerializer(UseOptimizedDatasetSchema,UseFastGuid).ConvertToJSON(obj);
}
public object ToObject(string json)
{
Dictionary<string, object> ht = new JsonParser(json).Decode() as Dictionary<string, object>;
if (ht == null) return null;
return ParseDictionary(ht);
}
#region [ PROPERTY GET SET CACHE ]
SafeDictionary<Type, string> _tyname = new SafeDictionary<Type, string>();
internal string GetTypeAssemblyName(Type t)
{
if(_tyname.ContainsKey(t))
return _tyname[t];
else
{
string s = t.AssemblyQualifiedName;
_tyname.Add(t,s);
return s;
}
}
SafeDictionary<string, Type> _typecache = new SafeDictionary<string, Type>();
private Type GetTypeFromCache(string typename)
{
if (_typecache.ContainsKey(typename))
return _typecache[typename];
else
{
Type t = Type.GetType(typename);
_typecache.Add(typename, t);
return t;
}
}
SafeDictionary<Type, CreateObject> _constrcache = new SafeDictionary<Type, CreateObject>();
private delegate object CreateObject();
private object FastCreateInstance(Type objtype)
{
CreateObject c = null;
if(_constrcache.ContainsKey(objtype))
{
c = _constrcache[objtype];
return c();
}
else
{
DynamicMethod dynMethod = new DynamicMethod("_", objtype, null);
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();
}
}
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;
public bool isDataSet;
public bool isHashtable;
public GenericSetter setter;
public bool isEnum;
public bool isDateTime;
public Type[] GenericTypes;
}
SafeDictionary<string, myPropInfo> _propertycache = new SafeDictionary<string, myPropInfo>();
private myPropInfo getproperty(Type type, string typename, string propertyname)
{
if (propertyname == "$type")
return new myPropInfo();
string n = string.Concat(typename, propertyname);
if (_propertycache.ContainsKey(n))
{
return _propertycache[n];
}
else
{
PropertyInfo[] pr = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (PropertyInfo p in pr)
{
myPropInfo d = new myPropInfo();
d.filled = true;
d.pt = p.PropertyType;
d.isDictionary = p.Name.Contains("Dictionary");
if(d.isDictionary)
d.GenericTypes = p.PropertyType.GetGenericArguments();
d.isValueType = p.PropertyType.IsValueType;
d.isGenericType = p.PropertyType.IsGenericType;
d.isArray = p.PropertyType.IsArray;
if(d.isArray)
d.bt = p.PropertyType.GetElementType();
if(d.isGenericType)
d.bt = p.PropertyType.GetGenericArguments()[0];
d.isByteArray = p.PropertyType == typeof(byte[]);
d.isGuid = (p.PropertyType == typeof(Guid) || p.PropertyType == typeof(Guid?));
d.isHashtable = p.PropertyType == typeof(Hashtable);
d.isDataSet = p.PropertyType == typeof(DataSet);
d.setter = CreateSetMethod(p);
d.changeType = GetChangeType(p.PropertyType);
d.isEnum = p.PropertyType.IsEnum;
d.isDateTime = p.PropertyType == typeof(DateTime) || p.PropertyType == typeof(DateTime?);
string nn = string.Concat(typename, p.Name);
if (_propertycache.ContainsKey(nn) == false)
_propertycache.Add(nn, d);
}
return _propertycache[n];
}
}
private delegate void GenericSetter(object target, object value);
private static GenericSetter CreateSetMethod(PropertyInfo propertyInfo)
{
MethodInfo setMethod = propertyInfo.GetSetMethod();
if (setMethod == null)
return null;
Type[] arguments = new Type[2];
arguments[0] = arguments[1] = typeof(object);
DynamicMethod setter = new DynamicMethod("_", typeof(void), arguments, propertyInfo.DeclaringType);
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;
Type[] arguments = new Type[1];
arguments[0] = typeof(object);
DynamicMethod getter = new DynamicMethod("_", typeof(object), arguments);
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)
{
if (_getterscache.ContainsKey(type)) return _getterscache[type];
PropertyInfo[] props = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
List<Getters> getters = new List<Getters>();
foreach (PropertyInfo p in props)
{
if (!p.CanWrite) continue;
JSON.GenericGetter g = CreateGetMethod(p);
if (g != null)
{
Getters gg = new Getters();
gg.Name = p.Name;
gg.Getter = g;
getters.Add(gg);
}
}
_getterscache.Add(type, getters);
return getters;
}
SafeDictionary<Type, Type> _changetype = new SafeDictionary<Type, Type>();
private object ChangeType(object value, Type conversionType)
{
if (_changetype.ContainsKey(conversionType))
conversionType = _changetype[conversionType];
else
{
Type t = GetChangeType(conversionType);
_changetype.Add(conversionType, t);
conversionType = t;
}
return Convert.ChangeType(value, conversionType, CultureInfo.InvariantCulture);
}
#endregion
private object ParseDictionary(Dictionary<string, object> d)
{
string tn = d["$type"].ToString();
Type type = GetTypeFromCache(tn);
string typename = type.Name;
object o = FastCreateInstance(type);
foreach (string name in d.Keys)
{
myPropInfo pi = getproperty(type, typename, name);
if (pi.filled == true )
{
object v = d[name];
if (v != null)
{
object oset = null;
if (pi.isGenericType && pi.isValueType == false && pi.isDictionary == false)
oset = CreateGenericList(v as ArrayList, pi.pt, pi.bt);
else if (pi.isByteArray)
oset = Convert.FromBase64String((v as string));
else if (pi.isArray && pi.isValueType == false)
oset = CreateArray(v as ArrayList, pi.pt, pi.bt);
else if (pi.isGuid)
{
string s = (string)v;
if(s.Length>30)
oset = new Guid(s);
else
oset = new Guid(Convert.FromBase64String(s));
}
else if (pi.isDataSet)
oset = CreateDataset((v as Dictionary<string, object>));
else if (pi.isDictionary || pi.isHashtable)
oset = CreateDictionary((v as ArrayList), pi.pt, pi.GenericTypes);
else if(pi.isEnum)
oset = Enum.Parse(pi.pt,v as string);
else if(pi.isDateTime)
oset = CreateDateTime(v as string);
else
oset = Convert.ChangeType(v, pi.changeType, CultureInfo.InvariantCulture);
pi.setter(o, oset);
}
}
}
return o;
}
private DateTime CreateDateTime(string value)
{
// 0123456789012345678
// datetime format = yyyy-MM-dd HH:mm:ss
int year = int.Parse(value.Substring(0,4));
int month = int.Parse(value.Substring(5,2));
int day = int.Parse(value.Substring(8,2));
int hour = int.Parse(value.Substring(11,2));
int min = int.Parse(value.Substring(14,2));
int sec = int.Parse(value.Substring(17,2));
return new DateTime(year,month,day,hour,min,sec);
}
private object CreateArray(ArrayList data, Type pt, Type bt)
{
ArrayList col = new ArrayList();
// create an array of objects
foreach (object ob in data)
{
if (ob is IDictionary)
col.Add(ParseDictionary((ob as Dictionary<string, object>)));
else
col.Add(Convert.ChangeType(ob, bt, CultureInfo.InvariantCulture));
}
return col.ToArray(bt);
}
private object CreateGenericList(ArrayList data, Type pt, Type bt)
{
IList col = (IList)FastCreateInstance(pt);
// create an array of objects
foreach (object ob in data)
{
if (ob is IDictionary)
col.Add(ParseDictionary(ob as Dictionary<string, object>));
else
col.Add(Convert.ChangeType(ob,bt,CultureInfo.InvariantCulture));
}
return col;
}
private object CreateDictionary(ArrayList reader, Type pt, Type[] types)
{
IDictionary col = (FastCreateInstance(pt) as IDictionary);
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);
else
key = ChangeType(key, types[0]);
if (val is Dictionary<string, object>)
val = ParseDictionary((Dictionary<string, object>)val);
else
val = ChangeType(val, types[1]);
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;
}
private DataSet CreateDataset(Dictionary<string, object> reader)
{
DataSet ds = new DataSet();
ds.EnforceConstraints = false;
ds.BeginInit();
// read dataset schema here
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);
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]));
}
}
foreach (KeyValuePair<string, object> pair in reader)
{
if (pair.Key == "$type" || pair.Key == "$schema") continue;
ArrayList rows = pair.Value as ArrayList;
if (rows == null) continue;
DataTable dt = ds.Tables[pair.Key];
dt.BeginInit();
dt.BeginLoadData();
List<int> guidcols = new List<int>();
foreach(DataColumn c in dt.Columns)
if(c.DataType == typeof(Guid) || c.DataType == typeof(Guid?))
guidcols.Add(c.Ordinal);
foreach (ArrayList row in rows)
{
object[] v = new object[row.Count];
row.CopyTo(v,0);
foreach(int i in guidcols)
{
string s = (string)v[i];
if(s!=null && s.Length<36)
v[i]=new Guid(Convert.FromBase64String(s));
}
dt.Rows.Add(v);
}
dt.EndLoadData();
dt.EndInit();
}
ds.EndInit();
return ds;
}
}
}