905 lines
32 KiB
C#
905 lines
32 KiB
C#
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
#if !SILVERLIGHT
|
|
using System.Data;
|
|
#endif
|
|
using System.Globalization;
|
|
using System.IO;
|
|
using System.Reflection;
|
|
using System.Reflection.Emit;
|
|
|
|
#if !__MonoCS__
|
|
#pragma warning disable CS1591
|
|
#endif
|
|
namespace fastJSON
|
|
{
|
|
public delegate string Serialize(object data);
|
|
public delegate object Deserialize(string data);
|
|
|
|
public sealed class JSONParameters
|
|
{
|
|
/// <summary>
|
|
/// Use the optimized fast Dataset Schema format (default = True)
|
|
/// </summary>
|
|
public bool UseOptimizedDatasetSchema = true;
|
|
/// <summary>
|
|
/// Use the fast GUID format (default = True)
|
|
/// </summary>
|
|
public bool UseFastGuid = true;
|
|
/// <summary>
|
|
/// Serialize null values to the output (default = True)
|
|
/// </summary>
|
|
public bool SerializeNullValues = true;
|
|
/// <summary>
|
|
/// Use the UTC date format (default = True)
|
|
/// </summary>
|
|
public bool UseUTCDateTime = true;
|
|
/// <summary>
|
|
/// Show the readonly properties of types in the output (default = False)
|
|
/// </summary>
|
|
public bool ShowReadOnlyProperties = false;
|
|
/// <summary>
|
|
/// Use the $types extension to optimise the output json (default = True)
|
|
/// </summary>
|
|
public bool UsingGlobalTypes = true;
|
|
/// <summary>
|
|
/// ** work in progress
|
|
/// </summary>
|
|
public bool IgnoreCaseOnDeserialize = false;
|
|
/// <summary>
|
|
/// Anonymous types have read only properties
|
|
/// </summary>
|
|
public bool EnableAnonymousTypes = false;
|
|
/// <summary>
|
|
/// Enable fastJSON extensions $types, $type, $map (default = True)
|
|
/// </summary>
|
|
public bool UseExtensions = true;
|
|
/// <summary>
|
|
/// Use escaped unicode i.e. \uXXXX format for non ASCII characters (default = True)
|
|
/// </summary>
|
|
public bool UseEscapedUnicode = true;
|
|
|
|
public void FixValues()
|
|
{
|
|
if (UseExtensions == false) // disable conflicting params
|
|
{
|
|
UsingGlobalTypes = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
public sealed class JSON
|
|
{
|
|
//public readonly static JSON Instance = new JSON();
|
|
[ThreadStatic]
|
|
private static JSON _instance;
|
|
|
|
public static JSON Instance
|
|
{
|
|
get { return _instance ?? (_instance = new JSON()); }
|
|
}
|
|
|
|
private JSON()
|
|
{
|
|
}
|
|
/// <summary>
|
|
/// You can set these paramters globally for all calls
|
|
/// </summary>
|
|
public JSONParameters Parameters = new JSONParameters();
|
|
private JSONParameters _params;
|
|
|
|
public string ToJSON(object obj)
|
|
{
|
|
_params = Parameters;
|
|
_params.FixValues();
|
|
Reflection.Instance.ShowReadOnlyProperties = _params.ShowReadOnlyProperties;
|
|
return ToJSON(obj, Parameters);
|
|
}
|
|
|
|
public string ToJSON(object obj, JSONParameters param)
|
|
{
|
|
_params = param;
|
|
_params.FixValues();
|
|
Reflection.Instance.ShowReadOnlyProperties = _params.ShowReadOnlyProperties;
|
|
Type t = null;
|
|
|
|
if (obj == null)
|
|
return "null";
|
|
|
|
if (obj.GetType().IsGenericType)
|
|
t = obj.GetType().GetGenericTypeDefinition();
|
|
if (t == typeof(Dictionary<,>) || t == typeof(List<>))
|
|
_params.UsingGlobalTypes = false;
|
|
|
|
// FEATURE : enable extensions when you can deserialize anon types
|
|
if (_params.EnableAnonymousTypes) { _params.UseExtensions = false; _params.UsingGlobalTypes = false; Reflection.Instance.ShowReadOnlyProperties = true; }
|
|
_usingglobals = _params.UsingGlobalTypes;
|
|
return new JSONSerializer(_params).ConvertToJSON(obj);
|
|
}
|
|
|
|
public object Parse(string json)
|
|
{
|
|
_params = Parameters;
|
|
Reflection.Instance.ShowReadOnlyProperties = _params.ShowReadOnlyProperties;
|
|
return new JsonParser(json, _params.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;
|
|
_params.FixValues();
|
|
Reflection.Instance.ShowReadOnlyProperties = _params.ShowReadOnlyProperties;
|
|
Type t = null;
|
|
if (type != null && type.IsGenericType)
|
|
t = type.GetGenericTypeDefinition();
|
|
if (t == typeof(Dictionary<,>) || t == typeof(List<>))
|
|
_params.UsingGlobalTypes = false;
|
|
_usingglobals = _params.UsingGlobalTypes;
|
|
|
|
object o = new JsonParser(json, Parameters.IgnoreCaseOnDeserialize).Decode();
|
|
if (o == null)
|
|
return null;
|
|
|
|
#if !SILVERLIGHT
|
|
if (type != null && type == typeof(DataSet))
|
|
return CreateDataset(o as Dictionary<string, object>, null);
|
|
|
|
if (type != null && type == typeof(DataTable))
|
|
return CreateDataTable(o as Dictionary<string, object>, null);
|
|
#endif
|
|
if (o is IDictionary)
|
|
{
|
|
if (type != null && type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Dictionary<,>)) // deserialize a dictionary
|
|
return RootDictionary(o, type);
|
|
else // deserialize an object
|
|
return ParseDictionary(o as Dictionary<string, object>, null, type, null);
|
|
}
|
|
|
|
if (o is List<object>)
|
|
{
|
|
if (type != null && type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Dictionary<,>)) // kv format
|
|
return RootDictionary(o, type);
|
|
|
|
if (type != null && type.IsGenericType && type.GetGenericTypeDefinition() == typeof(List<>)) // deserialize to generic list
|
|
return RootList(o, type);
|
|
else
|
|
return (o as List<object>).ToArray();
|
|
}
|
|
|
|
if (type != null && o.GetType() != type)
|
|
return ChangeType(o, type);
|
|
|
|
return o;
|
|
}
|
|
|
|
public string Beautify(string input)
|
|
{
|
|
return Formatter.PrettyPrint(input);
|
|
}
|
|
|
|
public object FillObject(object input, string json)
|
|
{
|
|
_params = Parameters;
|
|
_params.FixValues();
|
|
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));
|
|
}
|
|
|
|
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)
|
|
{
|
|
if (_customSerializer.Count == 0)
|
|
return false;
|
|
Serialize s;
|
|
return _customSerializer.TryGetValue(t, out s);
|
|
}
|
|
|
|
#region [ JSON specific reflection ]
|
|
|
|
private enum myPropInfoType
|
|
{
|
|
Int,
|
|
Long,
|
|
String,
|
|
Bool,
|
|
DateTime,
|
|
Enum,
|
|
Guid,
|
|
|
|
Array,
|
|
ByteArray,
|
|
Dictionary,
|
|
StringDictionary,
|
|
#if !SILVERLIGHT
|
|
Hashtable,
|
|
DataSet,
|
|
DataTable,
|
|
#endif
|
|
Custom,
|
|
Unknown,
|
|
}
|
|
|
|
[Flags]
|
|
private enum myPropInfoFlags
|
|
{
|
|
Filled = 1 << 0,
|
|
CanWrite = 1 << 1
|
|
}
|
|
|
|
private struct myPropInfo
|
|
{
|
|
public Type pt;
|
|
public Type bt;
|
|
public Type changeType;
|
|
public Reflection.GenericSetter setter;
|
|
public Reflection.GenericGetter getter;
|
|
public Type[] GenericTypes;
|
|
public string Name;
|
|
public myPropInfoType Type;
|
|
public myPropInfoFlags Flags;
|
|
|
|
public bool IsClass;
|
|
public bool IsValueType;
|
|
public bool IsGenericType;
|
|
}
|
|
|
|
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>();
|
|
PropertyInfo[] pr = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
|
|
foreach (PropertyInfo p in pr)
|
|
{
|
|
myPropInfo d = CreateMyProp(p.PropertyType, p.Name);
|
|
d.Flags |= myPropInfoFlags.CanWrite;
|
|
d.setter = Reflection.CreateSetMethod(type, p);
|
|
d.getter = Reflection.CreateGetMethod(type, p);
|
|
sd.Add(p.Name, d);
|
|
}
|
|
FieldInfo[] fi = type.GetFields(BindingFlags.Public | BindingFlags.Instance);
|
|
foreach (FieldInfo f in fi)
|
|
{
|
|
myPropInfo d = CreateMyProp(f.FieldType, f.Name);
|
|
d.setter = Reflection.CreateSetField(type, f);
|
|
d.getter = Reflection.CreateGetField(type, f);
|
|
sd.Add(f.Name, d);
|
|
}
|
|
|
|
_propertycache.Add(typename, sd);
|
|
return sd;
|
|
}
|
|
}
|
|
|
|
private myPropInfo CreateMyProp(Type t, string name)
|
|
{
|
|
myPropInfo d = new myPropInfo();
|
|
myPropInfoType d_type = myPropInfoType.Unknown;
|
|
myPropInfoFlags d_flags = myPropInfoFlags.Filled | myPropInfoFlags.CanWrite;
|
|
|
|
if (t == typeof(int) || t == typeof(int?)) d_type = myPropInfoType.Int;
|
|
else if (t == typeof(long) || t == typeof(long?)) d_type = myPropInfoType.Long;
|
|
else if (t == typeof(string)) d_type = myPropInfoType.String;
|
|
else if (t == typeof(bool) || t == typeof(bool?)) d_type = myPropInfoType.Bool;
|
|
else if (t == typeof(DateTime) || t == typeof(DateTime?)) d_type = myPropInfoType.DateTime;
|
|
else if (t.IsEnum) d_type = myPropInfoType.Enum;
|
|
else if (t == typeof(Guid) || t == typeof(Guid?)) d_type = myPropInfoType.Guid;
|
|
else if (t.IsArray)
|
|
{
|
|
d.bt = t.GetElementType();
|
|
if (t == typeof(byte[]))
|
|
d_type = myPropInfoType.ByteArray;
|
|
else
|
|
d_type = myPropInfoType.Array;
|
|
}
|
|
else if (t.Name.Contains("Dictionary"))
|
|
{
|
|
d.GenericTypes = t.GetGenericArguments();
|
|
if (d.GenericTypes.Length > 0 && d.GenericTypes[0] == typeof(string))
|
|
d_type = myPropInfoType.StringDictionary;
|
|
else
|
|
d_type = myPropInfoType.Dictionary;
|
|
}
|
|
#if !SILVERLIGHT
|
|
else if (t == typeof(Hashtable)) d_type = myPropInfoType.Hashtable;
|
|
else if (t == typeof(DataSet)) d_type = myPropInfoType.DataSet;
|
|
else if (t == typeof(DataTable)) d_type = myPropInfoType.DataTable;
|
|
#endif
|
|
|
|
else if (IsTypeRegistered(t))
|
|
d_type = myPropInfoType.Custom;
|
|
|
|
d.IsClass = t.IsClass;
|
|
d.IsValueType = t.IsValueType;
|
|
if (t.IsGenericType)
|
|
{
|
|
d.IsGenericType = true;
|
|
d.bt = t.GetGenericArguments()[0];
|
|
}
|
|
|
|
d.pt = t;
|
|
d.Name = name;
|
|
d.changeType = GetChangeType(t);
|
|
d.Type = d_type;
|
|
d.Flags = d_flags;
|
|
|
|
return d;
|
|
}
|
|
|
|
private object ChangeType(object value, Type conversionType)
|
|
{
|
|
if (conversionType == typeof(int))
|
|
return (int)((long)value);
|
|
|
|
else if (conversionType == typeof(long))
|
|
return (long)value;
|
|
|
|
else if (conversionType == typeof(string))
|
|
return (string)value;
|
|
|
|
else if (conversionType == typeof(Guid))
|
|
return CreateGuid((string)value);
|
|
|
|
else if (conversionType.IsEnum)
|
|
return CreateEnum(conversionType, (string)value);
|
|
|
|
else if (IsTypeRegistered(conversionType))
|
|
return CreateCustom((string)value, conversionType);
|
|
|
|
return Convert.ChangeType(value, conversionType, CultureInfo.InvariantCulture);
|
|
}
|
|
#endregion
|
|
|
|
#region [ p r i v a t e m e t h o d s ]
|
|
|
|
private object RootList(object parse, Type type)
|
|
{
|
|
Type[] gtypes = type.GetGenericArguments();
|
|
IList o = (IList)Reflection.Instance.FastCreateInstance(type);
|
|
foreach (var k in (IList)parse)
|
|
{
|
|
_usingglobals = false;
|
|
object v = k;
|
|
if (k is Dictionary<string, object>)
|
|
v = ParseDictionary(k as Dictionary<string, object>, null, gtypes[0], null);
|
|
else
|
|
v = ChangeType(k, gtypes[0]);
|
|
|
|
o.Add(v);
|
|
}
|
|
return o;
|
|
}
|
|
|
|
private object RootDictionary(object parse, Type type)
|
|
{
|
|
Type[] gtypes = type.GetGenericArguments();
|
|
if (parse is Dictionary<string, object>)
|
|
{
|
|
IDictionary o = (IDictionary)Reflection.Instance.FastCreateInstance(type);
|
|
|
|
foreach (var kv in (Dictionary<string, object>)parse)
|
|
{
|
|
object v;
|
|
object k = ChangeType(kv.Key, gtypes[0]);
|
|
if (kv.Value is Dictionary<string, object>)
|
|
v = ParseDictionary(kv.Value as Dictionary<string, object>, null, gtypes[1], null);
|
|
else if (kv.Value is List<object>)
|
|
v = CreateArray(kv.Value as List<object>, typeof(object), typeof(object), null);
|
|
else
|
|
v = ChangeType(kv.Value, gtypes[1]);
|
|
o.Add(k, v);
|
|
}
|
|
|
|
return o;
|
|
}
|
|
if (parse is List<object>)
|
|
return CreateDictionary(parse as List<object>, type, gtypes, null);
|
|
|
|
return null;
|
|
}
|
|
|
|
bool _usingglobals = false;
|
|
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 (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(System.Object))
|
|
{
|
|
return CreateDataset(d, globaltypes);
|
|
}
|
|
#endif
|
|
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 n in d.Keys)
|
|
{
|
|
string name = n;
|
|
if (_params.IgnoreCaseOnDeserialize) name = name.ToLower();
|
|
if (name == "$map")
|
|
{
|
|
ProcessMap(o, props, (Dictionary<string, object>)d[name]);
|
|
continue;
|
|
}
|
|
myPropInfo pi;
|
|
if (props.TryGetValue(name, out pi) == false)
|
|
continue;
|
|
if ((pi.Flags & (myPropInfoFlags.Filled | myPropInfoFlags.CanWrite)) != 0)
|
|
{
|
|
object v = d[name];
|
|
|
|
if (v != null)
|
|
{
|
|
object oset = null;
|
|
|
|
switch (pi.Type)
|
|
{
|
|
case myPropInfoType.Int: oset = (int)((long)v); break;
|
|
case myPropInfoType.Long: oset = (long)v; break;
|
|
case myPropInfoType.String: oset = (string)v; break;
|
|
case myPropInfoType.Bool: oset = (bool)v; break;
|
|
case myPropInfoType.DateTime: oset = CreateDateTime((string)v); break;
|
|
case myPropInfoType.Enum: oset = CreateEnum(pi.pt, (string)v); break;
|
|
case myPropInfoType.Guid: oset = CreateGuid((string)v); break;
|
|
|
|
case myPropInfoType.Array:
|
|
if (!pi.IsValueType)
|
|
oset = CreateArray((List<object>)v, pi.pt, pi.bt, globaltypes);
|
|
// what about 'else'?
|
|
break;
|
|
case myPropInfoType.ByteArray: oset = Convert.FromBase64String((string)v); break;
|
|
#if !SILVERLIGHT
|
|
case myPropInfoType.DataSet: oset = CreateDataset((Dictionary<string, object>)v, globaltypes); break;
|
|
case myPropInfoType.DataTable: oset = this.CreateDataTable((Dictionary<string, object>)v, globaltypes); break;
|
|
case myPropInfoType.Hashtable: // same case as Dictionary
|
|
#endif
|
|
case myPropInfoType.Dictionary: oset = CreateDictionary((List<object>)v, pi.pt, pi.GenericTypes, globaltypes); break;
|
|
case myPropInfoType.StringDictionary: oset = CreateStringKeyDictionary((Dictionary<string, object>)v, pi.pt, pi.GenericTypes, globaltypes); break;
|
|
|
|
case myPropInfoType.Custom: oset = CreateCustom((string)v, pi.pt); break;
|
|
default:
|
|
{
|
|
if (pi.IsGenericType && pi.IsValueType == false && v is List<object>)
|
|
oset = CreateGenericList((List<object>)v, pi.pt, pi.bt, globaltypes);
|
|
|
|
else if (pi.IsClass && v is Dictionary<string, object>)
|
|
oset = ParseDictionary((Dictionary<string, object>)v, globaltypes, pi.pt, pi.getter(o));
|
|
|
|
else if (v is List<object>)
|
|
oset = CreateArray((List<object>)v, pi.pt, typeof(object), globaltypes);
|
|
|
|
else if (pi.IsValueType)
|
|
oset = ChangeType(v, pi.changeType);
|
|
|
|
else
|
|
oset = v;
|
|
}
|
|
break;
|
|
}
|
|
|
|
o = pi.setter(o, oset);
|
|
}
|
|
}
|
|
}
|
|
return o;
|
|
}
|
|
|
|
private object CreateCustom(string v, Type type)
|
|
{
|
|
Deserialize d;
|
|
_customDeserializer.TryGetValue(type, out d);
|
|
return d(v);
|
|
}
|
|
|
|
private void ProcessMap(object obj, SafeDictionary<string, JSON.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 = Reflection.Instance.GetTypeFromCache((string)kv.Value);
|
|
if (t == typeof(Guid))
|
|
p.setter(obj, CreateGuid((string)o));
|
|
}
|
|
}
|
|
|
|
static int CreateInteger(out int num, string s, int index, int count)
|
|
{
|
|
num = 0;
|
|
bool neg = false;
|
|
for (int x = 0; x < count; x++, index++)
|
|
{
|
|
char cc = s[index];
|
|
|
|
if (cc == '-')
|
|
neg = true;
|
|
else if (cc == '+')
|
|
neg = false;
|
|
else
|
|
{
|
|
num *= 10;
|
|
num += (int)(cc - '0');
|
|
}
|
|
}
|
|
if (neg) num = -num;
|
|
|
|
return num;
|
|
}
|
|
|
|
internal static long CreateLong(out long num, char[] s, int index, int count)
|
|
{
|
|
num = 0;
|
|
bool neg = false;
|
|
for (int x = 0; x < count; x++, index++)
|
|
{
|
|
char cc = s[index];
|
|
|
|
if (cc == '-')
|
|
neg = true;
|
|
else if (cc == '+')
|
|
neg = false;
|
|
else
|
|
{
|
|
num *= 10;
|
|
num += (int)(cc - '0');
|
|
}
|
|
}
|
|
if (neg) num = -num;
|
|
|
|
return 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));
|
|
CreateInteger(out year, value, 0, 4);
|
|
CreateInteger(out month, value, 5, 2);
|
|
CreateInteger(out day, value, 8, 2);
|
|
CreateInteger(out hour, value, 11, 2);
|
|
CreateInteger(out min, value, 14, 2);
|
|
CreateInteger(out sec, value, 17, 2);
|
|
|
|
//if (value.EndsWith("Z"))
|
|
if (value[value.Length - 1] == 'Z')
|
|
utc = true;
|
|
|
|
if (_params.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();
|
|
}
|
|
|
|
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, null), i); // Original line
|
|
col.SetValue(RootDictionary(ob, typeof(Dictionary<string,object>)), i); // Change for UE4
|
|
else
|
|
col.SetValue(ChangeType(ob, bt), i);
|
|
}
|
|
|
|
return col;
|
|
}
|
|
|
|
|
|
private object CreateGenericList(List<object> data, Type pt, Type bt, Dictionary<string, object> globalTypes)
|
|
{
|
|
IList col = (IList)Reflection.Instance.FastCreateInstance(pt);
|
|
// create an array of objects
|
|
foreach (object ob in data)
|
|
{
|
|
if (ob is IDictionary)
|
|
col.Add(ParseDictionary((Dictionary<string, object>)ob, globalTypes, bt, null));
|
|
|
|
else if (ob is List<object>)
|
|
col.Add(((List<object>)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)
|
|
{
|
|
var 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)
|
|
{
|
|
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, null);
|
|
else
|
|
val = ChangeType(values.Value, t2);
|
|
col.Add(key, val);
|
|
}
|
|
|
|
return col;
|
|
}
|
|
|
|
private object CreateDictionary(List<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 (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, null);
|
|
else
|
|
key = ChangeType(key, t1);
|
|
|
|
if (val is Dictionary<string, object>)
|
|
val = ParseDictionary((Dictionary<string, object>)val, globalTypes, t2, null);
|
|
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 (KeyValuePair<string, object> pair in reader)
|
|
{
|
|
if (pair.Key == "$type" || pair.Key == "$schema") continue;
|
|
|
|
List<object> rows = (List<object>)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), null);
|
|
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], Reflection.Instance.GetTypeFromCache(ms.Info[i + 2]));
|
|
}
|
|
}
|
|
}
|
|
|
|
private void ReadDataTable(List<object> 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 (List<object> 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));
|
|
}
|
|
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();
|
|
}
|
|
|
|
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)this.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], Reflection.Instance.GetTypeFromCache(ms.Info[i + 2]));
|
|
}
|
|
}
|
|
|
|
foreach (var pair in reader)
|
|
{
|
|
if (pair.Key == "$type" || pair.Key == "$schema")
|
|
continue;
|
|
|
|
var rows = (List<object>)pair.Value;
|
|
if (rows == null)
|
|
continue;
|
|
|
|
if (!dt.TableName.Equals(pair.Key, StringComparison.InvariantCultureIgnoreCase))
|
|
continue;
|
|
|
|
ReadDataTable(rows, dt);
|
|
}
|
|
|
|
return dt;
|
|
}
|
|
#endif
|
|
#endregion
|
|
}
|
|
|
|
}
|
|
#if !__MonoCS__
|
|
#pragma warning restore CS1591
|
|
#endif
|