123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605 |
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using System.Data;
- using System.Globalization;
- using System.IO;
- using System.Reflection;
- public class JSON
- {
- 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 isDataTable;
- public bool isHashtable;
- public Reflection.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 Reflection.GenericGetter getter;
- public bool isStringDictionary;
- public string Name;
- public bool CanWrite;
- }
- public static readonly JSON Instance = new JSON();
- public JSONParameters Parameters = new JSONParameters();
- private JSONParameters _params;
- private SafeDictionary<string, SafeDictionary<string, myPropInfo>> _propertycache = new SafeDictionary<string, SafeDictionary<string, myPropInfo>>();
- private bool usingglobals = false;
- private JSON()
- {
- }
- public string ToJSON(object obj)
- {
- _params = Parameters;
- Reflection.Instance.ShowReadOnlyProperties = _params.ShowReadOnlyProperties;
- return ToJSON(obj, Parameters);
- }
- public string ToJSON(object obj, JSONParameters param)
- {
- _params = param;
- Reflection.Instance.ShowReadOnlyProperties = _params.ShowReadOnlyProperties;
- if (_params.EnableAnonymousTypes)
- {
- _params.UseExtensions = false;
- _params.UsingGlobalTypes = false;
- }
- return new JSONSerializer(param).ConvertToJSON(obj);
- }
- public object Parse(string json)
- {
- _params = Parameters;
- Reflection.Instance.ShowReadOnlyProperties = _params.ShowReadOnlyProperties;
- return new JsonParser(json, Parameters.IgnoreCaseOnDeserialize).Decode();
- }
- public T ToObject<T>(string json)
- {
- return (T)ToObject(json, typeof(T));
- }
- public object ToObject(string json)
- {
- return ToObject(json, null);
- }
- public object ToObject(string json, Type type)
- {
- _params = Parameters;
- Reflection.Instance.ShowReadOnlyProperties = _params.ShowReadOnlyProperties;
- Dictionary<string, object> ht = new JsonParser(json, Parameters.IgnoreCaseOnDeserialize).Decode() as Dictionary<string, object>;
- if (ht == null)
- {
- return null;
- }
- return ParseDictionary(ht, null, type, null);
- }
- public string Beautify(string input)
- {
- return Formatter.PrettyPrint(input);
- }
- public object FillObject(object input, string json)
- {
- _params = Parameters;
- Reflection.Instance.ShowReadOnlyProperties = _params.ShowReadOnlyProperties;
- Dictionary<string, object> ht = new JsonParser(json, Parameters.IgnoreCaseOnDeserialize).Decode() as Dictionary<string, object>;
- if (ht == null)
- {
- return null;
- }
- return ParseDictionary(ht, null, input.GetType(), input);
- }
- public object DeepCopy(object obj)
- {
- return ToObject(ToJSON(obj));
- }
- public T DeepCopy<T>(T obj)
- {
- return ToObject<T>(ToJSON(obj));
- }
- private SafeDictionary<string, myPropInfo> Getproperties(Type type, string typename)
- {
- SafeDictionary<string, myPropInfo> sd = null;
- if (_propertycache.TryGetValue(typename, out sd))
- {
- return sd;
- }
- sd = new SafeDictionary<string, myPropInfo>();
- PropertyInfo[] pr = type.GetProperties(BindingFlags.Instance | BindingFlags.Public);
- PropertyInfo[] array = pr;
- foreach (PropertyInfo p in array)
- {
- myPropInfo d = CreateMyProp(p.PropertyType, p.Name);
- d.CanWrite = p.CanWrite;
- d.setter = Reflection.CreateSetMethod(type, p);
- d.getter = Reflection.CreateGetMethod(type, p);
- sd.Add(p.Name, d);
- }
- FieldInfo[] fi = type.GetFields(BindingFlags.Instance | BindingFlags.Public);
- FieldInfo[] array2 = fi;
- foreach (FieldInfo f in array2)
- {
- myPropInfo d2 = CreateMyProp(f.FieldType, f.Name);
- d2.setter = Reflection.CreateSetField(type, f);
- d2.getter = Reflection.CreateGetField(type, f);
- sd.Add(f.Name, d2);
- }
- _propertycache.Add(typename, sd);
- return sd;
- }
- private myPropInfo CreateMyProp(Type t, string name)
- {
- myPropInfo d = default(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?);
- d.isHashtable = t == typeof(Hashtable);
- d.isDataSet = t == typeof(DataSet);
- d.isDataTable = t == typeof(DataTable);
- 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;
- }
- return d;
- }
- private object ChangeType(object value, Type conversionType)
- {
- if (conversionType == typeof(int))
- {
- return (int)CreateLong((string)value);
- }
- if (conversionType == typeof(long))
- {
- return CreateLong((string)value);
- }
- if (conversionType == typeof(string))
- {
- return (string)value;
- }
- if (conversionType == typeof(Guid))
- {
- return CreateGuid((string)value);
- }
- if (conversionType.IsEnum)
- {
- return CreateEnum(conversionType, (string)value);
- }
- return Convert.ChangeType(value, conversionType, CultureInfo.InvariantCulture);
- }
- private object ParseDictionary(Dictionary<string, object> d, Dictionary<string, object> globaltypes, Type type, object input)
- {
- object tn = "";
- if (d.TryGetValue("$types", out tn))
- {
- usingglobals = true;
- globaltypes = new Dictionary<string, object>();
- foreach (KeyValuePair<string, object> kv in (Dictionary<string, object>)tn)
- {
- globaltypes.Add((string)kv.Value, kv.Key);
- }
- }
- bool found = d.TryGetValue("$type", out tn);
- if (!found && type == typeof(object))
- {
- return CreateDataset(d, globaltypes);
- }
- if (found)
- {
- if (usingglobals)
- {
- object tname = "";
- if (globaltypes.TryGetValue((string)tn, out tname))
- {
- tn = tname;
- }
- }
- type = Reflection.Instance.GetTypeFromCache((string)tn);
- }
- if (type == null)
- {
- throw new Exception("Cannot determine type");
- }
- string typename = type.FullName;
- object o = input;
- if (o == null)
- {
- o = Reflection.Instance.FastCreateInstance(type);
- }
- SafeDictionary<string, myPropInfo> props = Getproperties(type, typename);
- foreach (string i in d.Keys)
- {
- string name = i;
- if (_params.IgnoreCaseOnDeserialize)
- {
- name = name.ToLower();
- }
- if (name == "$map")
- {
- ProcessMap(o, props, (Dictionary<string, object>)d[name]);
- }
- else
- {
- if (!props.TryGetValue(name, out var pi) || !pi.filled)
- {
- continue;
- }
- object v = d[name];
- if (v != null)
- {
- object oset = null;
- oset = (pi.isInt ? ((object)(int)CreateLong((string)v)) : (pi.isLong ? ((object)CreateLong((string)v)) : (pi.isString ? ((string)v) : (pi.isBool ? ((object)(bool)v) : ((pi.isGenericType && !pi.isValueType && !pi.isDictionary) ? CreateGenericList((ArrayList)v, pi.pt, pi.bt, globaltypes) : (pi.isByteArray ? Convert.FromBase64String((string)v) : ((pi.isArray && !pi.isValueType) ? CreateArray((ArrayList)v, pi.pt, pi.bt, globaltypes) : (pi.isGuid ? ((object)CreateGuid((string)v)) : (pi.isDataSet ? CreateDataset((Dictionary<string, object>)v, globaltypes) : (pi.isDataTable ? CreateDataTable((Dictionary<string, object>)v, globaltypes) : (pi.isStringDictionary ? CreateStringKeyDictionary((Dictionary<string, object>)v, pi.pt, pi.GenericTypes, globaltypes) : ((pi.isDictionary || pi.isHashtable) ? CreateDictionary((ArrayList)v, pi.pt, pi.GenericTypes, globaltypes) : (pi.isEnum ? CreateEnum(pi.pt, (string)v) : (pi.isDateTime ? ((object)CreateDateTime((string)v)) : ((pi.isClass && v is Dictionary<string, object>) ? ParseDictionary((Dictionary<string, object>)v, globaltypes, pi.pt, null) : (pi.isValueType ? ChangeType(v, pi.changeType) : ((!(v is ArrayList)) ? v : CreateArray((ArrayList)v, pi.pt, typeof(object), globaltypes))))))))))))))))));
- if (pi.CanWrite)
- {
- o = pi.setter(o, oset);
- }
- }
- }
- }
- return o;
- }
- private void ProcessMap(object obj, SafeDictionary<string, myPropInfo> props, Dictionary<string, object> dic)
- {
- foreach (KeyValuePair<string, object> 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 = 0L;
- bool neg = false;
- foreach (char cc in s)
- {
- switch (cc)
- {
- case '-':
- neg = true;
- break;
- case '+':
- neg = false;
- break;
- default:
- num *= 10;
- num += cc - 48;
- break;
- }
- }
- return neg ? (-num) : num;
- }
- private object CreateEnum(Type pt, string v)
- {
- return Enum.Parse(pt, v);
- }
- private Guid CreateGuid(string s)
- {
- if (s.Length > 30)
- {
- return new Guid(s);
- }
- return new Guid(Convert.FromBase64String(s));
- }
- private DateTime CreateDateTime(string value)
- {
- bool utc = false;
- 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 (!_params.UseUTCDateTime && !utc)
- {
- return new DateTime(year, month, day, hour, min, sec);
- }
- return new DateTime(year, month, day, hour, min, sec, DateTimeKind.Utc).ToLocalTime();
- }
- private object CreateArray(ArrayList data, Type pt, Type bt, Dictionary<string, object> globalTypes)
- {
- ArrayList col = new ArrayList();
- foreach (object ob in data)
- {
- if (ob is IDictionary)
- {
- col.Add(ParseDictionary((Dictionary<string, object>)ob, globalTypes, bt, null));
- }
- else
- {
- col.Add(ChangeType(ob, bt));
- }
- }
- return col.ToArray(bt);
- }
- private object CreateGenericList(ArrayList data, Type pt, Type bt, Dictionary<string, object> globalTypes)
- {
- IList col = (IList)Reflection.Instance.FastCreateInstance(pt);
- foreach (object ob in data)
- {
- if (ob is IDictionary)
- {
- col.Add(ParseDictionary((Dictionary<string, object>)ob, globalTypes, bt, null));
- }
- else if (ob is ArrayList)
- {
- col.Add(((ArrayList)ob).ToArray());
- }
- else
- {
- col.Add(ChangeType(ob, bt));
- }
- }
- return col;
- }
- private object CreateStringKeyDictionary(Dictionary<string, object> reader, Type pt, Type[] types, Dictionary<string, object> globalTypes)
- {
- IDictionary col = (IDictionary)Reflection.Instance.FastCreateInstance(pt);
- Type t1 = null;
- Type t2 = null;
- if (types != null)
- {
- t1 = types[0];
- t2 = types[1];
- }
- foreach (KeyValuePair<string, object> values in reader)
- {
- string key = values.Key;
- object val = null;
- val = ((!(values.Value is Dictionary<string, object>)) ? ChangeType(values.Value, t2) : ParseDictionary((Dictionary<string, object>)values.Value, globalTypes, t2, null));
- col.Add(key, val);
- }
- return col;
- }
- private object CreateDictionary(ArrayList reader, Type pt, Type[] types, Dictionary<string, object> globalTypes)
- {
- IDictionary col = (IDictionary)Reflection.Instance.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"];
- key = ((!(key is Dictionary<string, object>)) ? ChangeType(key, t1) : ParseDictionary((Dictionary<string, object>)key, globalTypes, t1, null));
- val = ((!(val is Dictionary<string, object>)) ? ChangeType(val, t2) : ParseDictionary((Dictionary<string, object>)val, globalTypes, t2, null));
- 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, Dictionary<string, object> globalTypes)
- {
- DataSet ds = new DataSet();
- ds.EnforceConstraints = false;
- ds.BeginInit();
- ReadSchema(reader, ds, globalTypes);
- foreach (KeyValuePair<string, object> pair in reader)
- {
- if (!(pair.Key == "$type") && !(pair.Key == "$schema"))
- {
- ArrayList rows = (ArrayList)pair.Value;
- if (rows != null)
- {
- 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)
- {
- object schema = reader["$schema"];
- if (schema is string)
- {
- TextReader tr = new StringReader((string)schema);
- ds.ReadXmlSchema(tr);
- return;
- }
- DatasetSchema ms = (DatasetSchema)ParseDictionary((Dictionary<string, object>)schema, globalTypes, typeof(DatasetSchema), null);
- ds.DataSetName = ms.Name;
- for (int i = 0; i < ms.Info.Count; i += 3)
- {
- if (!ds.Tables.Contains(ms.Info[i]))
- {
- 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();
- List<int> guidcols = new List<int>();
- List<int> datecol = new List<int>();
- foreach (DataColumn c in dt.Columns)
- {
- if (c.DataType == typeof(Guid) || c.DataType == typeof(Guid?))
- {
- guidcols.Add(c.Ordinal);
- }
- if (_params.UseUTCDateTime && (c.DataType == typeof(DateTime) || c.DataType == typeof(DateTime?)))
- {
- datecol.Add(c.Ordinal);
- }
- }
- foreach (ArrayList row in rows)
- {
- object[] v = new object[row.Count];
- row.CopyTo(v, 0);
- foreach (int j in guidcols)
- {
- string s2 = (string)v[j];
- if (s2 != null && s2.Length < 36)
- {
- v[j] = new Guid(Convert.FromBase64String(s2));
- }
- }
- if (_params.UseUTCDateTime)
- {
- foreach (int i in datecol)
- {
- string s = (string)v[i];
- if (s != null)
- {
- v[i] = CreateDateTime(s);
- }
- }
- }
- dt.Rows.Add(v);
- }
- dt.EndLoadData();
- dt.EndInit();
- }
- private DataTable CreateDataTable(Dictionary<string, object> reader, Dictionary<string, object> globalTypes)
- {
- DataTable dt = new DataTable();
- object schema = reader["$schema"];
- if (schema is string)
- {
- TextReader tr = new StringReader((string)schema);
- dt.ReadXmlSchema(tr);
- }
- else
- {
- DatasetSchema ms = (DatasetSchema)ParseDictionary((Dictionary<string, object>)schema, globalTypes, typeof(DatasetSchema), null);
- 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 (KeyValuePair<string, object> pair in reader)
- {
- if (!(pair.Key == "$type") && !(pair.Key == "$schema"))
- {
- ArrayList rows = (ArrayList)pair.Value;
- if (rows != null && dt.TableName.Equals(pair.Key, StringComparison.InvariantCultureIgnoreCase))
- {
- ReadDataTable(rows, dt);
- }
- }
- }
- return dt;
- }
- }
|